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

Re: tsan: t3008: hashmap_add touches size from multiple threads

From
JHJeff Hostetler <git@jeffhostetler.com>
Date
Aug 15, 2017, 20:46 UTC
Message-ID
<217f3160-f4cb-581a-b7f3-8b654c74d080@jeffhostetler.com>
In-Reply-To
<CAN0heSr-OcLJU54acTdXWx8NAo=nPD=9+DfexWZ0F7NRgRB9Dg@mail.gmail.com>
On 8/15/2017 3:21 PM, Martin Ågren wrote:
Show 46 quoted lines
> On 15 August 2017 at 20:48, Stefan Beller <sbeller@google.com> wrote:
>>>>>          /* total number of entries (0 means the hashmap is empty) */
>>>>> -       unsigned int size;
>>>>> +       /* -1 means size is unknown for threading reasons */
>>>>> +       int size;
>>>>
>>>> This double-encodes the state of disallow_rehash (i.e. if we had
>>>> signed size, then the invariant disallow_rehash === (size < 0)
>>>> is true, such that we could omit either the flag and just check for
>>>> size < 0 or we do not need the negative size as any user would
>>>> need to check disallow_rehash first. Not sure which API is harder
>>>> to misuse. I'd think just having the size and getting rid of
>>>> disallow_rehash might be hard to to reused.
>>>
>>> (Do you mean "might be hard to be misused"?)
>>
>> yes, I do.
>>
>>> One good thing about turning off the size-tracking with threading is
>>> that someone who later wants to know the size in a threaded application
>>> will not introduce any subtle bugs by misusing size, but will be forced
>>> to provide and use some sort of InterlockedIncrement().
>>
>> agreed.
>>
>>> When/if that
>>> change happens, it would be nice if no-one relied on the value of size
>>> to say anything about threading. So it might make sense to have an
>>> implementation-independent way of accessing disallow_rehash a.k.a.
>>> (size < 0).
>>
>> Yes, and my point was whether we want to keep disallow_rehash around,
>> as when a patch as this is applied, we'd have it encoded twice,
>> both size < 0 as well as disallow_rehash set indicate the rehashing
>> disabled.
>>
>> If we were to reduce it to one, we would not have "invalid" state possible
>> such as size < 0 and disallow_rehash = 0.
> 
> Agreed.
> 
>> In the future we may have more options that make size impossible to
>> compute efficiently, such that in that case we'd want to know which
>> condition lead to it. In that case we'd want to have the flags around.
> 
> Good point.

I feel like we're trying to push hashmaps a little beyond their capability. I mean the core hashmap code is NOT thread safe. The caller is responsible for carefully controlling how the hashmap is used and whatever locking strategy it wants -- whether it is a single lock on the entire hashmap -- or a set of partition-specific locks like I created here. Whatever the strategy, it is outside of hashmap.[ch].

Perhaps it would be best to just define things as:
* let (size < 0) mean we choose not to compute/track it (without
   saying why).
* keep "disallow_rehash = 1" to mean we do not want automatic
   resizing (without saying why).
Thread-aware callers will set both.

Thread-aware callers (when finished with threaded operations) can themselves choose whether to compute the correct size and re-allow rehashing. And we can add a method to hashmap.c to re-calculate the size if we want.

In my lazy_init_name_hash() I set "disallow", do the threaded code, and then unset "disallow" -- mainly to keep the usage consistent with the non-threaded case. I could just as easily set "disallow" and leave it that way -- the question is whether we care if the hashmap automatically resizes later. (I don't.)

Show 28 quoted lines
>>> For example a function hashmap_disallow_rehash(), except that's
>>> obviously taken. :-) Maybe the existing function would then be
>>> hashmap_set_disallow_rehash(). Oh well..
>>
>> Not sure I understand this one.
> 
> Sorry. What I meant was, if we drop the disallow_rehash-field, someone
> might be tempted to use size < 0 (or size == -1) to answer the question
> "is rehashing disallowed?". (Or "am I threaded?" which already is a
> question which the hashmap as it is today doesn't know about.)
> 
> So instead of looking at "disallow_rehash" one should perhaps be calling
> "hashmap_is_disallow_rehash()" or "hashmap_get_disallow_rehash()", which
> would be implemented as "return disallow_rehash", or possibly "return
> size == -1".
> 
> Except such names are, to the best of my understanding, not the Git-way,
> so it should be, e.g., "hashmap_disallow_rehash()".
> 
> Except ... that name is taken.... So to free that name up, the existing
> function should perhaps be renamed "hashmap_set_disallow_rehash()",
> again assuming I've picked up the right conventions in my recent
> browsing of the Git-code.
> 
> The final "Oh well" was a short form of "it began with an observation
> which currently has no practical effect, and is slowly turning into a
> chain of ideas on how to rebuild the interface".
> 
Previous: Martin ÅgrenNext: Jeff Hostetler
Message 15 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.