Commit f7ebbb5
authored
odb: scan all sources' packfiles before loose objects (#975)
Switching branches in a VFS for Git or Scalar enlistment became drastically
slower in Git v2.55. The cause is the interaction of two independent changes,
not a single one.
Commit 062b914 (treewide: convert users of repo_has_object_file() to
has_object()), first released in v2.50, accidentally inverted the object
existence check in cache_tree_fully_valid(), so that function bailed out at the
root instead of validating the cache tree recursively. Commit 5217312
(cache-tree: fix inverted object existence check in cache_tree_fully_valid),
first released in v2.55, correctly restored the recursion.
In between, v2.54's per-source object database refactor changed the
cross-source lookup order: instead of scanning all packfiles before any loose
object store, it scans packed then loose per source. That change caused no
observable checkout regression in v2.54 precisely because the inverted check
prevented recursion and thereby masked the per-object cost. Conversely, v2.49
did recurse, yet stayed fast because its global pack-first lookup found the
objects in an alternate's packs before attempting any loose lookup. v2.55 is
therefore the first version combining recursive cache-tree validation with
per-source packed-then-loose lookup, at a cost of roughly one wasted primary
loose-object lstat() per cache-tree node.
In enlistments that use an alternate object cache, that cost is severe.
cache_tree_fully_valid() calls odb_has_object() hundreds of thousands of times,
and ODB_HAS_OBJECT_RECHECK_PACKED clears OBJECT_INFO_QUICK, so each call
performs a real lstat() in the primary loose object store before the object is
found in the alternate's packfile. On a measured index with about 2.4M entries:
381,006 cache-tree nodes, 380,944 wasted lstat() calls, not a single miss;
cache-tree validation took about 32 seconds and switching to a branch pointing
at the same commit about 36 seconds.
This merge restores the all-sources-packed-before-all-sources-loose order
whenever more than one source is present. The wasted stats are gone, validation
drops to about 2 seconds and branch switching to about 6-7 seconds. Presence
semantics are unchanged.
The trade-off needs to be stated plainly: the mitigation lives in the shared
object-info lookup, which is a slightly incorrect representation layer for a
problem specific to presence-only queries via odb_has_object(). When an object
is loose in the primary and packed in an alternate, metadata callers now
observe the alternate's packed representation. Observable differences include
reported on-disk size, mtime, delta base, corruption handling, and
promisor-pack classification. Object content, type and logical size, as well as
presence, remain correct because objects are content-addressed, which bounds
the fallout to the representation level. We accept those behavior changes
deliberately in exchange for fixing an intolerable regression in this fork now.
The architecturally correct fix is upstream's plan to move alternate handling
into the files backend. That backend would own both the primary and the
alternates and could therefore scan all relevant packs before any loose-object
lookup without violating the abstraction. The upstream contributor estimates
that work at "three to four patch years", i.e. likely months in Git project
time, and probably not before Git 2.56. microsoft/git cannot wait that long.
This merge is consequently an explicitly temporary mitigation specific to
Microsoft Git. Once upstream's fix lands, this implementation should be
replaced and the regression test reassessed. That test currently asserts
packed-versus-loose selection through %(deltabase), which necessarily pins
representation ordering and may not survive the upstream architecture. A future
replacement could instead verify the absence of the unwanted lstat() calls
directly, possibly as a Linux-only strace test, since the behavior itself is
platform-independent.4 files changed
Lines changed: 94 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
756 | 756 | | |
757 | 757 | | |
758 | 758 | | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
759 | 772 | | |
760 | 773 | | |
761 | 774 | | |
| |||
781 | 794 | | |
782 | 795 | | |
783 | 796 | | |
784 | | - | |
785 | | - | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
786 | 811 | | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
787 | 819 | | |
788 | 820 | | |
789 | 821 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
332 | 332 | | |
333 | 333 | | |
334 | 334 | | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
335 | 347 | | |
336 | 348 | | |
337 | 349 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
59 | 63 | | |
60 | 64 | | |
61 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
91 | 134 | | |
0 commit comments