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

[PATCH 5/5] sha1_file: don't re-scan pack directory for null sha1

From
Jeff King <peff@peff.net>
Date
Nov 20, 2017, 20:35 UTC
Message-ID
<20171120203523.c3pt5qi43e24ttqq@sigill.intra.peff.net>
In-Reply-To
<20171120202607.tf2pvegqe35mhxjs@sigill.intra.peff.net>

In theory nobody should ever ask the low-level object code for a null sha1. It's used as a sentinel for "no such object" in lots of places, so leaking through to this level is a sign that the higher-level code is not being careful about its error-checking. In practice, though, quite a few code paths seem to rely on the null sha1 lookup failing as a way to quietly propagate non-existence (e.g., by feeding it to lookup_commit_reference_gently(), which then returns NULL).

When this happens, we do two inefficient things:
  1. We actually search for the null sha1 in packs and in
     the loose object directory.
  2. When we fail to find it, we re-scan the pack directory
     in case a simultaneous repack happened to move it from
     loose to packed.

It's debatable whether (1) is a good idea or not. The performance drop is at least linear in the number of lookups, so it's not too bad. And if by some 2^-160th chance somebody does have such an object, we probably ought to access it. On the other hand, enough code paths treat the null sha1 specially that the object probably isn't usable, anyway.

Problem (2), on the other hand, is a pretty severe performance issue. If you have a large number of packs, rescanning the pack directory can be very expensive. And it only helps in the case that you have an object with the null sha1 _and_ somebody was simultaneously repacking it. The tradeoff is certainly a bad one there.

In an ideal world, we'd simply fix all of the callers to notice the null sha1 and avoid passing it to us. But a simple experiment to catch this with a BUG() shows that there are a large number of code paths.

In the meantime, let's address problem (2). That's the minimal fix we can do to make the performance problems go away. p5551 shows this off (when a fetched ref is new, the "old" sha1 is 0{40}, which ends up being passed for fast-forward checks, the status table abbreviations, etc):

  Test            HEAD^             HEAD
  --------------------------------------------------------
  5551.4: fetch   5.51(5.03+0.48)   0.17(0.10+0.06) -96.9%

We could address (1), too, but there's not much performance improvement left to make.

Signed-off-by: Jeff King <peff@peff.net>
---
This is the minimal fix that addresses the performance issues.
I'd actually have no problem at all declaring that looking up a null
sha1 is insane, and having the object-lookup routines simply return "no
such object" without even doing the loose/pack lookup first.

I'm also fine with going down the BUG() route and fixing the higher-level callers, but it's a big enough task (with little enough real-world impact) that I think it would be worth applying this in the meantime.

 sha1_file.c | 3 +++
 1 file changed, 3 insertions(+)
diff --git a/sha1_file.c b/sha1_file.c
index 8a7c6b7eba..dde0ad101d 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1180,6 +1180,9 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
 		if (!sha1_loose_object_info(real, oi, flags))
 			return 0;
 
+		if (is_null_sha1(sha1))
+			return -1;
+
 		/* Not a loose object; someone else may have just packed it. */
 		if (flags & OBJECT_INFO_QUICK) {
 			return -1;
-- 
2.15.0.494.g79a8547723
Previous: Jeff KingNext: Stefan Beller
Message 12 of 25 in “avoiding pointless pack-directory re-scans”
  1. 0/5 avoiding pointless pack-directory re-scansJeff King, Nov 20, 2017
  2. 1/5 p5550: factor our nonsense-pack creationJeff King, Nov 20, 2017
  3. Eric SunshineNov 20, 2017
  4. Jeff KingNov 21, 2017
  5. Stefan BellerNov 22, 2017
  6. Jeff KingNov 22, 2017
  7. Junio C HamanoNov 23, 2017
  8. Jeff KingNov 23, 2017
  9. 2/5 t/perf/lib-pack: use fast-import checkpoint to create packsJeff King, Nov 20, 2017
  10. 3/5 p5551: add a script to test fetch pack-dir rescansJeff King, Nov 20, 2017
  11. 4/5 everything_local: use "quick" object existence checkJeff King, Nov 20, 2017
  12. 5/5 sha1_file: don't re-scan pack directory for null sha1Jeff King, Nov 20, 2017
  13. Stefan BellerNov 20, 2017
  14. Jeff KingNov 20, 2017
  15. Junio C HamanoNov 21, 2017
  16. Jeff KingNov 21, 2017
  17. Junio C HamanoNov 22, 2017
  18. Jeff KingNov 22, 2017
  19. Junio C HamanoNov 23, 2017
  20. Jeff KingNov 24, 2017
  21. Junio C HamanoNov 25, 2017
  22. Junio C HamanoNov 21, 2017
  23. Jeff KingNov 21, 2017
  24. Junio C HamanoNov 22, 2017
  25. Jeff KingNov 22, 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.