git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] hashmap: add API to disable item counting when threaded

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Sep 1, 2017, 23:31 UTC
Message-ID
<alpine.DEB.2.21.1.1709020109520.4132@virtualbox>
In-Reply-To
<20170830185922.10107-2-git@jeffhostetler.com>
Hi Jeff,
On Wed, 30 Aug 2017, Jeff Hostetler wrote:
Show 20 quoted lines
> From: Jeff Hostetler <jeffhost@microsoft.com>
> 
> This is to address concerns raised by ThreadSanitizer on the mailing
> list about threaded unprotected R/W access to map.size with my previous
> "disallow rehash" change (0607e10009ee4e37cb49b4cec8d28a9dda1656a4).
> See:
> https://public-inbox.org/git/adb37b70139fd1e2bac18bfd22c8b96683ae18eb.1502780344.git.martin.agren@gmail.com/
> 
> Add API to hashmap to disable item counting and to disable automatic
> rehashing.  Also include APIs to re-enable item counting and automatica
> rehashing.
> 
> When item counting is disabled, the map.size field is invalid.  So to
> prevent accidents, the field has been renamed and an accessor function
> hashmap_get_size() has been added.  All direct references to this field
> have been been updated.  And the name of the field changed to
> map.private_size to communicate thie.
> 
> Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
> ---

The Git contribution process forces me to point out lines longer than 80 columns. I wish there was already an automated tool to fix that, but we (as in "the core Git developers") have not yet managed to agree on one. So I'll have to ask you to identify and fix them manually.

Show 12 quoted lines
> @@ -253,6 +253,19 @@ static inline void hashmap_entry_init(void *entry, unsigned int hash)
>  }
>  
>  /*
> + * Return the number of items in the map.
> + */
> +inline unsigned int hashmap_get_size(struct hashmap *map)
> +{
> +	if (map->do_count_items)
> +		return map->private_size;
> +
> +	/* TODO Consider counting them and returning that. */
I'd rather not. If counting is disabled, it is disabled.
> +	die("hashmap_get_size: size not set");

Before anybody can ask for this message to be wrapped in _(...) to be translateable, let me suggest instead to add the prefix "BUG: ".

Show 13 quoted lines
> +static inline void hashmap_enable_item_counting(struct hashmap *map)
> +{
> +	void *item;
> +	unsigned int n = 0;
> +	struct hashmap_iter iter;
> +
> +	hashmap_iter_init(map, &iter);
> +	while ((item = hashmap_iter_next(&iter)))
> +		n++;
> +
> +	map->do_count_items = 1;
> +	map->private_size = n;
> +}

BTW this made me think that we may have a problem in our code since switching from my original hashmap implementation to the bucket one added in 6a364ced497 (add a hashtable implementation that supports O(1) removal, 2013-11-14): while it is not expected that there are many collisions, the "grow_at" logic still essentially assumes the number of buckets to be equal to the number of hashmap entries.

Your code simply reiterates that assumption, so I do not blame you for anything here, nor ask you to change your patch.

But it does look a bit weird to assume so much about the nature of our data, without having any real-life numbers. I wish I had more time so that I could afford to run a couple of tests on this hashmap, such as: what is the typical difference between bucket count and entry count, or the median of the bucket sizes when the map is 80% full (i.e. *just* below the grow threshold).

Show 15 quoted lines
> diff --git a/name-hash.c b/name-hash.c
> index 0e10f3e..829ff59 100644
> --- a/name-hash.c
> +++ b/name-hash.c
> @@ -580,9 +580,11 @@ static void lazy_init_name_hash(struct index_state *istate)
>  			NULL, istate->cache_nr);
>  
>  	if (lookup_lazy_params(istate)) {
> -		hashmap_disallow_rehash(&istate->dir_hash, 1);
> +		hashmap_disable_item_counting(&istate->dir_hash);
> +		hashmap_disable_auto_rehash(&istate->dir_hash);
>  		threaded_lazy_init_name_hash(istate);
> -		hashmap_disallow_rehash(&istate->dir_hash, 0);
> +		hashmap_enable_auto_rehash(&istate->dir_hash);
> +		hashmap_enable_item_counting(&istate->dir_hash);

By your rationale, it would be enough to simply disable and re-enable counting...

The rest of the patch looks just dandy to me.

Thanks, Dscho

Previous: Jeff HostetlerNext: Jonathan Nieder
Message 18 of 64 in “Some ThreadSanitizer-results”
  1. 0/5 Some ThreadSanitizer-resultsMartin Ågren, Aug 15, 2017
  2. 1/5 convert: initialize attr_action in convert_attrsMartin Ågren, Aug 15, 2017
  3. Torsten BögershausenAug 15, 2017
  4. Torsten BögershausenAug 15, 2017
  5. Martin ÅgrenAug 15, 2017
  6. 2/5 pack-objects: take lock before accessing `remaining`Martin Ågren, Aug 15, 2017
  7. Johannes SixtAug 15, 2017
  8. 5/5 ThreadSanitizer: add suppressionsMartin Ågren, Aug 15, 2017
  9. tsan: t3008: hashmap_add touches size from multiple threadsMartin Ågren, Aug 15, 2017
  10. Jeff HostetlerAug 15, 2017
  11. Stefan BellerAug 15, 2017
  12. Martin ÅgrenAug 15, 2017
  13. Stefan BellerAug 15, 2017
  14. Martin ÅgrenAug 15, 2017
  15. Jeff HostetlerAug 15, 2017
  16. hashmap: address ThreadSanitizer concernsJeff Hostetler, Aug 30, 2017
  17. hashmap: add API to disable item counting when threadedJeff Hostetler, Aug 30, 2017
  18. Johannes SchindelinSep 1, 2017
  19. Jonathan NiederSep 1, 2017
  20. Jeff HostetlerSep 5, 2017
  21. Martin ÅgrenSep 5, 2017
  22. Jeff KingSep 2, 2017
  23. Johannes SchindelinSep 4, 2017
  24. Jeff HostetlerSep 5, 2017
  25. Junio C HamanoSep 6, 2017
  26. Jeff HostetlerSep 5, 2017
  27. Jeff KingSep 2, 2017
  28. Jeff HostetlerSep 5, 2017
  29. Simon RuderichSep 2, 2017
  30. Junio C HamanoSep 6, 2017
  31. Jeff HostetlerSep 6, 2017
  32. hashmap: address ThreadSanitizer concernsJeff Hostetler, Sep 6, 2017
  33. hashmap: add API to disable item counting when threadedJeff Hostetler, Sep 6, 2017
  34. tsan: t5400: set_try_to_free_routineMartin Ågren, Aug 15, 2017
  35. Stefan BellerAug 15, 2017
  36. Martin ÅgrenAug 15, 2017
  37. Jeff KingAug 17, 2017
  38. 4/5 strbuf_reset: don't write to slopbuf with ThreadSanitizerMartin Ågren, Aug 15, 2017
  39. Junio C HamanoAug 15, 2017
  40. Martin ÅgrenAug 15, 2017
  41. Junio C HamanoAug 15, 2017
  42. 3/5 Makefile: define GIT_THREAD_SANITIZERMartin Ågren, Aug 15, 2017
  43. Jeff KingAug 20, 2017
  44. Martin ÅgrenAug 20, 2017
  45. 0/4 Some ThreadSanitizer-resultsMartin Ågren, Aug 21, 2017
  46. 1/4 convert: always initialize attr_action in convert_attrsMartin Ågren, Aug 21, 2017
  47. 2/4 pack-objects: take lock before accessing `remaining`Martin Ågren, Aug 21, 2017
  48. 3/4 strbuf_setlen: don't write to strbuf_slopbufMartin Ågren, Aug 21, 2017
  49. Junio C HamanoAug 23, 2017
  50. Martin ÅgrenAug 23, 2017
  51. Junio C HamanoAug 23, 2017
  52. Brandon CaseyAug 23, 2017
  53. Junio C HamanoAug 23, 2017
  54. Brandon CaseyAug 23, 2017
  55. Brandon CaseyAug 23, 2017
  56. Brandon CaseyAug 23, 2017
  57. Junio C HamanoAug 24, 2017
  58. Brandon CaseyAug 24, 2017
  59. Martin ÅgrenAug 24, 2017
  60. Junio C HamanoAug 23, 2017
  61. Brandon CaseyAug 23, 2017
  62. 4/4 ThreadSanitizer: add suppressionsMartin Ågren, Aug 21, 2017
  63. Jeff KingAug 25, 2017
  64. Jeff HostetlerAug 28, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.