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

Re: [PATCH v5 4/4] commit-graph: new filter ver. that fixes murmur3

From
JTJonathan Tan <jonathantanmy@google.com>
Date
Jul 20, 2023, 21:27 UTC
Message-ID
<20230720212753.2008505-1-jonathantanmy@google.com>
In-Reply-To
<ZLgqbB2JG8+HPoHN@nand.local>
Taylor Blau <me@ttaylorr.com> writes:
Show 21 quoted lines
> On Thu, Jul 13, 2023 at 02:42:11PM -0700, Jonathan Tan wrote:
> > The murmur3 implementation in bloom.c has a bug when converting series
> > of 4 bytes into network-order integers when char is signed (which is
> > controllable by a compiler option, and the default signedness of char is
> > platform-specific). When a string contains characters with the high bit
> > set, this bug causes results that, although internally consistent within
> > Git, does not accord with other implementations of murmur3 and even with
> > Git binaries that were compiled with different signedness of char. This
> > bug affects both how Git writes changed path filters to disk and how Git
> > interprets changed path filters on disk.
> 
> I think that you make a worthwhile point that the existing
> implementation is internally consistent, but doesn't actually implement
> a conventional murmur3. I wonder if it's worth being explicit where you
> mention its internal consistency to say that the existing implementation
> would never cause us to produce wrong results, but wouldn't be readable
> by other off-the-shelf implementations of murmur3.
> 
> (To be clear, I think that you already make this point, I'm just
> suggesting that it may be worth spelling it out even more explicitly
> than what is written above).
OK, I've added some more text describing this.
Show 27 quoted lines
> > Because this bug only manifests with characters that have the high bit
> > set, it may be possible that some (or all) commits in a given repo would
> > have the same changed path filter both before and after this fix is
> > applied. However, in order to determine whether this is the case, the
> > changed paths would first have to be computed, at which point it is not
> > much more expensive to just compute a new changed path filter.
> 
> Hmm. I think in the general case that is true, but I wonder if there's a
> shortcut we could take for trees that are known to not have *any*
> characters with their high-order bits set. That is, if we scan both of
> the first parent's trees and determine that no such paths exist, the
> contents of the Bloom filter would be the same in either version, right?
> 
> I think that that would be faster than recomputing all filters from
> scratch. In either case, we have to load the whole tree. But if we can
> quickly scan (and cache our results by setting some bit--indicating the
> absence of paths with characters having their highest bit set--on the tree
> objects' `flags` field), then we should be able to copy forward the
> existing representation of the filter.
> 
> I think the early checks would be more expensive, since in the worst
> case you have to walk the entire tree, only to realize that you actually
> wanted to compute a first-parent tree diff, meaning you have to
> essentially repeat the whole walk over again. But for repositories that
> have few or no commits whose Bloom filters need computing, I think it
> would be significantly faster, since many of the sub-trees wouldn't need
> to be visited again.

So for repositories that need little-to-no recomputation of Bloom filters, your idea likely means that each tree needs to be read once, as compared to recomputing everything in which, I think, each tree needs to be read roughly twice (once when computing the Bloom filter for the commit that introduces it, and once for the commit that substitutes a different tree in place).

I could change the text of the commit message to discuss this (instead of the blanket statement that it would be too hard), although I think that an implementation of this can be done after this patchset. What do you think?

Show 12 quoted lines
> > There is a change in write_commit_graph(). graph_read_bloom_data()
> > makes it possible for chunk_bloom_data to be non-NULL but
> > bloom_filter_settings to be NULL, which causes a segfault later on. I
> > produced such a segfault while developing this patch, but couldn't find
> > a way to reproduce it neither after this complete patch (or before),
> > but in any case it seemed like a good thing to include that might help
> > future patch authors.
> 
> Hmm. Interesting, I'd love to know more about what you were doing that
> produced the segfault. I think it would be worth it to prove to
> ourselves that this segfault can't occur in the wild. Or if it can, it
> would be worth it to understand the bug and prevent it from happening.

If I remember correctly, I changed the version in DEFAULT_BLOOM_FILTER_SETTINGS to 2 and ran it to see what broke. This was a while back so I don't remember it exactly, though.

Show 36 quoted lines
> > @@ -130,8 +187,10 @@ void fill_bloom_key(const char *data,
> >  	int i;
> >  	const uint32_t seed0 = 0x293ae76f;
> >  	const uint32_t seed1 = 0x7e646e2c;
> > -	const uint32_t hash0 = murmur3_seeded(seed0, data, len);
> > -	const uint32_t hash1 = murmur3_seeded(seed1, data, len);
> > +	const uint32_t hash0 = (settings->hash_version == 2
> > +		? murmur3_seeded_v2 : murmur3_seeded_v1)(seed0, data, len);
> > +	const uint32_t hash1 = (settings->hash_version == 2
> > +		? murmur3_seeded_v2 : murmur3_seeded_v1)(seed1, data, len);
> 
> I do admire the ternary operator over the function being called, as I
> think that Stolee pointed out earlier in this series. But I worry that
> these two checks could fall out of sync with each other, causing us to
> pick incosistent values for hash0, and hash1, respectively.
> 
> FWIW, I would probably write this as:
> 
>     const uint32_t hash0, hash1;
>     if (settings->hash_version == 2) {
>         hash0 = murmur3_seeded_v2(seed0, data, len);
>         hash1 = murmur3_seeded_v2(seed1, data, len);
>     } else {
>         hash0 = murmur3_seeded_v1(seed0, data, len);
>         hash1 = murmur3_seeded_v1(seed1, data, len);
>     }
> 
> I suppose that there isn't anything keeping the calls within each arm of
> the if-statement above in sync with each other (i.e., I could call
> murmur3_seeded_v1() immediately before dispatching a call to
> murmur3_seeded_v2()). So in that sense I think that this is no more or
> less safe than what's already written.
> 
> But IMHO I think this one reads more cleanly, so I might prefer it over
> what you have in this patch. But I don't feel so strongly about it
> either way.

I'm OK either way, so I'll go with your approach (except the "const", since my compiler doesn't like that).

Show 12 quoted lines
> > @@ -302,16 +302,25 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,
> >  	return 0;
> >  }
> >
> > +struct graph_read_bloom_data_data {
> > +	struct commit_graph *g;
> > +	int *commit_graph_changed_paths_version;
> > +};
> > +
> 
> Nit: maybe `graph_read_bloom_data_context`, to avoid repeating "data"? I
> don't have strong feelings here, FWIW.
I'll use "context".
> The rest of the implementation and tests look good to me.
> 
> Thanks,
> Taylor
Thanks for the review.
Previous: Taylor BlauNext: Taylor Blau
Message 78 of 116 in “Changed path filter hash fix and version bump”
  1. 0/2 Changed path filter hash fix and version bumpJonathan Tan, May 22, 2023
  2. 1/2 t4216: test wrong bloom filter version rejectionJonathan Tan, May 22, 2023
  3. 2/2 commit-graph: fix murmur3, bump filter ver. to 2Jonathan Tan, May 22, 2023
  4. Derrick StoleeMay 23, 2023
  5. Jonathan TanMay 23, 2023
  6. Junio C HamanoMay 23, 2023
  7. Jonathan TanMay 24, 2023
  8. Derrick StoleeMay 26, 2023
  9. Jonathan TanMay 30, 2023
  10. Junio C HamanoMay 23, 2023
  11. 0/3 Changed path filter hash fix and version bumpJonathan Tan, May 31, 2023
  12. 1/3 t4216: test changed path filters with high bit pathsJonathan Tan, May 31, 2023
  13. 2/3 repo-settings: introduce commitgraph.changedPathsVersionJonathan Tan, May 31, 2023
  14. 3/3 commit-graph: new filter ver. that fixes murmur3Jonathan Tan, May 31, 2023
  15. Junio C HamanoJun 3, 2023
  16. Junio C HamanoJun 3, 2023
  17. Jonathan TanJun 7, 2023
  18. Jonathan TanJun 7, 2023
  19. 0/4 Changed path filter hash fix and version bumpJonathan Tan, Jun 8, 2023
  20. 1/4 gitformat-commit-graph: describe version 2 of BDATJonathan Tan, Jun 8, 2023
  21. Ramsay JonesJun 8, 2023
  22. Junio C HamanoJun 12, 2023
  23. 2/4 t4216: test changed path filters with high bit pathsJonathan Tan, Jun 8, 2023
  24. 3/4 repo-settings: introduce commitgraph.changedPathsVersionJonathan Tan, Jun 8, 2023
  25. 4/4 commit-graph: new filter ver. that fixes murmur3Jonathan Tan, Jun 8, 2023
  26. Ramsay JonesJun 8, 2023
  27. Jonathan TanJun 9, 2023
  28. Junio C HamanoJun 12, 2023
  29. Jonathan TanJun 13, 2023
  30. CodingGuidelines: use octal escapes, not hexJonathan Tan, Jun 13, 2023
  31. Eric SunshineJun 13, 2023
  32. Jonathan TanJun 13, 2023
  33. Eric SunshineJun 13, 2023
  34. Junio C HamanoJun 13, 2023
  35. Junio C HamanoJun 13, 2023
  36. 0/4 Changed path filter hash fix and version bumpJonathan Tan, Jun 13, 2023
  37. 2/4 t4216: test changed path filters with high bit pathsJonathan Tan, Jun 13, 2023
  38. 1/4 gitformat-commit-graph: describe version 2 of BDATJonathan Tan, Jun 13, 2023
  39. Junio C HamanoJun 13, 2023
  40. Derrick StoleeJun 20, 2023
  41. Taylor BlauJun 21, 2023
  42. Jonathan TanJun 22, 2023
  43. Derrick StoleeJun 23, 2023
  44. 3/4 repo-settings: introduce commitgraph.changedPathsVersionJonathan Tan, Jun 13, 2023
  45. Derrick StoleeJun 20, 2023
  46. Taylor BlauJun 21, 2023
  47. 4/4 commit-graph: new filter ver. that fixes murmur3Jonathan Tan, Jun 13, 2023
  48. Derrick StoleeJun 20, 2023
  49. Junio C HamanoJun 20, 2023
  50. Junio C HamanoJun 13, 2023
  51. Derrick StoleeJun 20, 2023
  52. Jonathan TanJun 20, 2023
  53. Taylor BlauJun 21, 2023
  54. Derrick StoleeJun 21, 2023
  55. Jonathan TanJun 22, 2023
  56. Derrick StoleeJun 23, 2023
  57. 0/4 Changed path filter hash fix and version bumpJonathan Tan, Jul 13, 2023
  58. 3/4 repo-settings: introduce commitgraph.changedPathsVersionJonathan Tan, Jul 13, 2023
  59. Taylor BlauJul 19, 2023
  60. Jonathan TanJul 20, 2023
  61. Taylor BlauJul 20, 2023
  62. 2/4 t4216: test changed path filters with high bit pathsJonathan Tan, Jul 13, 2023
  63. Junio C HamanoJul 13, 2023
  64. Taylor BlauJul 19, 2023
  65. 0/4 commit-graph: avoid looking at Bloom filter data directlyTaylor Blau, Jul 19, 2023
  66. 1/4 t/helper/test-read-graph.c: extract `dump_graph_info()`Taylor Blau, Jul 19, 2023
  67. 2/4 bloom.h: make `load_bloom_filter_from_graph()` publicTaylor Blau, Jul 19, 2023
  68. 3/4 t/helper/test-read-graph: implement `bloom-filters` modeTaylor Blau, Jul 19, 2023
  69. 4/4 fixup! t4216: test changed path filters with high bit pathsTaylor Blau, Jul 19, 2023
  70. Junio C HamanoJul 19, 2023
  71. Jonathan TanJul 20, 2023
  72. 1/4 gitformat-commit-graph: describe version 2 of BDATJonathan Tan, Jul 13, 2023
  73. Taylor BlauJul 19, 2023
  74. Jonathan TanJul 20, 2023
  75. Taylor BlauJul 21, 2023
  76. 4/4 commit-graph: new filter ver. that fixes murmur3Jonathan Tan, Jul 13, 2023
  77. Taylor BlauJul 19, 2023
  78. Jonathan TanJul 20, 2023
  79. Taylor BlauJul 26, 2023
  80. Junio C HamanoJul 13, 2023
  81. Junio C HamanoJul 13, 2023
  82. Jonathan TanJul 14, 2023
  83. 0/7 Changed path filter hash fix and version bumpJonathan Tan, Jul 20, 2023
  84. 1/7 gitformat-commit-graph: describe version 2 of BDATJonathan Tan, Jul 20, 2023
  85. 2/7 t/helper/test-read-graph.c: extract `dump_graph_info()`Jonathan Tan, Jul 20, 2023
  86. Taylor BlauJul 26, 2023
  87. 3/7 bloom.h: make `load_bloom_filter_from_graph()` publicJonathan Tan, Jul 20, 2023
  88. 5/7 t4216: test changed path filters with high bit pathsJonathan Tan, Jul 20, 2023
  89. Taylor BlauJul 26, 2023
  90. 4/7 t/helper/test-read-graph: implement `bloom-filters` modeJonathan Tan, Jul 20, 2023
  91. 6/7 repo-settings: introduce commitgraph.changedPathsVersionJonathan Tan, Jul 20, 2023
  92. 7/7 commit-graph: new filter ver. that fixes murmur3Jonathan Tan, Jul 20, 2023
  93. Junio C HamanoJul 25, 2023
  94. Junio C HamanoJul 26, 2023
  95. Taylor BlauJul 27, 2023
  96. Junio C HamanoJul 27, 2023
  97. Jonathan TanJul 27, 2023
  98. Taylor BlauJul 27, 2023
  99. Jonathan TanJul 27, 2023
  100. Taylor BlauAug 1, 2023
  101. Jonathan TanAug 1, 2023
  102. Taylor BlauAug 3, 2023
  103. Derrick StoleeAug 3, 2023
  104. Taylor BlauAug 3, 2023
  105. Junio C HamanoJul 27, 2023
  106. 0/7 Changed path filter hash fix and version bumpJonathan Tan, Aug 1, 2023
  107. 1/7 gitformat-commit-graph: describe version 2 of BDATJonathan Tan, Aug 1, 2023
  108. 2/7 t/helper/test-read-graph.c: extract `dump_graph_info()`Jonathan Tan, Aug 1, 2023
  109. 3/7 bloom.h: make `load_bloom_filter_from_graph()` publicJonathan Tan, Aug 1, 2023
  110. 4/7 t/helper/test-read-graph: implement `bloom-filters` modeJonathan Tan, Aug 1, 2023
  111. 5/7 t4216: test changed path filters with high bit pathsJonathan Tan, Aug 1, 2023
  112. 6/7 repo-settings: introduce commitgraph.changedPathsVersionJonathan Tan, Aug 1, 2023
  113. 7/7 commit-graph: new filter ver. that fixes murmur3Jonathan Tan, Aug 1, 2023
  114. Junio C HamanoAug 1, 2023
  115. Taylor BlauAug 1, 2023
  116. Junio C HamanoAug 1, 2023

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.