bitmap: integrate a lookup table extension to the bitmap format
PATCH v5 3/6 pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Teach Git to provide a way for users to enable/disable bitmap lookup table extension by providing a config option named 'writeBitmapLookupTable'. Default is false.
Also add test to verify writting of lookup table.
--- Documentation/config/pack.txt | 7 + builtin/multi-pack-index.c | 7 + builtin/pack-objects.c | 8 + midx.c | 3 + midx.h | 1 + t/t5310-pack-bitmaps.sh | 792 ++++++++++++++++-------------- t/t5311-pack-bitmaps-shallow.sh | 53 +- t/t5326-multi-pack-bitmaps.sh | 421 +++++++++------- t/t5327-multi-pack-bitmaps-rev.sh | 24 +- 9 files changed, 733 insertions(+), 583 deletions(-)
Documentation/config/pack.txt +7 -0
@@ -164,6 +164,13 @@ When writing a multi-pack reachability bitmap, no new namehashes are computed; instead, any namehashes stored in an existing bitmap are permuted into their appropriate location when writing a new bitmap. +pack.writeBitmapLookupTable:: + When true, Git will include a "lookup table" section in the + bitmap index (if one is written). This table is used to defer + loading individual bitmaps as late as possible. This can be + beneficial in repositories that have relatively large bitmap + indexes. Defaults to false. + pack.writeReverseIndex:: When true, git will write a corresponding .rev file (see: link:../technical/pack-format.html[Documentation/technical/pack-format.txt])
builtin/multi-pack-index.c +7 -0
@@ -87,6 +87,13 @@ static int git_multi_pack_index_write_config(const char *var, const char *value, opts.flags &= ~MIDX_WRITE_BITMAP_HASH_CACHE ; } +if (!strcmp (var,"pack.writebitmaplookuptable" )) { +if (git_config_bool (var, value)) + opts.flags |=MIDX_WRITE_BITMAP_LOOKUP_TABLE ; +else + opts.flags &= ~MIDX_WRITE_BITMAP_LOOKUP_TABLE ; + } +/* * We should never make a fall-back call to 'git_default_config', since * this was already called in 'cmd_multi_pack_index()'.
builtin/pack-objects.c +8 -0
@@ -3148,6 +3148,14 @@ static int git_pack_config(const char *k, const char *v, void *cb)else write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE ; } + +if (!strcmp (k,"pack.writebitmaplookuptable" )) { +if (git_config_bool (k, v)) + write_bitmap_options |=BITMAP_OPT_LOOKUP_TABLE ; +else + write_bitmap_options &= ~BITMAP_OPT_LOOKUP_TABLE ; + } +if (!strcmp (k,"pack.usebitmaps" )) { use_bitmap_index_default =git_config_bool (k, v);return 0 ;
midx.c +3 -0
@@ -1072,6 +1072,9 @@ static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,if (flags &MIDX_WRITE_BITMAP_HASH_CACHE ) options |=BITMAP_OPT_HASH_CACHE ; +if (flags &MIDX_WRITE_BITMAP_LOOKUP_TABLE ) + options |=BITMAP_OPT_LOOKUP_TABLE ; +prepare_midx_packing_data (&pdata, ctx); commits =find_commits_for_midx_bitmap (&commits_nr, refs_snapshot, ctx);
midx.h +1 -0
@@ -47,6 +47,7 @@ struct multi_pack_index {#define MIDX_WRITE_REV_INDEX (1 << 1)#define MIDX_WRITE_BITMAP (1 << 2)#define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3) +#define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)const unsigned char *get_midx_checksum (struct multi_pack_index *m);void get_midx_filename (struct strbuf *out,const char *object_dir);
t/t5310-pack-bitmaps.sh +410 -382
807 lines not on this page · raw message
t/t5311-pack-bitmaps-shallow.sh +35 -18
58 lines not on this page · raw message
t/t5326-multi-pack-bitmaps.sh +240 -181
513 lines not on this page · raw message
t/t5327-multi-pack-bitmaps-rev.sh +22 -2
@@ -17,7 +17,27 @@ GIT_TEST_MIDX_READ_RIDX=0 export GIT_TEST_MIDX_WRITE_REV export GIT_TEST_MIDX_READ_RIDX -midx_bitmap_core rev -midx_bitmap_partial_tests rev +test_midx_bitmap_rev () { + writeLookupTable=false + + for i in "$@" + do + case $i in + "pack.writeBitmapLookupTable") writeLookupTable=true;; + esac + done + + test_expect_success 'setup bitmap config' ' + rm -rf * .git && + git init && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' + ' + + midx_bitmap_core rev + midx_bitmap_partial_tests rev + } + + test_midx_bitmap_rev + test_midx_bitmap_rev "pack.writeBitmapLookupTable" test_done
Signature · 1 line
gitgitgadget
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 12 lines · Abhradeep Chakraborty via GitGitGadget
From: Abhradeep Chakraborty <[email protected]>
Teach Git to provide a way for users to enable/disable bitmap lookup table extension by providing a config option named 'writeBitmapLookupTable'. Default is false.
Also add test to verify writting of lookup table.
Mentored-by Taylor Blau <[email protected]>Co-Mentored-by Kaartic Sivaraam <[email protected]>Co-Authored-by Taylor Blau <[email protected]>Signed-off-by Abhradeep Chakraborty <[email protected]>
Quoted 9 lines
--- Documentation/config/pack.txt | 7 + builtin/multi-pack-index.c | 7 + builtin/pack-objects.c | 8 + midx.c | 3 + midx.h | 1 + t/t5310-pack-bitmaps.sh | 792 ++++++++++++++++-------------- t/t5311-pack-bitmaps-shallow.sh | 53 +- t/t5326-multi-pack-bitmaps.sh | 421 +++++++++-------
That's quite a large a change, and unfortunately I pinpointed a flake to this patch when running with GIT_TEST_DEFAULT_HASH=sha256. The symptom is this:
-- snip --
[...]
+ diff -u expect.normalized actual.normalized
+ rm -f expect.normalized actual.normalized
ok 317 - enumerate --objects (full bitmap, other)
expecting success of 5326.318 'bitmap --objects handles non-commit objects (full bitmap, other)':
git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && grep $blob actual
+ git rev-list --objects --use-bitmap-index other tagged-blob
+ grep bff4ed5e839bd73e821f78b45a7fa34208aa85596535ec8e9ac5eab477ca6f81 actual bff4ed5e839bd73e821f78b45a7fa34208aa85596535ec8e9ac5eab477ca6f81 ok 318 - bitmap --objects handles non-commit objects (full bitmap, other)
expecting success of 5326.319 'clone from bitmapped repository':
rm -fr clone.git &&
git clone --no-local --bare . clone.git &&
git rev-parse HEAD >expect &&
git --git-dir=clone.git rev-parse HEAD >actual &&
test_cmp expect actual+ rm -fr clone.git
+ git clone --no-local --bare . clone.git
Cloning into bare repository 'clone.git'...
remote: Enumerating objects: 756, done.
remote: Counting objects: 100% (754/754), done.
remote: Compressing objects: 100% (281/281), done.
remote: Total 756 (delta 245), reused 740 (delta 234), pack-reused 2
Receiving objects: 100% (756/756), 77.50 KiB | 8.61 MiB/s, done.
fatal: REF_DELTA at offset 221 already resolved (duplicate base 4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cf?)
fatal: fetch-pack: invalid index-pack output
error: last command exited with $?=128
not ok 319 - clone from bitmapped repository
#
# rm -fr clone.git && # git clone --no-local --bare . clone.git && # git rev-parse HEAD >expect && # git --git-dir=clone.git rev-parse HEAD >actual && # test_cmp expect actual
#
1..319
-- snap --
On a hunch, I ran this through valgrind (took a while) but it did not point out the problem.
Again, this is only with SHA-256 (and somewhat flaky), it passes every time with SHA-1. Maybe you can reproduce on your side with that information?
Sadly, this patch is way too large for me to do a drive-by debugging session, so I will have to leave it to you to investigate further.
Ciao,
Dscho
Quoted 1,520 lines
t/t5327-multi-pack-bitmaps-rev.sh | 24 +- 9 files changed, 733 insertions(+), 583 deletions(-)Documentation/config/pack.txt +7
-0@@ -164,6 +164,13 @@ When writing a multi-pack reachability bitmap, no new namehashes are computed; instead, any namehashes stored in an existing bitmap are permuted into their appropriate location when writing a new bitmap. +pack.writeBitmapLookupTable:: + When true, Git will include a "lookup table" section in the + bitmap index (if one is written). This table is used to defer + loading individual bitmaps as late as possible. This can be + beneficial in repositories that have relatively large bitmap + indexes. Defaults to false. + pack.writeReverseIndex:: When true, git will write a corresponding .rev file (see: link:../technical/pack-format.html[Documentation/technical/pack-format.txt])builtin/multi-pack-index.c +7
-0@@ -87,6 +87,13 @@ static int git_multi_pack_index_write_config(const char *var, const char *value, opts.flags &= ~MIDX_WRITE_BITMAP_HASH_CACHE ; } +if (!strcmp (var,"pack.writebitmaplookuptable" )) { +if (git_config_bool (var, value)) + opts.flags |=MIDX_WRITE_BITMAP_LOOKUP_TABLE ; +else + opts.flags &= ~MIDX_WRITE_BITMAP_LOOKUP_TABLE ; + } +/* * We should never make a fall-back call to 'git_default_config', since * this was already called in 'cmd_multi_pack_index()'. builtin/pack-objects.c +8
-0@@ -3148,6 +3148,14 @@ static int git_pack_config(const char *k, const char *v, void *cb)else write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE ; } + +if (!strcmp (k,"pack.writebitmaplookuptable" )) { +if (git_config_bool (k, v)) + write_bitmap_options |=BITMAP_OPT_LOOKUP_TABLE ; +else + write_bitmap_options &= ~BITMAP_OPT_LOOKUP_TABLE ; + } +if (!strcmp (k,"pack.usebitmaps" )) { use_bitmap_index_default =git_config_bool (k, v);return 0 ;midx.c +3
-0@@ -1072,6 +1072,9 @@ static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,if (flags &MIDX_WRITE_BITMAP_HASH_CACHE ) options |=BITMAP_OPT_HASH_CACHE ; +if (flags &MIDX_WRITE_BITMAP_LOOKUP_TABLE ) + options |=BITMAP_OPT_LOOKUP_TABLE ; +prepare_midx_packing_data (&pdata, ctx); commits =find_commits_for_midx_bitmap (&commits_nr, refs_snapshot, ctx);midx.h +1
-0@@ -47,6 +47,7 @@ struct multi_pack_index {#define MIDX_WRITE_REV_INDEX (1 << 1)#define MIDX_WRITE_BITMAP (1 << 2)#define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3) +#define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)const unsigned char *get_midx_checksum (struct multi_pack_index *m);void get_midx_filename (struct strbuf *out,const char *object_dir);t/t5310-pack-bitmaps.sh +410
-382@@ -26,22 +26,413 @@ has_any () { grep -Ff "$1" "$2" } -setup_bitmap_history - -test_expect_success 'setup writing bitmaps during repack' ' - git config repack.writeBitmaps true -' - -test_expect_success 'full repack creates bitmaps' ' - GIT_TRACE2_EVENT="$(pwd)/trace" \ +test_bitmap_cases () { + writeLookupTable=false + for i in "$@" + do + case "$i" in + "pack.writeBitmapLookupTable") writeLookupTable=true;; + esac + done + + test_expect_success 'setup test repository' ' + rm -fr * .git && + git init && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' + ' + setup_bitmap_history + + test_expect_success 'setup writing bitmaps during repack' ' + git config repack.writeBitmaps true + ' + + test_expect_success 'full repack creates bitmaps' ' + GIT_TRACE2_EVENT="$(pwd)/trace" \ + git repack -ad && + ls .git/objects/pack/ | grep bitmap >output && + test_line_count = 1 output && + grep "\"key\":\"num_selected_commits\",\"value\":\"106\"" trace && + grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace + ' + + basic_bitmap_tests + + test_expect_success 'pack-objects respects --local (non-local loose)' ' + git init --bare alt.git && + echo $(pwd)/alt.git/objects >.git/objects/info/alternates && + echo content1 >file1 && + # non-local loose object which is not present in bitmapped pack + altblob=$(GIT_DIR=alt.git git hash-object -w file1) && + # non-local loose object which is also present in bitmapped pack + git cat-file blob $blob | GIT_DIR=alt.git git hash-object -w --stdin && + git add file1 && + test_tick && + git commit -m commit_file1 && + echo HEAD | git pack-objects --local --stdout --revs >1.pack && + git index-pack 1.pack && + list_packed_objects 1.idx >1.objects && + printf "%s\n" "$altblob" "$blob" >nonlocal-loose && + ! has_any nonlocal-loose 1.objects + ' + + test_expect_success 'pack-objects respects --honor-pack-keep (local non-bitmapped pack)' ' + echo content2 >file2 && + blob2=$(git hash-object -w file2) && + git add file2 && + test_tick && + git commit -m commit_file2 && + printf "%s\n" "$blob2" "$bitmaptip" >keepobjects && + pack2=$(git pack-objects pack2 <keepobjects) && + mv pack2-$pack2.* .git/objects/pack/ && + >.git/objects/pack/pack2-$pack2.keep && + rm $(objpath $blob2) && + echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >2a.pack && + git index-pack 2a.pack && + list_packed_objects 2a.idx >2a.objects && + ! has_any keepobjects 2a.objects + ' + + test_expect_success 'pack-objects respects --local (non-local pack)' ' + mv .git/objects/pack/pack2-$pack2.* alt.git/objects/pack/ && + echo HEAD | git pack-objects --local --stdout --revs >2b.pack && + git index-pack 2b.pack && + list_packed_objects 2b.idx >2b.objects && + ! has_any keepobjects 2b.objects + ' + + test_expect_success 'pack-objects respects --honor-pack-keep (local bitmapped pack)' ' + ls .git/objects/pack/ | grep bitmap >output && + test_line_count = 1 output && + packbitmap=$(basename $(cat output) .bitmap) && + list_packed_objects .git/objects/pack/$packbitmap.idx >packbitmap.objects && + test_when_finished "rm -f .git/objects/pack/$packbitmap.keep" && + >.git/objects/pack/$packbitmap.keep && + echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >3a.pack && + git index-pack 3a.pack && + list_packed_objects 3a.idx >3a.objects && + ! has_any packbitmap.objects 3a.objects + ' + + test_expect_success 'pack-objects respects --local (non-local bitmapped pack)' ' + mv .git/objects/pack/$packbitmap.* alt.git/objects/pack/ && + rm -f .git/objects/pack/multi-pack-index && + test_when_finished "mv alt.git/objects/pack/$packbitmap.* .git/objects/pack/" && + echo HEAD | git pack-objects --local --stdout --revs >3b.pack && + git index-pack 3b.pack && + list_packed_objects 3b.idx >3b.objects && + ! has_any packbitmap.objects 3b.objects + ' + + test_expect_success 'pack-objects to file can use bitmap' ' + # make sure we still have 1 bitmap index from previous tests + ls .git/objects/pack/ | grep bitmap >output && + test_line_count = 1 output && + # verify equivalent packs are generated with/without using bitmap index + packasha1=$(git pack-objects --no-use-bitmap-index --all packa </dev/null) && + packbsha1=$(git pack-objects --use-bitmap-index --all packb </dev/null) && + list_packed_objects packa-$packasha1.idx >packa.objects && + list_packed_objects packb-$packbsha1.idx >packb.objects && + test_cmp packa.objects packb.objects + ' + + test_expect_success 'full repack, reusing previous bitmaps' ' git repack -ad && - ls .git/objects/pack/ | grep bitmap >output && - test_line_count = 1 output && - grep "\"key\":\"num_selected_commits\",\"value\":\"106\"" trace && - grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace -' + ls .git/objects/pack/ | grep bitmap >output && + test_line_count = 1 output + ' + + test_expect_success 'fetch (full bitmap)' ' + git --git-dir=clone.git fetch origin second:second && + git rev-parse HEAD >expect && + git --git-dir=clone.git rev-parse HEAD >actual && + test_cmp expect actual + ' + + test_expect_success 'create objects for missing-HAVE tests' ' + blob=$(echo "missing have" | git hash-object -w --stdin) && + tree=$(printf "100644 blob $blob\tfile\n" | git mktree) && + parent=$(echo parent | git commit-tree $tree) && + commit=$(echo commit | git commit-tree $tree -p $parent) && + cat >revs <<-EOF + HEAD + ^HEAD^ + ^$commit + EOF + ' + + test_expect_success 'pack-objects respects --incremental' ' + cat >revs2 <<-EOF && + HEAD + $commit + EOF + git pack-objects --incremental --stdout --revs <revs2 >4.pack && + git index-pack 4.pack && + list_packed_objects 4.idx >4.objects && + test_line_count = 4 4.objects && + git rev-list --objects $commit >revlist && + cut -d" " -f1 revlist |sort >objects && + test_cmp 4.objects objects + ' + + test_expect_success 'pack with missing blob' ' + rm $(objpath $blob) && + git pack-objects --stdout --revs <revs >/dev/null + ' + + test_expect_success 'pack with missing tree' ' + rm $(objpath $tree) && + git pack-objects --stdout --revs <revs >/dev/null + ' + + test_expect_success 'pack with missing parent' ' + rm $(objpath $parent) && + git pack-objects --stdout --revs <revs >/dev/null + ' + + test_expect_success JGIT,SHA1 'we can read jgit bitmaps' ' + git clone --bare . compat-jgit.git && + ( + cd compat-jgit.git && + rm -f objects/pack/*.bitmap && + jgit gc && + git rev-list --test-bitmap HEAD + ) + ' + + test_expect_success JGIT,SHA1 'jgit can read our bitmaps' ' + git clone --bare . compat-us.git && + ( + cd compat-us.git && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + git repack -adb && + # jgit gc will barf if it does not like our bitmaps + jgit gc + ) + ' + + test_expect_success 'splitting packs does not generate bogus bitmaps' ' + test-tool genrandom foo $((1024 * 1024)) >rand && + git add rand && + git commit -m "commit with big file" && + git -c pack.packSizeLimit=500k repack -adb && + git init --bare no-bitmaps.git && + git -C no-bitmaps.git fetch .. HEAD + ' + + test_expect_success 'set up reusable pack' ' + rm -f .git/objects/pack/*.keep && + git repack -adb && + reusable_pack () { + git for-each-ref --format="%(objectname)" | + git pack-objects --delta-base-offset --revs --stdout "$@" + } + ' + + test_expect_success 'pack reuse respects --honor-pack-keep' ' + test_when_finished "rm -f .git/objects/pack/*.keep" && + for i in .git/objects/pack/*.pack + do + >${i%.pack}.keep || return 1 + done && + reusable_pack --honor-pack-keep >empty.pack && + git index-pack empty.pack && + git show-index <empty.idx >actual && + test_must_be_empty actual + ' + + test_expect_success 'pack reuse respects --local' ' + mv .git/objects/pack/* alt.git/objects/pack/ && + test_when_finished "mv alt.git/objects/pack/* .git/objects/pack/" && + reusable_pack --local >empty.pack && + git index-pack empty.pack && + git show-index <empty.idx >actual && + test_must_be_empty actual + ' + + test_expect_success 'pack reuse respects --incremental' ' + reusable_pack --incremental >empty.pack && + git index-pack empty.pack && + git show-index <empty.idx >actual && + test_must_be_empty actual + ' + + test_expect_success 'truncated bitmap fails gracefully (ewah)' ' + test_config pack.writebitmaphashcache false && + git repack -ad && + git rev-list --use-bitmap-index --count --all >expect && + bitmap=$(ls .git/objects/pack/*.bitmap) && + test_when_finished "rm -f $bitmap" && + test_copy_bytes 256 <$bitmap >$bitmap.tmp && + mv -f $bitmap.tmp $bitmap && + git rev-list --use-bitmap-index --count --all >actual 2>stderr && + test_cmp expect actual && + test_i18ngrep corrupt.ewah.bitmap stderr + ' + + test_expect_success 'truncated bitmap fails gracefully (cache)' ' + git repack -ad && + git rev-list --use-bitmap-index --count --all >expect && + bitmap=$(ls .git/objects/pack/*.bitmap) && + test_when_finished "rm -f $bitmap" && + test_copy_bytes 512 <$bitmap >$bitmap.tmp && + mv -f $bitmap.tmp $bitmap && + git rev-list --use-bitmap-index --count --all >actual 2>stderr && + test_cmp expect actual && + test_i18ngrep corrupted.bitmap.index stderr + ' + + # Create a state of history with these properties: + # + # - refs that allow a client to fetch some new history, while sharing some old + # history with the server; we use branches delta-reuse-old and + # delta-reuse-new here + # + # - the new history contains an object that is stored on the server as a delta + # against a base that is in the old history + # + # - the base object is not immediately reachable from the tip of the old + # history; finding it would involve digging down through history we know the + # other side has + # + # This should result in a state where fetching from old->new would not + # traditionally reuse the on-disk delta (because we'd have to dig to realize + # that the client has it), but we will do so if bitmaps can tell us cheaply + # that the other side has it. + test_expect_success 'set up thin delta-reuse parent' ' + # This first commit contains the buried base object. + test-tool genrandom delta 16384 >file && + git add file && + git commit -m "delta base" && + base=$(git rev-parse --verify HEAD:file) && + + # These intermediate commits bury the base back in history. + # This becomes the "old" state. + for i in 1 2 3 4 5 + do + echo $i >file && + git commit -am "intermediate $i" || return 1 + done && + git branch delta-reuse-old && + + # And now our new history has a delta against the buried base. Note + # that this must be smaller than the original file, since pack-objects + # prefers to create deltas from smaller objects to larger. + test-tool genrandom delta 16300 >file && + git commit -am "delta result" && + delta=$(git rev-parse --verify HEAD:file) && + git branch delta-reuse-new && + + # Repack with bitmaps and double check that we have the expected delta + # relationship. + git repack -adb && + have_delta $delta $base + ' + + # Now we can sanity-check the non-bitmap behavior (that the server is not able + # to reuse the delta). This isn't strictly something we care about, so this + # test could be scrapped in the future. But it makes sure that the next test is + # actually triggering the feature we want. + # + # Note that our tools for working with on-the-wire "thin" packs are limited. So + # we actually perform the fetch, retain the resulting pack, and inspect the + # result. + test_expect_success 'fetch without bitmaps ignores delta against old base' ' + test_config pack.usebitmaps false && + test_when_finished "rm -rf client.git" && + git init --bare client.git && + ( + cd client.git && + git config transfer.unpackLimit 1 && + git fetch .. delta-reuse-old:delta-reuse-old && + git fetch .. delta-reuse-new:delta-reuse-new && + have_delta $delta $ZERO_OID + ) + ' + + # And do the same for the bitmap case, where we do expect to find the delta. + test_expect_success 'fetch with bitmaps can reuse old base' ' + test_config pack.usebitmaps true && + test_when_finished "rm -rf client.git" && + git init --bare client.git && + ( + cd client.git && + git config transfer.unpackLimit 1 && + git fetch .. delta-reuse-old:delta-reuse-old && + git fetch .. delta-reuse-new:delta-reuse-new && + have_delta $delta $base + ) + ' + + test_expect_success 'pack.preferBitmapTips' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + + # create enough commits that not all are receive bitmap + # coverage even if they are all at the tip of some reference. + test_commit_bulk --message="%s" 103 && + + git rev-list HEAD >commits.raw && + sort <commits.raw >commits && + + git log --format="create refs/tags/%s %H" HEAD >refs && + git update-ref --stdin <refs && + + git repack -adb && + test-tool bitmap list-commits | sort >bitmaps && + + # remember which commits did not receive bitmaps + comm -13 bitmaps commits >before && + test_file_not_empty before && + + # mark the commits which did not receive bitmaps as preferred, + # and generate the bitmap again + perl -pe "s{^}{create refs/tags/include/$. }" <before | + git update-ref --stdin && + git -c pack.preferBitmapTips=refs/tags/include repack -adb && + + # finally, check that the commit(s) without bitmap coverage + # are not the same ones as before + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >after && + + ! test_cmp before after + ) + ' + + test_expect_success 'complains about multiple pack bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + + test_commit base && + + git repack -adb && + bitmap="$(ls .git/objects/pack/pack-*.bitmap)" && + mv "$bitmap" "$bitmap.bak" && + + test_commit other && + git repack -ab && + + mv "$bitmap.bak" "$bitmap" && + + find .git/objects/pack -type f -name "*.pack" >packs && + find .git/objects/pack -type f -name "*.bitmap" >bitmaps && + test_line_count = 2 packs && + test_line_count = 2 bitmaps && + + git rev-list --use-bitmap-index HEAD 2>err && + grep "ignoring extra bitmap file" err + ) + ' +} -basic_bitmap_tests +test_bitmap_cases test_expect_success 'incremental repack fails when bitmaps are requested' ' test_commit more-1 &&@@ -54,375 +445,12 @@ test_expect_success 'incremental repack can disable bitmaps' ' git repack -d --no-write-bitmap-index ' -test_expect_success 'pack-objects respects --local (non-local loose)' ' - git init --bare alt.git && - echo $(pwd)/alt.git/objects >.git/objects/info/alternates && - echo content1 >file1 && - # non-local loose object which is not present in bitmapped pack - altblob=$(GIT_DIR=alt.git git hash-object -w file1) && - # non-local loose object which is also present in bitmapped pack - git cat-file blob $blob | GIT_DIR=alt.git git hash-object -w --stdin && - git add file1 && - test_tick && - git commit -m commit_file1 && - echo HEAD | git pack-objects --local --stdout --revs >1.pack && - git index-pack 1.pack && - list_packed_objects 1.idx >1.objects && - printf "%s\n" "$altblob" "$blob" >nonlocal-loose && - ! has_any nonlocal-loose 1.objects -' - -test_expect_success 'pack-objects respects --honor-pack-keep (local non-bitmapped pack)' ' - echo content2 >file2 && - blob2=$(git hash-object -w file2) && - git add file2 && - test_tick && - git commit -m commit_file2 && - printf "%s\n" "$blob2" "$bitmaptip" >keepobjects && - pack2=$(git pack-objects pack2 <keepobjects) && - mv pack2-$pack2.* .git/objects/pack/ && - >.git/objects/pack/pack2-$pack2.keep && - rm $(objpath $blob2) && - echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >2a.pack && - git index-pack 2a.pack && - list_packed_objects 2a.idx >2a.objects && - ! has_any keepobjects 2a.objects -' - -test_expect_success 'pack-objects respects --local (non-local pack)' ' - mv .git/objects/pack/pack2-$pack2.* alt.git/objects/pack/ && - echo HEAD | git pack-objects --local --stdout --revs >2b.pack && - git index-pack 2b.pack && - list_packed_objects 2b.idx >2b.objects && - ! has_any keepobjects 2b.objects -' - -test_expect_success 'pack-objects respects --honor-pack-keep (local bitmapped pack)' ' - ls .git/objects/pack/ | grep bitmap >output && - test_line_count = 1 output && - packbitmap=$(basename $(cat output) .bitmap) && - list_packed_objects .git/objects/pack/$packbitmap.idx >packbitmap.objects && - test_when_finished "rm -f .git/objects/pack/$packbitmap.keep" && - >.git/objects/pack/$packbitmap.keep && - echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >3a.pack && - git index-pack 3a.pack && - list_packed_objects 3a.idx >3a.objects && - ! has_any packbitmap.objects 3a.objects -' - -test_expect_success 'pack-objects respects --local (non-local bitmapped pack)' ' - mv .git/objects/pack/$packbitmap.* alt.git/objects/pack/ && - rm -f .git/objects/pack/multi-pack-index && - test_when_finished "mv alt.git/objects/pack/$packbitmap.* .git/objects/pack/" && - echo HEAD | git pack-objects --local --stdout --revs >3b.pack && - git index-pack 3b.pack && - list_packed_objects 3b.idx >3b.objects && - ! has_any packbitmap.objects 3b.objects -' - -test_expect_success 'pack-objects to file can use bitmap' ' - # make sure we still have 1 bitmap index from previous tests - ls .git/objects/pack/ | grep bitmap >output && - test_line_count = 1 output && - # verify equivalent packs are generated with/without using bitmap index - packasha1=$(git pack-objects --no-use-bitmap-index --all packa </dev/null) && - packbsha1=$(git pack-objects --use-bitmap-index --all packb </dev/null) && - list_packed_objects packa-$packasha1.idx >packa.objects && - list_packed_objects packb-$packbsha1.idx >packb.objects && - test_cmp packa.objects packb.objects -' - -test_expect_success 'full repack, reusing previous bitmaps' ' - git repack -ad && - ls .git/objects/pack/ | grep bitmap >output && - test_line_count = 1 output -' - -test_expect_success 'fetch (full bitmap)' ' - git --git-dir=clone.git fetch origin second:second && - git rev-parse HEAD >expect && - git --git-dir=clone.git rev-parse HEAD >actual && - test_cmp expect actual -' - -test_expect_success 'create objects for missing-HAVE tests' ' - blob=$(echo "missing have" | git hash-object -w --stdin) && - tree=$(printf "100644 blob $blob\tfile\n" | git mktree) && - parent=$(echo parent | git commit-tree $tree) && - commit=$(echo commit | git commit-tree $tree -p $parent) && - cat >revs <<-EOF - HEAD - ^HEAD^ - ^$commit - EOF -' - -test_expect_success 'pack-objects respects --incremental' ' - cat >revs2 <<-EOF && - HEAD - $commit - EOF - git pack-objects --incremental --stdout --revs <revs2 >4.pack && - git index-pack 4.pack && - list_packed_objects 4.idx >4.objects && - test_line_count = 4 4.objects && - git rev-list --objects $commit >revlist && - cut -d" " -f1 revlist |sort >objects && - test_cmp 4.objects objects -' - -test_expect_success 'pack with missing blob' ' - rm $(objpath $blob) && - git pack-objects --stdout --revs <revs >/dev/null -' +test_bitmap_cases "pack.writeBitmapLookupTable" -test_expect_success 'pack with missing tree' ' - rm $(objpath $tree) && - git pack-objects --stdout --revs <revs >/dev/null -' - -test_expect_success 'pack with missing parent' ' - rm $(objpath $parent) && - git pack-objects --stdout --revs <revs >/dev/null -' - -test_expect_success JGIT,SHA1 'we can read jgit bitmaps' ' - git clone --bare . compat-jgit.git && - ( - cd compat-jgit.git && - rm -f objects/pack/*.bitmap && - jgit gc && - git rev-list --test-bitmap HEAD - ) -' - -test_expect_success JGIT,SHA1 'jgit can read our bitmaps' ' - git clone --bare . compat-us.git && - ( - cd compat-us.git && - git repack -adb && - # jgit gc will barf if it does not like our bitmaps - jgit gc - ) -' - -test_expect_success 'splitting packs does not generate bogus bitmaps' ' - test-tool genrandom foo $((1024 * 1024)) >rand && - git add rand && - git commit -m "commit with big file" && - git -c pack.packSizeLimit=500k repack -adb && - git init --bare no-bitmaps.git && - git -C no-bitmaps.git fetch .. HEAD -' - -test_expect_success 'set up reusable pack' ' - rm -f .git/objects/pack/*.keep && - git repack -adb && - reusable_pack () { - git for-each-ref --format="%(objectname)" | - git pack-objects --delta-base-offset --revs --stdout "$@" - } -' - -test_expect_success 'pack reuse respects --honor-pack-keep' ' - test_when_finished "rm -f .git/objects/pack/*.keep" && - for i in .git/objects/pack/*.pack - do - >${i%.pack}.keep || return 1 - done && - reusable_pack --honor-pack-keep >empty.pack && - git index-pack empty.pack && - git show-index <empty.idx >actual && - test_must_be_empty actual -' - -test_expect_success 'pack reuse respects --local' ' - mv .git/objects/pack/* alt.git/objects/pack/ && - test_when_finished "mv alt.git/objects/pack/* .git/objects/pack/" && - reusable_pack --local >empty.pack && - git index-pack empty.pack && - git show-index <empty.idx >actual && - test_must_be_empty actual -' - -test_expect_success 'pack reuse respects --incremental' ' - reusable_pack --incremental >empty.pack && - git index-pack empty.pack && - git show-index <empty.idx >actual && - test_must_be_empty actual -' - -test_expect_success 'truncated bitmap fails gracefully (ewah)' ' - test_config pack.writebitmaphashcache false && - git repack -ad && - git rev-list --use-bitmap-index --count --all >expect && - bitmap=$(ls .git/objects/pack/*.bitmap) && - test_when_finished "rm -f $bitmap" && - test_copy_bytes 256 <$bitmap >$bitmap.tmp && - mv -f $bitmap.tmp $bitmap && - git rev-list --use-bitmap-index --count --all >actual 2>stderr && - test_cmp expect actual && - test_i18ngrep corrupt.ewah.bitmap stderr -' - -test_expect_success 'truncated bitmap fails gracefully (cache)' ' - git repack -ad && - git rev-list --use-bitmap-index --count --all >expect && - bitmap=$(ls .git/objects/pack/*.bitmap) && - test_when_finished "rm -f $bitmap" && - test_copy_bytes 512 <$bitmap >$bitmap.tmp && - mv -f $bitmap.tmp $bitmap && - git rev-list --use-bitmap-index --count --all >actual 2>stderr && - test_cmp expect actual && - test_i18ngrep corrupted.bitmap.index stderr -' - -# Create a state of history with these properties: -# -# - refs that allow a client to fetch some new history, while sharing some old -# history with the server; we use branches delta-reuse-old and -# delta-reuse-new here -# -# - the new history contains an object that is stored on the server as a delta -# against a base that is in the old history -# -# - the base object is not immediately reachable from the tip of the old -# history; finding it would involve digging down through history we know the -# other side has -# -# This should result in a state where fetching from old->new would not -# traditionally reuse the on-disk delta (because we'd have to dig to realize -# that the client has it), but we will do so if bitmaps can tell us cheaply -# that the other side has it. -test_expect_success 'set up thin delta-reuse parent' ' - # This first commit contains the buried base object. - test-tool genrandom delta 16384 >file && - git add file && - git commit -m "delta base" && - base=$(git rev-parse --verify HEAD:file) && - - # These intermediate commits bury the base back in history. - # This becomes the "old" state. - for i in 1 2 3 4 5 - do - echo $i >file && - git commit -am "intermediate $i" || return 1 - done && - git branch delta-reuse-old && - - # And now our new history has a delta against the buried base. Note - # that this must be smaller than the original file, since pack-objects - # prefers to create deltas from smaller objects to larger. - test-tool genrandom delta 16300 >file && - git commit -am "delta result" && - delta=$(git rev-parse --verify HEAD:file) && - git branch delta-reuse-new && - - # Repack with bitmaps and double check that we have the expected delta - # relationship. - git repack -adb && - have_delta $delta $base -' - -# Now we can sanity-check the non-bitmap behavior (that the server is not able -# to reuse the delta). This isn't strictly something we care about, so this -# test could be scrapped in the future. But it makes sure that the next test is -# actually triggering the feature we want. -# -# Note that our tools for working with on-the-wire "thin" packs are limited. So -# we actually perform the fetch, retain the resulting pack, and inspect the -# result. -test_expect_success 'fetch without bitmaps ignores delta against old base' ' - test_config pack.usebitmaps false && - test_when_finished "rm -rf client.git" && - git init --bare client.git && - ( - cd client.git && - git config transfer.unpackLimit 1 && - git fetch .. delta-reuse-old:delta-reuse-old && - git fetch .. delta-reuse-new:delta-reuse-new && - have_delta $delta $ZERO_OID - ) -' - -# And do the same for the bitmap case, where we do expect to find the delta. -test_expect_success 'fetch with bitmaps can reuse old base' ' - test_config pack.usebitmaps true && - test_when_finished "rm -rf client.git" && - git init --bare client.git && - ( - cd client.git && - git config transfer.unpackLimit 1 && - git fetch .. delta-reuse-old:delta-reuse-old && - git fetch .. delta-reuse-new:delta-reuse-new && - have_delta $delta $base - ) -' - -test_expect_success 'pack.preferBitmapTips' ' - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && - - # create enough commits that not all are receive bitmap - # coverage even if they are all at the tip of some reference. - test_commit_bulk --message="%s" 103 && - - git rev-list HEAD >commits.raw && - sort <commits.raw >commits && - - git log --format="create refs/tags/%s %H" HEAD >refs && - git update-ref --stdin <refs && - - git repack -adb && - test-tool bitmap list-commits | sort >bitmaps && - - # remember which commits did not receive bitmaps - comm -13 bitmaps commits >before && - test_file_not_empty before && - - # mark the commits which did not receive bitmaps as preferred, - # and generate the bitmap again - perl -pe "s{^}{create refs/tags/include/$. }" <before | - git update-ref --stdin && - git -c pack.preferBitmapTips=refs/tags/include repack -adb && - - # finally, check that the commit(s) without bitmap coverage - # are not the same ones as before - test-tool bitmap list-commits | sort >bitmaps && - comm -13 bitmaps commits >after && - - ! test_cmp before after - ) -' - -test_expect_success 'complains about multiple pack bitmaps' ' - rm -fr repo && - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && - - test_commit base && - - git repack -adb && - bitmap="$(ls .git/objects/pack/pack-*.bitmap)" && - mv "$bitmap" "$bitmap.bak" && - - test_commit other && - git repack -ab && - - mv "$bitmap.bak" "$bitmap" && - - find .git/objects/pack -type f -name "*.pack" >packs && - find .git/objects/pack -type f -name "*.bitmap" >bitmaps && - test_line_count = 2 packs && - test_line_count = 2 bitmaps && - - git rev-list --use-bitmap-index HEAD 2>err && - grep "ignoring extra bitmap file" err - ) +test_expect_success 'verify writing bitmap lookup table when enabled' ' + GIT_TRACE2_EVENT="$(pwd)/trace2" \ + git repack -ad && + grep "\"label\":\"writing_lookup_table\"" trace2 ' test_donet/t5311-pack-bitmaps-shallow.sh +35
-18@@ -17,23 +17,40 @@ test_description='check bitmap operation with shallow repositories' # the tree for A. But in a shallow one, we've grafted away # A, and fetching A to B requires that the other side send # us the tree for file=1. -test_expect_success 'setup shallow repo' ' - echo 1 >file && - git add file && - git commit -m orig && - echo 2 >file && - git commit -a -m update && - git clone --no-local --bare --depth=1 . shallow.git && - echo 1 >file && - git commit -a -m repeat -' - -test_expect_success 'turn on bitmaps in the parent' ' - git repack -adb -' - -test_expect_success 'shallow fetch from bitmapped repo' ' - (cd shallow.git && git fetch) -' +test_shallow_bitmaps () { + writeLookupTable=false + + for i in "$@" + do + case $i in + "pack.writeBitmapLookupTable") writeLookupTable=true;; + esac + done + + test_expect_success 'setup shallow repo' ' + rm -rf * .git && + git init && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + echo 1 >file && + git add file && + git commit -m orig && + echo 2 >file && + git commit -a -m update && + git clone --no-local --bare --depth=1 . shallow.git && + echo 1 >file && + git commit -a -m repeat + ' + + test_expect_success 'turn on bitmaps in the parent' ' + git repack -adb + ' + + test_expect_success 'shallow fetch from bitmapped repo' ' + (cd shallow.git && git fetch) + ' +} + +test_shallow_bitmaps +test_shallow_bitmaps "pack.writeBitmapLookupTable" test_donet/t5326-multi-pack-bitmaps.sh +240
-181@@ -15,17 +15,24 @@ GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 sane_unset GIT_TEST_MIDX_WRITE_REV sane_unset GIT_TEST_MIDX_READ_RIDX -midx_bitmap_core - bitmap_reuse_tests() { from=$1 to=$2 + writeLookupTable=false + + for i in $3-${$#} + do + case $i in + "pack.writeBitmapLookupTable") writeLookupTable=true;; + esac + done test_expect_success "setup pack reuse tests ($from -> $to)" ' rm -fr repo && git init repo && ( cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && test_commit_bulk 16 && git tag old-tip &&@@ -43,6 +50,7 @@ bitmap_reuse_tests() { test_expect_success "build bitmap from existing ($from -> $to)" ' ( cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && test_commit_bulk --id=further 16 && git tag new-tip &&@@ -59,6 +67,7 @@ bitmap_reuse_tests() { test_expect_success "verify resulting bitmaps ($from -> $to)" ' ( cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && git for-each-ref && git rev-list --test-bitmap refs/tags/old-tip && git rev-list --test-bitmap refs/tags/new-tip@@ -66,244 +75,294 @@ bitmap_reuse_tests() { ' } -bitmap_reuse_tests 'pack' 'MIDX' -bitmap_reuse_tests 'MIDX' 'pack' -bitmap_reuse_tests 'MIDX' 'MIDX' +test_midx_bitmap_cases () { + writeLookupTable=false + writeBitmapLookupTable= + + for i in "$@" + do + case $i in + "pack.writeBitmapLookupTable") + writeLookupTable=true + writeBitmapLookupTable="$i" + ;; + esac + done + + test_expect_success 'setup test_repository' ' + rm -rf * .git && + git init && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' + ' -test_expect_success 'missing object closure fails gracefully' ' - rm -fr repo && - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && + midx_bitmap_core - test_commit loose && - test_commit packed && + bitmap_reuse_tests 'pack' 'MIDX' "$writeBitmapLookupTable" + bitmap_reuse_tests 'MIDX' 'pack' "$writeBitmapLookupTable" + bitmap_reuse_tests 'MIDX' 'MIDX' "$writeBitmapLookupTable" - # Do not pass "--revs"; we want a pack without the "loose" - # commit. - git pack-objects $objdir/pack/pack <<-EOF && - $(git rev-parse packed) - EOF + test_expect_success 'missing object closure fails gracefully' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && - test_must_fail git multi-pack-index write --bitmap 2>err && - grep "doesn.t have full closure" err && - test_path_is_missing $midx - ) -' + test_commit loose && + test_commit packed && -midx_bitmap_partial_tests + # Do not pass "--revs"; we want a pack without the "loose" + # commit. + git pack-objects $objdir/pack/pack <<-EOF && + $(git rev-parse packed) + EOF -test_expect_success 'removing a MIDX clears stale bitmaps' ' - rm -fr repo && - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && - test_commit base && - git repack && - git multi-pack-index write --bitmap && + test_must_fail git multi-pack-index write --bitmap 2>err && + grep "doesn.t have full closure" err && + test_path_is_missing $midx + ) + ' - # Write a MIDX and bitmap; remove the MIDX but leave the bitmap. - stale_bitmap=$midx-$(midx_checksum $objdir).bitmap && - rm $midx && + midx_bitmap_partial_tests - # Then write a new MIDX. - test_commit new && - git repack && - git multi-pack-index write --bitmap && + test_expect_success 'removing a MIDX clears stale bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + test_commit base && + git repack && + git multi-pack-index write --bitmap && + + # Write a MIDX and bitmap; remove the MIDX but leave the bitmap. + stale_bitmap=$midx-$(midx_checksum $objdir).bitmap && + rm $midx && + + # Then write a new MIDX. + test_commit new && + git repack && + git multi-pack-index write --bitmap && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_missing $stale_bitmap + ) + ' - test_path_is_file $midx && - test_path_is_file $midx-$(midx_checksum $objdir).bitmap && - test_path_is_missing $stale_bitmap - ) -' + test_expect_success 'pack.preferBitmapTips' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && -test_expect_success 'pack.preferBitmapTips' ' - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && + test_commit_bulk --message="%s" 103 && - test_commit_bulk --message="%s" 103 && + git log --format="%H" >commits.raw && + sort <commits.raw >commits && - git log --format="%H" >commits.raw && - sort <commits.raw >commits && + git log --format="create refs/tags/%s %H" HEAD >refs && + git update-ref --stdin <refs && - git log --format="create refs/tags/%s %H" HEAD >refs && - git update-ref --stdin <refs && + git multi-pack-index write --bitmap && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && - git multi-pack-index write --bitmap && - test_path_is_file $midx && - test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >before && + test_line_count = 1 before && - test-tool bitmap list-commits | sort >bitmaps && - comm -13 bitmaps commits >before && - test_line_count = 1 before && + perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \ + <before | git update-ref --stdin && - perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \ - <before | git update-ref --stdin && + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx && - rm -fr $midx-$(midx_checksum $objdir).bitmap && - rm -fr $midx && + git -c pack.preferBitmapTips=refs/tags/include \ + multi-pack-index write --bitmap && + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >after && - git -c pack.preferBitmapTips=refs/tags/include \ - multi-pack-index write --bitmap && - test-tool bitmap list-commits | sort >bitmaps && - comm -13 bitmaps commits >after && + ! test_cmp before after + ) + ' - ! test_cmp before after - ) -' + test_expect_success 'writing a bitmap with --refs-snapshot' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && -test_expect_success 'writing a bitmap with --refs-snapshot' ' - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && + test_commit one && + test_commit two && - test_commit one && - test_commit two && + git rev-parse one >snapshot && - git rev-parse one >snapshot && + git repack -ad && - git repack -ad && + # First, write a MIDX which see both refs/tags/one and + # refs/tags/two (causing both of those commits to receive + # bitmaps). + git multi-pack-index write --bitmap && - # First, write a MIDX which see both refs/tags/one and - # refs/tags/two (causing both of those commits to receive - # bitmaps). - git multi-pack-index write --bitmap && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && - test_path_is_file $midx && - test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test-tool bitmap list-commits | sort >bitmaps && + grep "$(git rev-parse one)" bitmaps && + grep "$(git rev-parse two)" bitmaps && - test-tool bitmap list-commits | sort >bitmaps && - grep "$(git rev-parse one)" bitmaps && - grep "$(git rev-parse two)" bitmaps && + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx && - rm -fr $midx-$(midx_checksum $objdir).bitmap && - rm -fr $midx && + # Then again, but with a refs snapshot which only sees + # refs/tags/one. + git multi-pack-index write --bitmap --refs-snapshot=snapshot && - # Then again, but with a refs snapshot which only sees - # refs/tags/one. - git multi-pack-index write --bitmap --refs-snapshot=snapshot && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && - test_path_is_file $midx && - test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test-tool bitmap list-commits | sort >bitmaps && + grep "$(git rev-parse one)" bitmaps && + ! grep "$(git rev-parse two)" bitmaps + ) + ' - test-tool bitmap list-commits | sort >bitmaps && - grep "$(git rev-parse one)" bitmaps && - ! grep "$(git rev-parse two)" bitmaps - ) -' + test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && -test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' ' - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && + test_commit_bulk --message="%s" 103 && - test_commit_bulk --message="%s" 103 && + git log --format="%H" >commits.raw && + sort <commits.raw >commits && - git log --format="%H" >commits.raw && - sort <commits.raw >commits && + git log --format="create refs/tags/%s %H" HEAD >refs && + git update-ref --stdin <refs && - git log --format="create refs/tags/%s %H" HEAD >refs && - git update-ref --stdin <refs && + git multi-pack-index write --bitmap && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && - git multi-pack-index write --bitmap && - test_path_is_file $midx && - test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >before && + test_line_count = 1 before && - test-tool bitmap list-commits | sort >bitmaps && - comm -13 bitmaps commits >before && - test_line_count = 1 before && + ( + grep -vf before commits.raw && + # mark missing commits as preferred + sed "s/^/+/" before + ) >snapshot && + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx && + + git multi-pack-index write --bitmap --refs-snapshot=snapshot && + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >after && + + ! test_cmp before after + ) + ' + + test_expect_success 'hash-cache values are propagated from pack bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && ( - grep -vf before commits.raw && - # mark missing commits as preferred - sed "s/^/+/" before - ) >snapshot && + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && - rm -fr $midx-$(midx_checksum $objdir).bitmap && - rm -fr $midx && + test_commit base && + test_commit base2 && + git repack -adb && - git multi-pack-index write --bitmap --refs-snapshot=snapshot && - test-tool bitmap list-commits | sort >bitmaps && - comm -13 bitmaps commits >after && + test-tool bitmap dump-hashes >pack.raw && + test_file_not_empty pack.raw && + sort pack.raw >pack.hashes && - ! test_cmp before after - ) -' + test_commit new && + git repack && + git multi-pack-index write --bitmap && -test_expect_success 'hash-cache values are propagated from pack bitmaps' ' - rm -fr repo && - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && + test-tool bitmap dump-hashes >midx.raw && + sort midx.raw >midx.hashes && - test_commit base && - test_commit base2 && - git repack -adb && + # ensure that every namehash in the pack bitmap can be found in + # the midx bitmap (i.e., that there are no oid-namehash pairs + # unique to the pack bitmap). + comm -23 pack.hashes midx.hashes >dropped.hashes && + test_must_be_empty dropped.hashes + ) + ' - test-tool bitmap dump-hashes >pack.raw && - test_file_not_empty pack.raw && - sort pack.raw >pack.hashes && + test_expect_success 'no .bitmap is written without any objects' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && - test_commit new && - git repack && - git multi-pack-index write --bitmap && + empty="$(git pack-objects $objdir/pack/pack </dev/null)" && + cat >packs <<-EOF && + pack-$empty.idx + EOF - test-tool bitmap dump-hashes >midx.raw && - sort midx.raw >midx.hashes && + git multi-pack-index write --bitmap --stdin-packs \ + <packs 2>err && - # ensure that every namehash in the pack bitmap can be found in - # the midx bitmap (i.e., that there are no oid-namehash pairs - # unique to the pack bitmap). - comm -23 pack.hashes midx.hashes >dropped.hashes && - test_must_be_empty dropped.hashes - ) -' + grep "bitmap without any objects" err && -test_expect_success 'no .bitmap is written without any objects' ' - rm -fr repo && - git init repo && - test_when_finished "rm -fr repo" && - ( - cd repo && + test_path_is_file $midx && + test_path_is_missing $midx-$(midx_checksum $objdir).bitmap + ) + ' + + test_expect_success 'graceful fallback when missing reverse index' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && - empty="$(git pack-objects $objdir/pack/pack </dev/null)" && - cat >packs <<-EOF && - pack-$empty.idx - EOF + test_commit base && - git multi-pack-index write --bitmap --stdin-packs \ - <packs 2>err && + # write a pack and MIDX bitmap containing base + git repack -adb && + git multi-pack-index write --bitmap && - grep "bitmap without any objects" err && + GIT_TEST_MIDX_READ_RIDX=0 \ + git rev-list --use-bitmap-index HEAD 2>err && + ! grep "ignoring extra bitmap file" err + ) + ' +} - test_path_is_file $midx && - test_path_is_missing $midx-$(midx_checksum $objdir).bitmap - ) -' +test_midx_bitmap_cases + +test_midx_bitmap_cases "pack.writeBitmapLookupTable" -test_expect_success 'graceful fallback when missing reverse index' ' +test_expect_success 'multi-pack-index write writes lookup table if enabled' ' rm -fr repo && git init repo && test_when_finished "rm -fr repo" && ( cd repo && - test_commit base && - - # write a pack and MIDX bitmap containing base - git repack -adb && - git multi-pack-index write --bitmap && - - GIT_TEST_MIDX_READ_RIDX=0 \ - git rev-list --use-bitmap-index HEAD 2>err && - ! grep "ignoring extra bitmap file" err + git config pack.writeBitmapLookupTable true && + git repack -ad && + GIT_TRACE2_EVENT="$(pwd)/trace" \ + git multi-pack-index write --bitmap && + grep "\"label\":\"writing_lookup_table\"" trace ) 't/t5327-multi-pack-bitmaps-rev.sh +22
-3@@ -17,7 +17,27 @@ GIT_TEST_MIDX_READ_RIDX=0 export GIT_TEST_MIDX_WRITE_REV export GIT_TEST_MIDX_READ_RIDX -midx_bitmap_core rev -midx_bitmap_partial_tests rev +test_midx_bitmap_rev () { + writeLookupTable=false + + for i in "$@" + do + case $i in + "pack.writeBitmapLookupTable") writeLookupTable=true;; + esac + done + + test_expect_success 'setup bitmap config' ' + rm -rf * .git && + git init && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' + ' + + midx_bitmap_core rev + midx_bitmap_partial_tests rev + } + + test_midx_bitmap_rev + test_midx_bitmap_rev "pack.writeBitmapLookupTable" test_done --gitgitgadget
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 3 lines · Johannes Schindelin
That's quite a large a change, and unfortunately I pinpointed a flake to this patch when running with GIT_TEST_DEFAULT_HASH=sha256. The symptom is this:
Hi Dscho, sorry for this long delay in response. I was quite busy for 3-4 days in hostel room shifting. So, I couldn't work properly during this time.
Quoted 44 lines
-- snip --
[...]
+ diff -u expect.normalized actual.normalized
+ rm -f expect.normalized actual.normalized
ok 317 - enumerate --objects (full bitmap, other)expecting success of 5326.318 'bitmap --objects handles non-commit objects (full bitmap, other)':
git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && grep $blob actual+ git rev-list --objects --use-bitmap-index other tagged-blob
+ grepbff4ed5e839bd73e821f78b45a7fa34208aa85596535ec8e9ac5eab477ca6f81actualbff4ed5e839bd73e821f78b45a7fa34208aa85596535ec8e9ac5eab477ca6f81ok 318 - bitmap --objects handles non-commit objects (full bitmap, other)expecting success of 5326.319 'clone from bitmapped repository':
rm -fr clone.git && git clone --no-local --bare . clone.git && git rev-parse HEAD >expect && git --git-dir=clone.git rev-parse HEAD >actual && test_cmp expect actual+ rm -fr clone.git
+ git clone --no-local --bare . clone.git
Cloning into bare repository 'clone.git'...
remote: Enumerating objects: 756, done.
remote: Counting objects: 100% (754/754), done.
remote: Compressing objects: 100% (281/281), done.
remote: Total 756 (delta 245), reused 740 (delta 234), pack-reused 2
Receiving objects: 100% (756/756), 77.50 KiB | 8.61 MiB/s, done.
fatal:REF_DELTAat offset 221 already resolved (duplicate base4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cf?)
fatal: fetch-pack: invalid index-pack output
error: last command exited with $?=128
not ok 319 - clone from bitmapped repository
## rm -fr clone.git && # git clone --no-local --bare . clone.git && # git rev-parse HEAD >expect && # git --git-dir=clone.git rev-parse HEAD >actual && # test_cmp expect actual#
1..319
-- snap --
Quoted 6 lines
On a hunch, I ran this through valgrind (took a while) but it did not point out the problem.
Again, this is only with SHA-256 (and somewhat flaky), it passes every time with SHA-1. Maybe you can reproduce on your side with that information?
Yeah, I can reproduce it on my side. But I am sure it is not related to the lookup table implementation code. Because when I swap the order of calling test_midx_bitmap_cases "pack.writeBitmapLookupTable" and test_midx_bitmap_cases (in t5326-multi-pack-bitmaps.sh), in that case, the error is being generated in test_midx_bitmap_cases call. Generally speaking, the error is always being generated in the second call.
For now, my understanding says that there is something fishy in the test script. I am still not able to figure out the problem here. But let me further investigate.
If anyone has some idea about what could be the culprit, I will be very happy to know.
Thanks :)
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 54 lines · Abhradeep Chakraborty
Quoted 3 lines · Johannes Schindelin
That's quite a large a change, and unfortunately I pinpointed a flake to this patch when running with GIT_TEST_DEFAULT_HASH=sha256. The symptom is this:
Hi Dscho, sorry for this long delay in response. I was quite busy for 3-4 days in hostel room shifting. So, I couldn't work properly during this time.
Quoted 44 lines
-- snip --
[...]
+ diff -u expect.normalized actual.normalized
+ rm -f expect.normalized actual.normalized
ok 317 - enumerate --objects (full bitmap, other)expecting success of 5326.318 'bitmap --objects handles non-commit objects (full bitmap, other)':
git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && grep $blob actual+ git rev-list --objects --use-bitmap-index other tagged-blob
+ grepbff4ed5e839bd73e821f78b45a7fa34208aa85596535ec8e9ac5eab477ca6f81actualbff4ed5e839bd73e821f78b45a7fa34208aa85596535ec8e9ac5eab477ca6f81ok 318 - bitmap --objects handles non-commit objects (full bitmap, other)expecting success of 5326.319 'clone from bitmapped repository':
rm -fr clone.git && git clone --no-local --bare . clone.git && git rev-parse HEAD >expect && git --git-dir=clone.git rev-parse HEAD >actual && test_cmp expect actual+ rm -fr clone.git
+ git clone --no-local --bare . clone.git
Cloning into bare repository 'clone.git'...
remote: Enumerating objects: 756, done.
remote: Counting objects: 100% (754/754), done.
remote: Compressing objects: 100% (281/281), done.
remote: Total 756 (delta 245), reused 740 (delta 234), pack-reused 2
Receiving objects: 100% (756/756), 77.50 KiB | 8.61 MiB/s, done.
fatal:REF_DELTAat offset 221 already resolved (duplicate base4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cf?)
fatal: fetch-pack: invalid index-pack output
error: last command exited with $?=128
not ok 319 - clone from bitmapped repository
## rm -fr clone.git && # git clone --no-local --bare . clone.git && # git rev-parse HEAD >expect && # git --git-dir=clone.git rev-parse HEAD >actual && # test_cmp expect actual#
1..319
-- snap --
Quoted 8 lines
Quoted 6 lines
On a hunch, I ran this through valgrind (took a while) but it did not point out the problem.
Again, this is only with SHA-256 (and somewhat flaky), it passes every time with SHA-1. Maybe you can reproduce on your side with that information?
Yeah, I can reproduce it on my side.
Good.
Quoted 6 lines
But I am sure it is not related to the lookup table implementation code. Because when I swap the order of calling
test_midx_bitmap_cases "pack.writeBitmapLookupTable"andtest_midx_bitmap_cases(int5326-multi-pack-bitmaps.sh), in that case, the error is being generated intest_midx_bitmap_casescall. Generally speaking, the error is always being generated in the second call.
Indeed, it probably has something to do with the test tick (which gives rise to the author/committer date of the commits that are generated, and hence with the SHA order of said commits).
With this patch:
-- snip --
t/t5326-multi-pack-bitmaps.sh +5 -1
@@ -347,7 +347,11 @@ test_midx_bitmap_cases () { ' } -test_midx_bitmap_cases +# test_midx_bitmap_cases + +GIT_COMMITTER_DATE='1112928553 -0700' +GIT_AUTHOR_DATE='1112928553 -0700' +test_tick='1112928553' test_midx_bitmap_cases "pack.writeBitmapLookupTable"
-- snap --
I can reproduce it quicker via
GIT_TEST_DEFAULT_HASH=sha256 sh t5326-*.sh --run=1,71,91,92,93,124,145
Without setting those variables, I cannot skip the first test_midx_bitmap_cases invocation _and_ reproduce the failure.
For shiggles, I now also ran this command-line after deleting the "pack.writeBitmapLookupTable" argument, and it fails in the exact same way. So you're correct: this has nothing to do with the writeBitmapLookupTable code, it's just a failure that is triggered by those patches.
Quoted 2 lines
For now, my understanding says that there is something fishy in the test script.
I do not actually think so. I believe that this just points out a bug in the MIDX bitmap code.
Quoted 5 lines
I am still not able to figure out the problem here. But let me further investigate.
If anyone has some idea about what could be the culprit, I will be very happy to know.
So I noticed that the test will pass every 4th to 5th time over here, which means that it is a racy condition that is the culprit.
I dug a bit deeper and reduced the reproducer even further, by running this command with a trash directory just after above test script invocation failed:
bin-wrappers/git -C t/trash\ directory.t5326-multi-pack-bitmaps/ \ -c pack.threads=1 pack-objects --revs --thin --stdout \ --progress --delta-base-offset </tmp/a5 | bin-wrappers/git -C t/trash\ directory.t5326-multi-pack-bitmaps/ \ -c pack.threads=1 index-pack --stdin -v --fix-thin \ '--keep=fetch-pack 12345 on labtop' \ --check-self-contained-and-connected
where /tmp/a5 contains these lines:
-- snip -- 0ae5a358dcea86d81c0903aaec1e21857688cdb36c7fd89b04bd293fb2cceaa6 67df8a01ac84cf5f028855c48384eac3336bb02a52603bac285c4b31d66b3ab5 098a57f7753320c8a37cf0cb84526a9e50439d9f70fb673c91436a5283a7efe8 --not
-- snap --
This allowed me to instrument the code with _many_ debug printf statements (I actually use error("%s:d: ...", __FILE__, __LINE__, ...) calls) to dive deeper into the weeds.
One relatively obvious difference I can see is that when the code reaches builtin/pack-objects.c:1198, in the passing case after writing the reused pack we're at offset 900 in the written pack file, but in the failing case we're at offset 269.
Another difference I first saw was that the mtime of.git/objects/pack/multi-pack-index was identical to the mtime of .git/objects/pack/multi-pack-index-2ec3c30357d2fff78db9b36cc749b393087e989bffdd278771d6f62089406061.bitmap in the failing case, while the mtimes of the corresponding files were
different in the passing case.
But in another failing run, the mtimes were also non-identical. Meaning:
the race cannot be caused by identical or non-identical timestamps there.
One consistent difference, however, was the SHA-256 in that .bitmap file
name: In the failing case it was always 2ec3c30357d2fff78db9b36cc749b393087e989bffdd278771d6f62089406061, while in the succeeding case it was always 0c275657a915eeff1f2a1c17e5ded43cc3b232b0e178923e44fc15c1970516fb.
My suspicion is that this .bitmap file is written out in an earlier test case, and is already incorrect at that stage. Maybe it should have been updated, but isn't, and the result is an incorrectly-reused partial pack file.
I also noticed that deleting the multi-pack-index-*.bitmap file in the failing case will "fix" the pack-objects | index-pack command I showed above.
Hopefully this will help you dig in further because even if the bug is not in your code, it needs to be fixed. And I suspect that it is a bug in the code we already have in the main branch, so that fix is really, really needed, now.
Since you are very familiar with the details of bitmaps now, I would like to encourage you to work on some kind of validator/inspector, e.g. something along the lines of a test-tool midx-bitmap dump (and later ... verify) that would help future you (and future me) investigate similar breakages. Ideally, that tool will not only parse the .bitmap file but immediately print out everything in a human-readable form.
The reason I suggest this: I got a bit tired of staring at the output of hexdump -C and comparing it to the documentation in
https://git-scm.com/docs/pack-format, so I had to stop after looking too long at one broken pack file (i.e. the output of the pack-objects command I showed above, where already the first entry seems to have an infinite delta chain that pretends that 4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cf has itself as delta base) before I even could analyze the MIDX bitmap files.
The proposed tool would make analyzing MIDX bitmaps substantially more fun, and would also help stave off future breakages if it was taught some verify mode that would essentially automate what right now has to be done manually: to verify that the MIDX bitmap file contents are sound and consistent with the contents of the pack files.
Obviously, this verify command should be called in strategic places of t5326.
Thanks,
Dscho
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 33 lines · Johannes Schindelin
Quoted 6 lines
But I am sure it is not related to the lookup table implementation code. Because when I swap the order of calling
test_midx_bitmap_cases "pack.writeBitmapLookupTable"andtest_midx_bitmap_cases(int5326-multi-pack-bitmaps.sh), in that case, the error is being generated intest_midx_bitmap_casescall. Generally speaking, the error is always being generated in the second call.Indeed, it probably has something to do with the test tick (which gives rise to the author/committer date of the commits that are generated, and hence with the SHA order of said commits).
With this patch:
-- snip --
t/t5326-multi-pack-bitmaps.sh +5
-2@@ -347,7 +347,11 @@ test_midx_bitmap_cases () { ' } -test_midx_bitmap_cases +# test_midx_bitmap_cases + +GIT_COMMITTER_DATE='1112928553 -0700' +GIT_AUTHOR_DATE='1112928553 -0700' +test_tick='1112928553' test_midx_bitmap_cases "pack.writeBitmapLookupTable" -- snap --
Quoted 6 lines
I can reproduce it quicker via
GIT_TEST_DEFAULT_HASH=sha256 sh t5326-*.sh --run=1,71,91,92,93,124,145Without setting those variables, I cannot skip the first
test_midx_bitmap_casesinvocation _and_ reproduce the failure.
Yeah, this works for me also.
Quoted 8 lines
Quoted 5 lines
I am still not able to figure out the problem here. But let me further investigate.
If anyone has some idea about what could be the culprit, I will be very happy to know.
So I noticed that the test will pass every 4th to 5th time over here, which means that it is a racy condition that is the culprit.
I also encountered the same and it blew my mind at first (because it is the first race condition that I faced in my life) :)
Quoted 45 lines
I dug a bit deeper and reduced the reproducer even further, by running this command with a trash directory just after above test script invocation failed:
bin-wrappers/git -C t/trash\ directory.t5326-multi-pack-bitmaps/ \ -c pack.threads=1 pack-objects --revs --thin --stdout \ --progress --delta-base-offset </tmp/a5 | bin-wrappers/git -C t/trash\ directory.t5326-multi-pack-bitmaps/ \ -c pack.threads=1 index-pack --stdin -v --fix-thin \ '--keep=fetch-pack 12345 on labtop' \ --check-self-contained-and-connectedwhere
/tmp/a5contains these lines:-- snip --
0ae5a358dcea86d81c0903aaec1e21857688cdb36c7fd89b04bd293fb2cceaa667df8a01ac84cf5f028855c48384eac3336bb02a52603bac285c4b31d66b3ab5098a57f7753320c8a37cf0cb84526a9e50439d9f70fb673c91436a5283a7efe8--not
-- snap --This allowed me to instrument the code with _many_ debug printf statements (I actually use
error("%s:d: ...", __FILE__, __LINE__, ...)calls) to dive deeper into the weeds.One relatively obvious difference I can see is that when the code reaches
builtin/pack-objects.c:1198, in the passing case after writing the reused pack we're at offset 900 in the written pack file, but in the failing case we're at offset 269.Another difference I first saw was that the mtime of
.git/objects/pack/multi-pack-indexwas identical to the mtime of.git/objects/pack/multi-pack-index-2ec3c30357d2fff78db9b36cc749b393087e989bffdd278771d6f62089406061.bitmapin the failing case, while the mtimes of the corresponding files were
different in the passing case.But in another failing run, the mtimes were also non-identical. Meaning:
the race cannot be caused by identical or non-identical timestamps there.One consistent difference, however, was the SHA-256 in that
.bitmapfile
name: In the failing case it was always2ec3c30357d2fff78db9b36cc749b393087e989bffdd278771d6f62089406061, while in the succeeding case it was always0c275657a915eeff1f2a1c17e5ded43cc3b232b0e178923e44fc15c1970516fb.
Quoted 4 lines
My suspicion is that this
.bitmapfile is written out in an earlier test case, and is already incorrect at that stage. Maybe it should have been updated, but isn't, and the result is an incorrectly-reused partial pack file.
I agree with you.
Quoted 8 lines
I also noticed that deleting the
multi-pack-index-*.bitmapfile in the failing case will "fix" thepack-objects | index-packcommand I showed above.Hopefully this will help you dig in further because even if the bug is not in your code, it needs to be fixed. And I suspect that it is a bug in the code we already have in the main branch, so that fix is really, really needed, now.
Yeah, definitely! Thanks for all the information! It will truly help me to identify the problem.
Quoted 16 lines
Since you are very familiar with the details of bitmaps now, I would like to encourage you to work on some kind of validator/inspector, e.g. something along the lines of a
test-tool midx-bitmap dump(and later... verify) that would help future you (and future me) investigate similar breakages. Ideally, that tool will not only parse the.bitmapfile but immediately print out everything in a human-readable form.The reason I suggest this: I got a bit tired of staring at the output of
hexdump -Cand comparing it to the documentation in
https://git-scm.com/docs/pack-format, so I had to stop after looking too long at one broken pack file (i.e. the output of thepack-objectscommand I showed above, where already the first entry seems to have an infinite delta chain that pretends that4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cfhas itself as delta base) before I even could analyze the MIDX bitmap files.
Quoted 8 lines
The proposed tool would make analyzing MIDX bitmaps substantially more fun, and would also help stave off future breakages if it was taught some
verifymode that would essentially automate what right now has to be done manually: to verify that the MIDX bitmap file contents are sound and consistent with the contents of the pack files.Obviously, this
verifycommand should be called in strategic places of t5326.
Ok, sure!
Thanks :)
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 10 lines · Abhradeep Chakraborty
Quoted 7 lines · Johannes Schindelin
Since you are very familiar with the details of bitmaps now, I would like to encourage you to work on some kind of validator/inspector, e.g. something along the lines of a
test-tool midx-bitmap dump(and later... verify) that would help future you (and future me) investigate similar breakages. Ideally, that tool will not only parse the.bitmapfile but immediately print out everything in a human-readable form.
Have you made progress on this? I am interested mostly because I am trying very hard to maintain passing CI runs of Git for Windows' shears/seen branch (which essentially tries to rebase all of Git for Windows' patches on top of seen), and this failure is consistently causing said CI runs to fail for a while already.
Ciao,
Dscho
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 16 lines · Johannes Schindelin
Hi Abhradeep,
Quoted 10 lines · Abhradeep Chakraborty
Quoted 7 lines · Johannes Schindelin
Since you are very familiar with the details of bitmaps now, I would like to encourage you to work on some kind of validator/inspector, e.g. something along the lines of a
test-tool midx-bitmap dump(and later... verify) that would help future you (and future me) investigate similar breakages. Ideally, that tool will not only parse the.bitmapfile but immediately print out everything in a human-readable form.
Quoted 5 lines
Have you made progress on this? I am interested mostly because I am trying very hard to maintain passing CI runs of Git for Windows'
shears/seenbranch (which essentially tries to rebase all of Git for Windows' patches on top ofseen), and this failure is consistently causing said CI runs to fail for a while already.
Hey Dscho, I am trying hard to solve the issue but unfortunately I haven't found the key yet.
I investigated the bitmap code-base and used debug lines but didn't find a way to fix it. Sorry for that :|
I am still trying it.
Hope I will be able to share the good news soon. Thanks :)
Quoted 2 lines
Ciao,
Dscho
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 16 lines · Abhradeep Chakraborty
Quoted 14 lines · Johannes Schindelin
Quoted 10 lines · Abhradeep Chakraborty
Quoted 7 lines · Johannes Schindelin
Since you are very familiar with the details of bitmaps now, I would like to encourage you to work on some kind of validator/inspector, e.g. something along the lines of a
test-tool midx-bitmap dump(and later... verify) that would help future you (and future me) investigate similar breakages. Ideally, that tool will not only parse the.bitmapfile but immediately print out everything in a human-readable form.
Quoted 8 lines
Quoted 5 lines
Have you made progress on this? I am interested mostly because I am trying very hard to maintain passing CI runs of Git for Windows'
shears/seenbranch (which essentially tries to rebase all of Git for Windows' patches on top ofseen), and this failure is consistently causing said CI runs to fail for a while already.Hey Dscho, I am trying hard to solve the issue but unfortunately I haven't found the key yet.
The tool I proposed could potentially help, in particular with distributing the burden of the investigation on more shoulders than just yours.
Quoted 2 lines
I investigated the bitmap code-base and used debug lines but didn't find a way to fix it.
Have you investigated whether the .bitmap file was produced for the latest set of pack files? It should be relatively quick to investigate that, and if it turns out not to be the case, the fix should be quick, too.
Thanks,
Dscho
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 27 lines · Johannes Schindelin
Hi Abhradeep,
Quoted 22 lines · Abhradeep Chakraborty
Quoted 19 lines · Johannes Schindelin
Quoted 10 lines · Abhradeep Chakraborty
Quoted 7 lines · Johannes Schindelin
Since you are very familiar with the details of bitmaps now, I would like to encourage you to work on some kind of validator/inspector, e.g. something along the lines of a
test-tool midx-bitmap dump(and later... verify) that would help future you (and future me) investigate similar breakages. Ideally, that tool will not only parse the.bitmapfile but immediately print out everything in a human-readable form.Have you made progress on this? I am interested mostly because I am trying very hard to maintain passing CI runs of Git for Windows'
shears/seenbranch (which essentially tries to rebase all of Git for Windows' patches on top ofseen), and this failure is consistently causing said CI runs to fail for a while already.
Quoted 6 lines
Quoted 2 lines
Hey Dscho, I am trying hard to solve the issue but unfortunately I haven't found the key yet.
The tool I proposed could potentially help, in particular with distributing the burden of the investigation on more shoulders than just yours.
Yeah, it should. I thought that I would do that after fixing the bug. Now I think I was wrong.
Quoted 7 lines
Quoted 2 lines
I investigated the bitmap code-base and used debug lines but didn't find a way to fix it.
Have you investigated whether the
.bitmapfile was produced for the latest set of pack files? It should be relatively quick to investigate that, and if it turns out not to be the case, the fix should be quick, too.
Frankly speaking, I doubt that the generated multi-pack-index file is faulty. The first reason is the .bitmap filename. As you said before (and as I noticed here), .bitmap filenames in failing case and in passing case are different. As far as I know the hash value in the filename depends on the content of its respective midx file. So, if the midx contents were the same in both cases, .bitmap filename should not differ.
I compared both the multi-pack-index files (i.e. passing case and failing case) using `cmp ./trash\
directory.t5326-multi-pack-bitmaps/.git/objects/pack/multi-pack-index ../tmp/trash\ directory.t5326-multi-pack-bitmaps/.git/objects/pack/multi-pack-index` and found that these both defers -
differ: char 3124, line 10
I also checked whether the packing_data->in_pack_by_idx contained all the packs. For this I wrote a debug error message in prepare_in_pack_by_idx()[1] function and found that packing_data is using the latest packs.
I noticed in the 'setup partial bitmaps' test case that if we comment
out the line git repack && , it runs successfully.
test_expect_success 'setup partial bitmaps' '
test_commit packed &&
# git repack &&
test_commit loose &&
git multi-pack-index write --bitmap 2>err &&
...
'Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 4 lines · Abhradeep Chakraborty
I also checked whether the
packing_data->in_pack_by_idxcontained all the packs. For this I wrote a debug error message inprepare_in_pack_by_idx()[1]function and found thatpacking_datais using the latest packs.
Looks like I forgot to specify the link -
https://github.com/git/git/blob/c50926e1f48891e2671e1830dbcd2912a4563450/pack-objects.c#L87
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
In reply to Abhradeep ChakrabortyHi Abhradeep,
Quoted 10 lines · Abhradeep Chakraborty
I noticed in the 'setup partial bitmaps' test case that if we comment
out the linegit repack &&, it runs successfully.test_expect_success 'setup partial bitmaps' ' test_commit packed && # git repack && test_commit loose && git multi-pack-index write --bitmap 2>err && ... '
That's interesting. Are the .bitmap and .midx files updated as part of that repack?
Ciao,
Dscho
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 13 lines · Johannes Schindelin
Quoted 10 lines · Abhradeep Chakraborty
I noticed in the 'setup partial bitmaps' test case that if we comment
out the linegit repack &&, it runs successfully.test_expect_success 'setup partial bitmaps' ' test_commit packed && # git repack && test_commit loose && git multi-pack-index write --bitmap 2>err && ... '
Quoted 2 lines
That's interesting. Are the
.bitmapand.midxfiles updated as part of thatrepack?
I instrumented this, and saw that the multi-pack-index and multi-pack-index*.bitmap files were unchanged by the git repack invocation.
Re-generating the MIDX bitmap forcefully after the repack seems to fix things over here:
-- snip --
t/lib-bitmap.sh +3 -0
@@ -438,7 +438,10 @@ midx_bitmap_partial_tests () { test_expect_success 'setup partial bitmaps' ' test_commit packed && +ls -l .git/objects/pack/ && git repack && +git multi-pack-index write --bitmap && +ls -l .git/objects/pack/ && test_commit loose && git multi-pack-index write --bitmap 2>err && test_path_is_file $midx &&
-- snap --
This suggests to me that the multi-pack-index write --bitmap 2>err call in this hunk might reuse a stale MIDX bitmap, and that _that_ might be the root cause of this breakage.
What do you think?
Ciao,
Dscho
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 5 lines · Johannes Schindelin
Hi Abhradeep,
I instrumented this, and saw that themulti-pack-indexandmulti-pack-index*.bitmapfiles were unchanged by thegit repackinvocation.
Yeah, those two files remain unchanged here.
Quoted 21 lines
Re-generating the MIDX bitmap forcefully after the repack seems to fix things over here:
-- snip --
t/lib-bitmap.sh +3
-1@@ -438,7 +438,10 @@ midx_bitmap_partial_tests () { test_expect_success 'setup partial bitmaps' ' test_commit packed && +ls -l .git/objects/pack/ && git repack && +git multi-pack-index write --bitmap && +ls -l .git/objects/pack/ && test_commit loose && git multi-pack-index write --bitmap 2>err && test_path_is_file $midx && -- snap --
Quoted 3 lines
This suggests to me that the
multi-pack-index write --bitmap 2>errcall in this hunk might reuse a stale MIDX bitmap, and that _that_ might be the root cause of this breakage.
Yeah, the multi-pack-index write --bitmap 2>err is creating the problem. More specifically the multi-pack-index write part. As you can see in my previous comment (if you get the comment), I shared a screenshot there which pointed out that the multi-pack-index files in both cases are different. The portion from which it started to differ belongs to the RIDX chunk.
So, I used some debug lines in midx_pack_order() function[1] and found that the objects are sorted differently in those cases (i.e. passing case and failing case). For passing case, the RIDX chunk contents are like below -
pack_order = [ 1, 36, 11, 6, 18, 3, 19, 12, 5, 31, 27, 23, 29, 8, 38, 22, 9, 15, 14, 24, 37, 28, 7, 39, 10, 34, 26, 4, 30, 33, 2, 35, 17, 32, 0, 21, 16, 25, 13, 40, 20,]
And in the failing case, this is -
pack_order = [ 12, 18, 3, 19, 1, 36, 11, 6, 5, 31, 27, 23, 29, 8, 38, 22, 9, 15, 14, 24, 37, 28, 7, 39, 10, 34, 26, 4, 30, 33, 2, 35, 17, 32, 0, 21, 16, 25, 13, 40, 20,]
I went further and realized that this is due to the line[2] -
if (!e->preferred)
data[i].pack |= (1U << 31);I.e. 4- 5 pack_midx_entry objects have different preferred values in those cases. For example, "46193a971f5045cb3ca6022957541f9ccddfbfe78591d8506e2d952f8113059b" (with pack order 12) is preferred in failing case (that's why it is in the first position) and the same is not preferred in the passing case.
It may be because of reusing a stale midx bitmap (as you said). But I am not sure. Just to ensure myself, I compared all the other packfiles, idx files and a pack .bitmap file (which you can see using ls command) of failing and passing cases and found that they are the same.
Thanks :)
[1] https://github.com/git/git/blob/c50926e1f48891e2671e1830dbcd2912a4563450/midx.c#L861
[2] https://github.com/git/git/blob/c50926e1f48891e2671e1830dbcd2912a4563450/midx.c#L872
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 69 lines · Abhradeep Chakraborty
Quoted 5 lines · Johannes Schindelin
Hi Abhradeep,
I instrumented this, and saw that themulti-pack-indexandmulti-pack-index*.bitmapfiles were unchanged by thegit repackinvocation.Yeah, those two files remain unchanged here.
Quoted 21 lines
Re-generating the MIDX bitmap forcefully after the repack seems to fix things over here:
-- snip --
t/lib-bitmap.sh +3
-1@@ -438,7 +438,10 @@ midx_bitmap_partial_tests () { test_expect_success 'setup partial bitmaps' ' test_commit packed && +ls -l .git/objects/pack/ && git repack && +git multi-pack-index write --bitmap && +ls -l .git/objects/pack/ && test_commit loose && git multi-pack-index write --bitmap 2>err && test_path_is_file $midx && -- snap --Quoted 3 lines
This suggests to me that the
multi-pack-index write --bitmap 2>errcall in this hunk might reuse a stale MIDX bitmap, and that _that_ might be the root cause of this breakage.Yeah, the
multi-pack-index write --bitmap 2>erris creating the problem. More specifically themulti-pack-index writepart. As you can see in my previous comment (if you get the comment), I shared a screenshot there which pointed out that the multi-pack-index files in both cases are different. The portion from which it started to differ belongs to theRIDXchunk.So, I used some debug lines in
midx_pack_order()function[1] and found that the objects are sorted differently in those cases (i.e. passing case and failing case). For passing case, the RIDX chunk contents are like below -
pack_order= [ 1, 36, 11, 6, 18, 3, 19, 12, 5, 31, 27, 23, 29, 8, 38, 22, 9, 15, 14, 24, 37, 28, 7, 39, 10, 34, 26, 4, 30, 33, 2, 35, 17, 32, 0, 21, 16, 25, 13, 40, 20,]And in the failing case, this is -
pack_order= [ 12, 18, 3, 19, 1, 36, 11, 6, 5, 31, 27, 23, 29, 8, 38, 22, 9, 15, 14, 24, 37, 28, 7, 39, 10, 34, 26, 4, 30, 33, 2, 35, 17, 32, 0, 21, 16, 25, 13, 40, 20,]I went further and realized that this is due to the line[2] -
if (!e->preferred) data[i].pack |= (1U << 31);I.e. 4- 5
pack_midx_entryobjects have differentpreferredvalues in those cases. For example, "46193a971f5045cb3ca6022957541f9ccddfbfe78591d8506e2d952f8113059b" (with pack order 12) ispreferredin failing case (that's why it is in the first position) and the same isnot preferredin the passing case.
Quoted 5 lines
It may be because of reusing a stale midx bitmap (as you said). But I am not sure. Just to ensure myself, I compared all the other packfiles, idx files and a pack
.bitmapfile (which you can see using ls command) of failing and passing cases and found that they are the same.
You are right that this choice of a 'preferred' pack is part of the root cause for this flake. This choice is not deterministic if the mtime of some pack-files are within the same second.
I can make the flake go away with this change:
t/lib-bitmap.sh +2 -0
@@ -438,7 +438,9 @@ midx_bitmap_partial_tests () { test_expect_success 'setup partial bitmaps' ' test_commit packed && + test_tick && git repack && + test_tick && test_commit loose && git multi-pack-index write --bitmap 2>err && test_path_is_file $midx &&
However, that doesn't help us actually find out what the problem is in our case.
I've tried exploring other considerations, resulting in this diff:
midx.c +2 -1
@@ -921,8 +921,9 @@ static void prepare_midx_packing_data(struct packing_data *pdata,struct pack_midx_entry *from = &ctx->entries[ctx->pack_order[i]];struct object_entry *to =packlist_alloc (pdata, &from->oid); +/* Why does removing the permutation here not change the outcome? */ oe_set_in_pack (pdata, to, - ctx->info[ctx->pack_perm[from->pack_int_id]].p); + ctx->info[from->pack_int_id].p); } }
This method is setting up some important information, supposedly, and in the failing case I see that the ctx->pack_perm performs a 5-cycle ( 0->1, 1->2, 2->3, 3->4, 4->0 ) but this removal does not affect _any existing test cases_!
Turns out that the packfile sent here goes through this very trivial path in oe_set_in_pack() every time we are writing a multi-pack-index:
static inline void oe_set_in_pack(struct packing_data *pack,
struct object_entry *e, struct packed_git *p)
{
if (pack->in_pack_by_idx) {
if (p->index) {
e->in_pack_idx = p->index;
return;
}
/*
* We're accessing packs by index, but this pack doesn't have
* an index (e.g., because it was added since we created the
* in_pack_by_idx array). Bail to oe_map_new_pack(), which
* will convert us to using the full in_pack array, and then
* fall through to our in_pack handling.
*/
oe_map_new_pack(pack);
}
pack->in_pack[e - pack->objects] = p;
}By debugging, I discovered we are hitting the case that calls oe_map_new_pack(pack). The documentation for that method provides the following (**emphasis mine**):
/*
* A new pack appears after prepare_in_pack_by_idx() has been
* run. **This is likely a race.**
*
* We could map this new pack to in_pack_by_idx[] array, but then we
* have to deal with full array anyway. And since it's hard to test
* this fall back code, just stay simple and fall back to using
* in_pack[] array.
*/
void oe_map_new_pack(struct packing_data *pack)
The issue being that prepare_packing_data() uses get_all_packs() to get the list of pack-files, but that list is stale for some reason. Adding a reprepare_packed_git() in advance of that call also removes the flake (with always passing):
midx.c +1 -0
@@ -915,6 +915,7 @@ static void prepare_midx_packing_data(struct packing_data *pdata,uint32_t i;memset (pdata,0 ,sizeof (struct packing_data )); +reprepare_packed_git (the_repository);prepare_packing_data (the_repository, pdata);for (i =0 ; i < ctx->entries_nr; i++) {
But this still appears like it is just a band-aid over a trickier underlying issue.
Hopefully my rambling helps push you in a helpful direction to find a more complete fix.
Thanks,
-Stolee
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hello,
I think I have found the problem. Derrick was right that mtime part is not the culprit. I tried to understand the whole midx workflow and some questions were raised in my mind. I don't know whether those are features or bugs (because I do not have much experience in multi-pack-index code).
I am writing a brief description for the context of the issue and the questions I have.
Let us start from the write_midx_internal() function. As packs_to_include is null in our case, We can use the old midx to write a new midx file. The line ctx.m = lookup_multi_pack_index(the_repository, object_dir)[1] does this. It also loads packs that do not belong to any multi-pack-indexes. It also sets the_repository->objects->packed_git_intialized to 1. If we look at our test case (setup partial bitmap) the last .pack file (generated by git repack && ) does not belong to any midx. So, that pack will be loaded in this step.
[1] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L1169
Next let us move to the if (ctx.m)[2] block. As we will be writing a bitmap, if (flags & MIDX_WRITE_REV_INDEX) is true. Thus all packs related to the old midx are loaded and ctx.info[ctx.nr].p stores the pointers of these packs.
[2] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L1182
After that we come to the for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx); line[3] . The add_pack_to_midx[4] function adds packs (that are not in the old midx) to ctx.info. Now I have a question here - Why are we using the add_packed_git()[5] function provided we already loaded those packs in the lookup_multi_pack_index step (i.e. 1st step)? These packs are not added in r->objects->packed_git. This question is related to our current issue.
I.e. instead of this -
ctx->info[ctx->nr].p = add_packed_git(full_path,
full_path_len, 0);
Why not this (or similar) -
for (cp = the_repository->objects->packed_git; cp; cp = cp->next)
if (!cmp_idx_or_pack_name(cp->pack_name, full_path))
ctx->info[ctx->nr].p = cp;[3] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L1221
[4] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L462
[5] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L492
write_midx_bitmap() function is where bitmap related code starts.
let us directly jump into the prepare_packed_git() function (called by get_all_packs()[6]). As I said previously, r->objects->packed_git_initialized is already enabled so this function becomes a no-op function. Which means it does not load the newly written midx (by calling prepare_multi_pack_index_one function) and uses old midx to write the bitmap (though we still have new packs and they can be used with the old midx to generate the bitmap, maybe?) . Here comes my second question - Is this the desired case? or should we use the new midx to write the bitmaps?
One important point to note is that get_all_packs() returns r->objects->packed_git which now stores pointers of all the packs and only these packfiles have their ->index set.
[6] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/packfile.c#L1043
Now let us move to the last function - oe_set_in_pack() (called by prepare_midx_packing_data()). Note that, we are passing ctx->info[ctx->pack_perm[from->pack_int_id]].p along with other parameters. As I have said in an earlier para (containing my first question), ctx->info has some packs (i.e. newer packs that are not related to the old midx) that are not installed in r->objects->packed_git . In other words, we have two instances of the same pack file - one in r->objects->packed_git list and another in ctx->info[id].p. As prepare_in_pack_by_idx function only sets ->index for r->objects->packed_git packs, these packs (i.e. ctx.info[id].p) do not have their p->index set and thus end up calling the oe_map_new_pack function.
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 8 lines · Abhradeep Chakraborty
I think I have found the problem. Derrick was right that
mtimepart is not the culprit. I tried to understand the whole midx workflow and some questions were raised in my mind. I don't know whether those are features or bugs (because I do not have much experience in multi-pack-index code).I am writing a brief description for the context of the issue and the questions I have.
Thanks for the detailed writeup.
Quoted 44 lines
Let us start from the
write_midx_internal()function. Aspacks_to_includeis null in our case, We can use the old midx to write a new midx file. The linectx.m = lookup_multi_pack_index(the_repository, object_dir)[1] does this. It also loads packs that do not belong to any multi-pack-indexes. It also setsthe_repository->objects->packed_git_intializedto 1. If we look at our test case (setup partial bitmap) the last.packfile (generated bygit repack &&) does not belong to any midx. So, that pack will be loaded in this step.[1] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L1169
Next let us move to the
if (ctx.m)[2] block. As we will be writing a bitmap,if (flags & MIDX_WRITE_REV_INDEX)is true. Thus all packs related to the old midx are loaded andctx.info[ctx.nr].pstores the pointers of these packs.[2] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L1182
After that we come to the
for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);line[3] . Theadd_pack_to_midx[4] function adds packs (that are not in the old midx) toctx.info. Now I have a question here - Why are we using theadd_packed_git()[5] function provided we already loaded those packs in thelookup_multi_pack_indexstep (i.e. 1st step)? These packs are not added inr->objects->packed_git. This question is related to our current issue.I.e. instead of this -
ctx->info[ctx->nr].p = add_packed_git(full_path,
full_path_len, 0);Why not this (or similar) -
for (cp = the_repository->objects->packed_git; cp; cp = cp->next) if (!cmp_idx_or_pack_name(cp->pack_name, full_path)) ctx->info[ctx->nr].p = cp;[3] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L1221
[4] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L462
[5] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/midx.c#L492
Quoted 10 lines
write_midx_bitmap()function is where bitmap related code starts.
let us directly jump into theprepare_packed_git()function (called byget_all_packs()[6]). As I said previously,r->objects->packed_git_initializedis already enabled so this function becomes a no-op function. Which means it does not load the newly written midx (by callingprepare_multi_pack_index_onefunction) and uses old midx to write the bitmap (though we still have new packs and they can be used with the old midx to generate the bitmap, maybe?) . Here comes my second question - Is this the desired case? or should we use the new midx to write the bitmaps?
The confusing part of all this is that the bitmaps are being written while the "new" midx is written only to "multi-pack-index.lock" and has not been renamed to "multi-pack-index". If we renamed first, then the old .bitmap file would not match the new midx and all Git commands would act as if there was no .bitmap file.
Quoted 6 lines
One important point to note is that
get_all_packs()returnsr->objects->packed_gitwhich now stores pointers of all the packs and only these packfiles have their->indexset.[6] https://github.com/git/git/blob/5502f77b6944eda8e26813d8f542cffe7d110aea/packfile.c#L1043
Quoted 12 lines
Now let us move to the last function -
oe_set_in_pack()(called byprepare_midx_packing_data()). Note that, we are passingctx->info[ctx->pack_perm[from->pack_int_id]].palong with other parameters. As I have said in an earlier para (containing my first question),ctx->infohas some packs (i.e. newer packs that are not related to the old midx) that are not installed inr->objects->packed_git. In other words, we have two instances of the same pack file - one inr->objects->packed_gitlist and another inctx->info[id].p. Asprepare_in_pack_by_idxfunction only sets->indexforr->objects->packed_gitpacks, these packs (i.e.ctx.info[id].p) do not have theirp->indexset and thus end up calling theoe_map_new_packfunction.
So really, the problem is that we are handling the r->objects->packed_git list instead of an array of packs that are under the control of the new midx. This assumption is baked deep in the pack-objects flow, so it would be hard to separate this idea.
Perhaps doing the reprepare_packed_git() to regenerate the list would be sufficient as a band-aid for now, but we would want to later do the big dig of focusing the pack_data struct to a specific list of pack-files (by default the set from get_all_packs(), but for midx bitmaps we can supply a specific set of packs).
Thanks,
-Stolee
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 11 lines · Derrick Stolee
So really, the problem is that we are handling the
r->objects->packed_gitlist instead of an array of packs that are under the control of the new midx. This assumption is baked deep in the pack-objects flow, so it would be hard to separate this idea.Perhaps doing the
reprepare_packed_git()to regenerate the list would be sufficient as a band-aid for now, but we would want to later do the big dig of focusing thepack_datastruct to a specific list of pack-files (by default the set fromget_all_packs(), but for midx bitmaps we can supply a specific set of packs).
reprepare_packed_git() can not stop it. Because this function updates r->objects->packed_git list (i.e. it reloads packs that are not in the old midx) and as I said before, we are setting ->index for only r->objects->packed_git not ctx.info[id].p. So, it will call the oe_map_new_pack() function in either way. I have tested it.
One thing that really worries me is what if the failure is not related to calling `oe_map_new_pack()? I did all my work assuming that this function is the culprit. But I don't know if it is.
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 3 lines · Abhradeep Chakraborty
One thing that really worries me is what if the failure is not related to calling `oe_map_new_pack()? I did all my work assuming that this function is the culprit. But I don't know if it is.
After much consternation, I was able to rule out oe_map_new_pack() as the culprit.
(Your find that we call add_packed_git() with arguments corresponding to pack(s) that we've already loaded is good, and I think that is definitely something we can and should consider cleaning up. But it ultimately doesn't affect correctness, just the memory efficiency of the process).
When I took a close look at the process to generate MIDX bitmaps, I found a couple of interesting things. The first more trivial fix is that we incorrectly propagate the "preferred"-ness bit from packs in an existing MIDX when generating a new one. If the identity of the preferred pack changes, we should not drag forward those bits on objects already known (and preferred) by the existing MIDX:
--- >8 ---
midx.c +4 -1
@@ -619,6 +619,9 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,if (m) {uint32_t start =0 , end; +int orig_preferred_pack =-1 ; +if (0 <= preferred_pack && preferred_pack < m->num_packs) + orig_preferred_pack = info[preferred_pack].orig_pack_int_id;if (cur_fanout) start =ntohl (m->chunk_oid_fanout[cur_fanout -1 ]);
@@ -629,7 +632,7 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,nth_midxed_pack_midx_entry (m, &entries_by_fanout[nr_fanout], cur_object); -if (nth_midxed_pack_int_id (m, cur_object) == preferred_pack) +if (nth_midxed_pack_int_id (m, cur_object) == orig_preferred_pack) entries_by_fanout[nr_fanout].preferred =1 ;else entries_by_fanout[nr_fanout].preferred =0 ;
--- 8< ---
But a more interesting problem arose when I took a closer look at the psuedo-pack order of objects generated according to prepare_midx_packing_data(). With Johannes' fixed $test_tick value, I was able to see the following in runs that succeeded:
27bb4ecd3e96cd0b3bc37d92a78cb5cbf34c418afa67f74cc52517ff7df418e1 (12 in pack-63c460f99a5c08f631396b1828c64006170a9d543b064506fd11b504a62acf52.idx)
c68154d69c19f010afce786c6debe926ae6e7decfb946a4549085a792cf9de7e (202 in pack-63c460f99a5c08f631396b1828c64006170a9d543b064506fd11b504a62acf52.idx)
a0b85b314ede46aa9f9b5796a284a4cf0b86ebb8fa32f87ae246e21b5378b11c (392 in pack-63c460f99a5c08f631396b1828c64006170a9d543b064506fd11b504a62acf52.idx)
[...]and the following in runs that failed:
46193a971f5045cb3ca6022957541f9ccddfbfe78591d8506e2d952f8113059b (221 in pack-3fc052de674e3d48096af7cc5125675c0ae1082aa798eb9358de357b2655f9ad.idx)
67df8a01ac84cf5f028855c48384eac3336bb02a52603bac285c4b31d66b3ab5 (12 in pack-2021cdedb33b542b244eacf3d009d1384471a53286b0c1235c91d124355dc818.idx)
1556b5f0ad7cb0c25a1fc47355fcffc00775e90d94ae8c511e5776b204796ce6 (200 in pack-2021cdedb33b542b244eacf3d009d1384471a53286b0c1235c91d124355dc818.idx)In the successful case, pack 63c460f99a... is preferred, and its objects appear in ascending order of their pack offsets. But in the other case, pack 3fc052de67... is preferred, but its first object starts at offset
221. Huh? That's not right:
$ git show-index <.git/objects/pack/pack-3fc052de674e3d48096af7cc5125675c0ae1082aa798eb9358de357b2655f9ad.idx
221 46193a971f5045cb3ca6022957541f9ccddfbfe78591d8506e2d952f8113059b (1f4bd28e)
12 4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cf (fadf885b)Indeed, there is another object there at offset 12. Missing that object (since it comes from a preferred pack) is an invariant violation (since all objects from the preferred pack should be selected when multiple copies are available).
It's missing because the existing MIDX selects that object from a different pack, and when we get to fanout 0x4d (the one which should include that object), we skip over seeing its copy in the preferred pack because that pack already appears in the existing MIDX, though it wasn't preferred.
I think there are a couple of ways to fix this. The easiest thing to do would be to force the identity of the preferred pack to be the same when generating a MIDX bitmap *while reusing an existing MIDX*, since that is the only time this bug can happen.
But that's a little magical for my taste. I think a more reasonable fix would be to include copies of all objects from the preferred pack including in the case where that pack was non-preferred in an existing MIDX and at least one object in that pack was selected from a different pack in the existing MIDX.
Abhradeep -- let me know if this is something you want to look into. I think it's a very worthwhile bug to fix, since it is definitely trigger-able in the wild (notably, only with git multi-pack-index write --bitmap without --stdin-packs and only under certain circumstances), and not just limited to SHA-256 mode.
If you are busy experimenting with CRoaring, that's no problem and I can fix this up, too. Either way, it would be worth you and others weighing in on which fix you think is worth pursuing.
Phew.
Thanks,
Taylor
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hello Taylor, extremely thanks for finding the reason for this failure.
Quoted 27 lines · Taylor Blau
Hi Abhradeep,
When I took a close look at the process to generate MIDX bitmaps, I found a couple of interesting things. The first more trivial fix is that we incorrectly propagate the "preferred"-ness bit from packs in an existing MIDX when generating a new one. If the identity of the preferred pack changes, we should not drag forward those bits on objects already known (and preferred) by the existing MIDX:
--- >8 ---
midx.c +3
-0@@ -619,6 +619,9 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,if (m) {uint32_t start =0 , end; +int orig_preferred_pack =-1 ; +if (0 <= preferred_pack && preferred_pack < m->num_packs) + orig_preferred_pack = info[preferred_pack].orig_pack_int_id;if (cur_fanout) start =ntohl (m->chunk_oid_fanout[cur_fanout -1 ]);
midx.c static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
Quoted 10 lines
midx.c +1
-2@@ -629,7 +632,7 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,nth_midxed_pack_midx_entry (m, &entries_by_fanout[nr_fanout], cur_object); -if (nth_midxed_pack_int_id (m, cur_object) == preferred_pack) +if (nth_midxed_pack_int_id (m, cur_object) == orig_preferred_pack) entries_by_fanout[nr_fanout].preferred =1 ;else entries_by_fanout[nr_fanout].preferred =0 ; --- 8< ---
I am not able to understand this modification. info[preferred_pack].orig_pack_int_id and preferred_pack have the same value, right? I see ctx.info getting sorted only after calling get_sorted_entries() function.
Quoted 30 lines
But a more interesting problem arose when I took a closer look at the psuedo-pack order of objects generated according to
prepare_midx_packing_data(). With Johannes' fixed $test_tick value, I was able to see the following in runs that succeeded:27bb4ecd3e96cd0b3bc37d92a78cb5cbf34c418afa67f74cc52517ff7df418e1 (12 in pack-63c460f99a5c08f631396b1828c64006170a9d543b064506fd11b504a62acf52.idx) c68154d69c19f010afce786c6debe926ae6e7decfb946a4549085a792cf9de7e (202 in pack-63c460f99a5c08f631396b1828c64006170a9d543b064506fd11b504a62acf52.idx) a0b85b314ede46aa9f9b5796a284a4cf0b86ebb8fa32f87ae246e21b5378b11c (392 in pack-63c460f99a5c08f631396b1828c64006170a9d543b064506fd11b504a62acf52.idx) [...]and the following in runs that failed:
46193a971f5045cb3ca6022957541f9ccddfbfe78591d8506e2d952f8113059b (221 in pack-3fc052de674e3d48096af7cc5125675c0ae1082aa798eb9358de357b2655f9ad.idx) 67df8a01ac84cf5f028855c48384eac3336bb02a52603bac285c4b31d66b3ab5 (12 in pack-2021cdedb33b542b244eacf3d009d1384471a53286b0c1235c91d124355dc818.idx) 1556b5f0ad7cb0c25a1fc47355fcffc00775e90d94ae8c511e5776b204796ce6 (200 in pack-2021cdedb33b542b244eacf3d009d1384471a53286b0c1235c91d124355dc818.idx)In the successful case, pack
63c460f99a... is preferred, and its objects appear in ascending order of their pack offsets. But in the other case, pack3fc052de67... is preferred, but its first object starts at offset
221. Huh? That's not right:$ git show-index <.git/objects/pack/pack-3fc052de674e3d48096af7cc5125675c0ae1082aa798eb9358de357b2655f9ad.idx 221 46193a971f5045cb3ca6022957541f9ccddfbfe78591d8506e2d952f8113059b (1f4bd28e) 12 4d332072f161629ffe4652ecd3ce377ef88447bec73f05ab0f3515f98bd061cf (fadf885b)Indeed, there is another object there at offset 12. Missing that object (since it comes from a preferred pack) is an invariant violation (since all objects from the preferred pack should be selected when multiple copies are available).
Quoted 5 lines
It's missing because the existing MIDX selects that object from a different pack, and when we get to fanout
0x4d(the one which should include that object), we skip over seeing its copy in the preferred pack because that pack already appears in the existing MIDX, though it wasn't preferred.
ahh, now I understand what the problem was actually. Thanks :)
Quoted 10 lines
I think there are a couple of ways to fix this. The easiest thing to do would be to force the identity of the preferred pack to be the same when generating a MIDX bitmap *while reusing an existing MIDX*, since that is the only time this bug can happen.
But that's a little magical for my taste. I think a more reasonable fix would be to include copies of all objects from the preferred pack including in the case where that pack was non-preferred in an existing MIDX and at least one object in that pack was selected from a different pack in the existing MIDX.
I think the later approach makes the most sense to me. It might not be a good idea to keep the same pack as preferred as a better candidate would be ignored in that case.
Quoted 9 lines
Abhradeep -- let me know if this is something you want to look into. I think it's a very worthwhile bug to fix, since it is definitely trigger-able in the wild (notably, only with
git multi-pack-index write --bitmapwithout--stdin-packsand only under certain circumstances), and not just limited to SHA-256 mode.If you are busy experimenting with CRoaring, that's no problem and I can fix this up, too. Either way, it would be worth you and others weighing in on which fix you think is worth pursuing.
I will be happy to fix it but I can't work on it right now (neither on CRoaring) because I am currently preparing for my exam. I can continue my work after that (i.e. from 19 aug). If you feel it is getting too late then you can do this too. I am also thinking of writing a patch for bitmap specific test dump tool (as Johannes proposed previously).
My exam dates are 18 Aug, 31 Aug, 1 Sep, 2 Sep and 3 Sep (I know the dates are weird) The dates are adjusted on request for Smart India Hackathon ( 24 Aug - 27 Aug).
Thanks :)
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Quoted 1 line · Abhradeep Chakraborty
Hello Taylor, extremely thanks for finding the reason for this failure.
No problem. I appreciate all of the time and effort that you, Dscho, and Stolee all put into looking into this (especially while I was out).
My experience with the bitmap code is that it can be somewhat difficult to work in, because there are both (a) many ways to introduce bugs, and
(b) the effect of a bug can occur far away from the source of the bug. Those two together make debugging difficult, at least for me.
I think that having a test-tool (like Dscho suggested) to dump some basic information about a bitmap's structure would be quite helpful in the future.
Quoted 5 lines · Taylor Blau
I am not able to understand this modification.
info[preferred_pack].orig_pack_int_idandpreferred_packhave the same value, right? I seectx.infogetting sorted only after callingget_sorted_entries()function.
Yeah, I realized that this is bogus. For one, (as you note) those have the same value before setting up the pack_perm array. But it also goes against the grain of what we're trying to do: the point is that the prefered-ness of objects in an existing MIDX should be discarded when generating a new pseudo-pack order.
Quoted 11 lines
Quoted 10 lines
I think there are a couple of ways to fix this. The easiest thing to do would be to force the identity of the preferred pack to be the same when generating a MIDX bitmap *while reusing an existing MIDX*, since that is the only time this bug can happen.
But that's a little magical for my taste. I think a more reasonable fix would be to include copies of all objects from the preferred pack including in the case where that pack was non-preferred in an existing MIDX and at least one object in that pack was selected from a different pack in the existing MIDX.
Quoted 3 lines
I think the later approach makes the most sense to me. It might not be a good idea to keep the same pack as
preferredas a better candidate would be ignored in that case.
Yep, I agree. Users should feel free to change the identity of the preferred pack when rewriting a MIDX regardless of whether or not they are using --stdin-packs.
Quoted 10 lines
Quoted 9 lines
Abhradeep -- let me know if this is something you want to look into. I think it's a very worthwhile bug to fix, since it is definitely trigger-able in the wild (notably, only with
git multi-pack-index write --bitmapwithout--stdin-packsand only under certain circumstances), and not just limited to SHA-256 mode.If you are busy experimenting with CRoaring, that's no problem and I can fix this up, too. Either way, it would be worth you and others weighing in on which fix you think is worth pursuing.
Quoted 5 lines
I will be happy to fix it but I can't work on it right now (neither on CRoaring) because I am currently preparing for my exam. I can continue my work after that (i.e. from 19 aug). If you feel it is getting too late then you can do this too. I am also thinking of writing a patch for bitmap specific test dump tool (as Johannes proposed previously).
No problem. I wrote up some patches today myself that implement the above fix. I haven't polished them up yet, but they are available here:
https://github.com/ttaylorr/git/compare/master...ttaylorr:git:tb/bitmap-use-existing-preferred
I want to add a more direct reproduction that works in both SHA-1 and SHA-256 to demonstrate that these patches fix the issue. But in the meantime, you can use Dscho's reproduction with these patches (based on the tip of master) applied on top and observe that it passes consistently.
Thanks,
Taylor
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
Hi Abhradeep,
Quoted 19 lines · Taylor Blau
Quoted 10 lines
Quoted 9 lines
Abhradeep -- let me know if this is something you want to look into. I think it's a very worthwhile bug to fix, since it is definitely trigger-able in the wild (notably, only with
git multi-pack-index write --bitmapwithout--stdin-packsand only under certain circumstances), and not just limited to SHA-256 mode.If you are busy experimenting with CRoaring, that's no problem and I can fix this up, too. Either way, it would be worth you and others weighing in on which fix you think is worth pursuing.
Quoted 5 lines
I will be happy to fix it but I can't work on it right now (neither on CRoaring) because I am currently preparing for my exam. I can continue my work after that (i.e. from 19 aug). If you feel it is getting too late then you can do this too. I am also thinking of writing a patch for bitmap specific test dump tool (as Johannes proposed previously).
No problem. I wrote up some patches today myself that implement the above fix. I haven't polished them up yet, but they are available here:
Quoted 7 lines
https://github.com/ttaylorr/git/compare/master...ttaylorr:git:tb/bitmap-use-existing-preferred
I want to add a more direct reproduction that works in both SHA-1 and SHA-256 to demonstrate that these patches fix the issue. But in the meantime, you can use Dscho's reproduction with these patches (based on the tip of
master) applied on top and observe that it passes consistently.
That is now done and I sent the resulting patch series to the list, which I'd encourage you to review here:
https://lore.kernel.org/git/[email protected]/T/#t
Phew!
Thanks,
Taylor
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
In reply to Johannes SchindelinQuoted 46 lines · Johannes Schindelin
Hi Abhradeep,
Quoted 13 lines · Johannes Schindelin
Quoted 10 lines · Abhradeep Chakraborty
I noticed in the 'setup partial bitmaps' test case that if we comment
out the linegit repack &&, it runs successfully.test_expect_success 'setup partial bitmaps' ' test_commit packed && # git repack && test_commit loose && git multi-pack-index write --bitmap 2>err && ... 'Quoted 2 lines
That's interesting. Are the
.bitmapand.midxfiles updated as part of thatrepack?I instrumented this, and saw that the
multi-pack-indexandmulti-pack-index*.bitmapfiles were unchanged by thegit repackinvocation.Re-generating the MIDX bitmap forcefully after the repack seems to fix things over here:
-- snip --
t/lib-bitmap.sh +3
-1@@ -438,7 +438,10 @@ midx_bitmap_partial_tests () { test_expect_success 'setup partial bitmaps' ' test_commit packed && +ls -l .git/objects/pack/ && git repack && +git multi-pack-index write --bitmap && +ls -l .git/objects/pack/ && test_commit loose && git multi-pack-index write --bitmap 2>err && test_path_is_file $midx && -- snap --
Quoted 5 lines
This suggests to me that the
multi-pack-index write --bitmap 2>errcall in this hunk might reuse a stale MIDX bitmap, and that _that_ might be the root cause of this breakage.What do you think?
Hi Dscho,
I used your code to see if it is the case but it doesn't affect the result (at least in my laptop).
Re: [PATCH v5 3/6] pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
In reply to Johannes SchindelinQuoted 15 lines · Johannes Schindelin
Hi Abhradeep,
Quoted 10 lines · Abhradeep Chakraborty
I noticed in the 'setup partial bitmaps' test case that if we comment
out the linegit repack &&, it runs successfully.test_expect_success 'setup partial bitmaps' ' test_commit packed && # git repack && test_commit loose && git multi-pack-index write --bitmap 2>err && ... '
Quoted 2 lines
That's interesting. Are the
.bitmapand.midxfiles updated as part of thatrepack?
They aren't. You can cause a MIDX / bitmap to be updated during git repack provided that the flags --write-midx and --write-bitmap-index are given to repack.
But the point of that git repack in this test case specifically is to ensure that the commit generated on the previous line is included in a new pack, and that that pack makes its way into the MIDX.
So removing that invocation of git repack means that the set of packs would be unchanged, and the git multi-pack-index write --bitmap would be a noop. That should rule out the theory that the existing MIDX is broken, since without the git repack, we'd be using that MIDX in subsequent tests (which pass).
Thanks,
Taylor
PATCH v5 4/6 pack-bitmap: prepare to read lookup table extension
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Earlier change teaches Git to write bitmap lookup table. But Git does not know how to parse them.
Teach Git to parse the existing bitmap lookup table. The older versions of Git are not affected by it. Those versions ignore the lookup table.
--- pack-bitmap.c | 275 ++++++++++++++++++++++++++++++++++++++-- pack-bitmap.h | 9 ++ t/t5310-pack-bitmaps.sh | 22 ++++ 3 files changed, 296 insertions(+), 10 deletions(-)
pack-bitmap.c +265 -10
@@ -82,6 +82,12 @@ struct bitmap_index {/* The checksum of the packfile or MIDX; points into map. */ const unsigned char *checksum; +/* +* If not NULL, this point into the commit table extension +* (within the memory mapped region `map`). +*/ +unsigned char *table_lookup; +/* * Extended index. *
@@ -185,6 +191,16 @@ static int load_bitmap_header(struct bitmap_index *index) index->hashes = (void *)(index_end - cache_size); index_end -= cache_size; } + +if (flags &BITMAP_OPT_LOOKUP_TABLE ) { +size_t table_size =st_mult (ntohl (header->entry_count), +BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH ); +if (table_size > index_end - index->map - header_size) +return error (_ ("corrupted bitmap index file (too short to fit lookup table)" )); +if (git_env_bool ("GIT_TEST_READ_COMMIT_TABLE" ,1 )) + index->table_lookup = (void *)(index_end - table_size); + index_end -= table_size; + } } index->entry_count =ntohl (header->entry_count);
@@ -211,11 +227,13 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index, hash_pos =kh_put_oid_map (index->bitmaps, stored->oid, &ret); -/* a 0 return code means the insertion succeeded with no changes, -* because the SHA1 already existed on the map. this is bad, there -* shouldn't be duplicated commits in the index */ +/* +* A 0 return code means the insertion succeeded with no changes, +* because the SHA1 already existed on the map. This is bad, there +* shouldn't be duplicated commits in the index. +*/ if (ret ==0 ) { -error ("Duplicate entry in bitmap index: %s" ,oid_to_hex (oid)); +error (_ ("duplicate entry in bitmap index: %s" ),oid_to_hex (oid));return NULL ; }
@@ -470,7 +488,7 @@ static int load_bitmap(struct bitmap_index *bitmap_git) !(bitmap_git->tags = read_bitmap_1(bitmap_git))) goto failed; -if (load_bitmap_entries_v1 (bitmap_git) <0 ) +if (!bitmap_git->table_lookup &&load_bitmap_entries_v1 (bitmap_git) <0 ) goto failed;return 0 ;
@@ -557,13 +575,238 @@ struct include_data {struct bitmap *seen; }; +struct bitmap_lookup_table_triplet { +uint32_t commit_pos; +uint64_t offset; +uint32_t xor_row; +}; + +struct bitmap_lookup_table_xor_item { +struct object_id oid; +uint64_t offset; +}; + +/* +* Given a `triplet` struct pointer and pointer `p`, this +* function reads the triplet beginning at `p` into the struct. +* Note that this function assumes that there is enough memory +* left for filling the `triplet` struct from `p`. +*/ +static int lookup_table_get_triplet_by_pointer (struct bitmap_lookup_table_triplet *triplet, +const unsigned char *p) +{ +if (!triplet) +return -1 ; + + triplet->commit_pos =get_be32 (p); + p +=sizeof (uint32_t ); + triplet->offset =get_be64 (p); + p +=sizeof (uint64_t ); + triplet->xor_row =get_be32 (p); +return 0 ; +} + +/* +* This function gets the raw triplet from `row`'th row in the +* lookup table and fills that data to the `triplet`. +*/ +static int lookup_table_get_triplet (struct bitmap_index *bitmap_git, +uint32_t pos, +struct bitmap_lookup_table_triplet *triplet) +{ +unsigned char *p =NULL ; +if (pos >= bitmap_git->entry_count) +return error (_ ("corrupt bitmap lookup table: triplet position out of index" )); + + p = bitmap_git->table_lookup +st_mult (pos,BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH ); + +return lookup_table_get_triplet_by_pointer (triplet, p); +} + +/* +* Searches for a matching triplet. `commit_pos` is a pointer +* to the wanted commit position value. `table_entry` points to +* a triplet in lookup table. The first 4 bytes of each +* triplet (pointed by `table_entry`) are compared with `*commit_pos`. +*/ +static int triplet_cmp (const void *commit_pos,const void *table_entry) +{ + +uint32_t a = *(uint32_t *)commit_pos; +uint32_t b =get_be32 (table_entry); +if (a > b) +return 1 ; +else if (a < b) +return -1 ; + +return 0 ; +} + +static uint32_t bsearch_pos (struct bitmap_index *bitmap_git, +struct object_id *oid, +uint32_t *result) +{ +int found; + +if (bitmap_is_midx (bitmap_git)) + found =bsearch_midx (oid, bitmap_git->midx, result); +else + found =bsearch_pack (oid, bitmap_git->pack, result); + +return found; +} + +/* +* `bsearch_triplet_by_pos` function searches for the raw triplet +* having commit position same as `commit_pos` and fills `triplet` +* object from the raw triplet. Returns 1 on success and 0 on +* failure. +*/ +static int bsearch_triplet_by_pos (uint32_t commit_pos, +struct bitmap_index *bitmap_git, +struct bitmap_lookup_table_triplet *triplet) +{ +unsigned char *p =bsearch (&commit_pos, bitmap_git->table_lookup, bitmap_git->entry_count, +BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH , triplet_cmp); + +if (!p) +return -1 ; + +return lookup_table_get_triplet_by_pointer (triplet, p); +} + +static struct stored_bitmap *lazy_bitmap_for_commit (struct bitmap_index *bitmap_git, +struct commit *commit) +{ +uint32_t commit_pos, xor_row; +uint64_t offset; +int flags, found; +struct bitmap_lookup_table_triplet triplet; +struct object_id *oid = &commit->object.oid; +struct ewah_bitmap *bitmap; +struct stored_bitmap *xor_bitmap =NULL ; +const int bitmap_header_size =6 ; +static struct bitmap_lookup_table_xor_item *xor_items =NULL ; +static size_t xor_items_nr =0 , xor_items_alloc =0 ; +static int is_corrupt =0 ; + +if (is_corrupt) +return NULL ; + + found =bsearch_pos (bitmap_git, oid, &commit_pos); + +if (!found) +return NULL ; + +if (bsearch_triplet_by_pos (commit_pos, bitmap_git, &triplet) <0 ) +return NULL ; + + xor_items_nr =0 ; + offset = triplet.offset; + xor_row = triplet.xor_row; + +if (xor_row !=0xffffffff ) { +int xor_flags; +khiter_t hash_pos; +struct bitmap_lookup_table_xor_item *xor_item; + +while (xor_row !=0xffffffff ) { +ALLOC_GROW (xor_items, xor_items_nr +1 , xor_items_alloc); + +if (xor_items_nr +1 >= bitmap_git->entry_count) { +error (_ ("corrupt bitmap lookup table: xor chain exceed entry count" )); + goto corrupt; + } + +if (lookup_table_get_triplet (bitmap_git, xor_row, &triplet) <0 ) + goto corrupt; + + xor_item = &xor_items[xor_items_nr]; + xor_item->offset = triplet.offset; + +if (nth_bitmap_object_oid (bitmap_git, &xor_item->oid, triplet.commit_pos) <0 ) { +error (_ ("corrupt bitmap lookup table: commit index %u out of range" ), + triplet.commit_pos); + goto corrupt; + } + + hash_pos =kh_get_oid_map (bitmap_git->bitmaps, xor_item->oid); + +/* +* If desired bitmap is already stored, we don't need +* to iterate further. Because we know that bitmaps +* that are needed to be parsed to parse this bitmap +* has already been stored. So, assign this stored bitmap +* to the xor_bitmap. +*/ +if (hash_pos <kh_end (bitmap_git->bitmaps) && + (xor_bitmap =kh_value (bitmap_git->bitmaps, hash_pos))) +break ; + xor_items_nr++; + xor_row = triplet.xor_row; + } + +while (xor_items_nr) { + xor_item = &xor_items[xor_items_nr -1 ]; + bitmap_git->map_pos = xor_item->offset; +if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) { +error (_ ("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" ), +oid_to_hex (&xor_item->oid)); + goto corrupt; + } + + bitmap_git->map_pos = bitmap_git->map_pos +sizeof (uint32_t ) +sizeof (uint8_t ); + xor_flags =read_u8 (bitmap_git->map, &bitmap_git->map_pos); + bitmap =read_bitmap_1 (bitmap_git); + +if (!bitmap) + goto corrupt; + + xor_bitmap =store_bitmap (bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags); + xor_items_nr--; + } + } + + bitmap_git->map_pos = offset; +if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) { +error (_ ("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" ), +oid_to_hex (oid)); + goto corrupt; + } + + bitmap_git->map_pos = bitmap_git->map_pos +sizeof (uint32_t ) +sizeof (uint8_t ); + flags =read_u8 (bitmap_git->map, &bitmap_git->map_pos); + bitmap =read_bitmap_1 (bitmap_git); + +if (!bitmap) + goto corrupt; + +return store_bitmap (bitmap_git, bitmap, oid, xor_bitmap, flags); + +corrupt: +free (xor_items); + is_corrupt =1 ; +return NULL ; +} +struct ewah_bitmap *bitmap_for_commit (struct bitmap_index *bitmap_git,struct commit *commit) {khiter_t hash_pos =kh_get_oid_map (bitmap_git->bitmaps, commit->object.oid); -if (hash_pos >=kh_end (bitmap_git->bitmaps)) -return NULL ; +if (hash_pos >=kh_end (bitmap_git->bitmaps)) { +struct stored_bitmap *bitmap =NULL ; +if (!bitmap_git->table_lookup) +return NULL ; + +trace2_region_enter ("pack-bitmap" ,"reading_lookup_table" , the_repository); +/* NEEDSWORK: cache misses aren't recorded */ + bitmap =lazy_bitmap_for_commit (bitmap_git, commit); +trace2_region_leave ("pack-bitmap" ,"reading_lookup_table" , the_repository); +if (!bitmap) +return NULL ; +return lookup_stored_bitmap (bitmap); + }return lookup_stored_bitmap (kh_value (bitmap_git->bitmaps, hash_pos)); }
@@ -1699,8 +1942,10 @@ void test_bitmap_walk(struct rev_info *revs)if (revs->pending.nr !=1 )die ("you must specify exactly one commit to test" ); -fprintf (stderr,"Bitmap v%d test (%d entries loaded)\n" , - bitmap_git->version, bitmap_git->entry_count); +fprintf (stderr,"Bitmap v%d test (%d entries%s)" , + bitmap_git->version, + bitmap_git->entry_count, + bitmap_git->table_lookup ?"" :" loaded" ); root = revs->pending.objects[0 ].item; bm =bitmap_for_commit (bitmap_git, (struct commit *)root);
@@ -1753,13 +1998,23 @@ void test_bitmap_walk(struct rev_info *revs)int test_bitmap_commits (struct repository *r) { -struct bitmap_index *bitmap_git =prepare_bitmap_git (r);struct object_id oid; MAYBE_UNUSED void *value; +struct bitmap_index *bitmap_git =prepare_bitmap_git (r); + +/* +* As this function is only used to print bitmap selected +* commits, we don't have to read the commit table. +*/ if (!bitmap_git)die ("failed to load bitmap indexes" ); +if (bitmap_git->table_lookup) { +if (load_bitmap_entries_v1 (bitmap_git) <0 ) +die (_ ("failed to load bitmap indexes" )); + } +kh_foreach (bitmap_git->bitmaps, oid, value, {printf ("%s\n" ,oid_to_hex (&oid)); });
pack-bitmap.h +9 -0
@@ -23,6 +23,15 @@ struct bitmap_disk_header {#define NEEDS_BITMAP (1u<<22) +/* +* The width in bytes of a single triplet in the lookup table +* extension: +* (commit_pos, offset, xor_row) +* +* whose fields ar 32-, 64-, 32- bits wide, respectively. +*/ +#define BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH (16) +enum pack_bitmap_opts {BITMAP_OPT_FULL_DAG =0x1 ,BITMAP_OPT_HASH_CACHE =0x4 ,
t/t5310-pack-bitmaps.sh +22 -0
@@ -258,6 +258,7 @@ test_bitmap_cases () { test_expect_success 'truncated bitmap fails gracefully (ewah)' ' test_config pack.writebitmaphashcache false && + test_config pack.writebitmaplookuptable false && git repack -ad && git rev-list --use-bitmap-index --count --all >expect && bitmap=$(ls .git/objects/pack/*.bitmap) &&
@@ -270,6 +271,7 @@ test_bitmap_cases () { ' test_expect_success 'truncated bitmap fails gracefully (cache)' ' + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && git repack -ad && git rev-list --use-bitmap-index --count --all >expect && bitmap=$(ls .git/objects/pack/*.bitmap) &&
@@ -453,4 +455,24 @@ test_expect_success 'verify writing bitmap lookup table when enabled' ' grep "\"label\":\"writing_lookup_table\"" trace2 ' +test_expect_success 'lookup table is actually used to traverse objects' ' + git repack -adb && + GIT_TRACE2_EVENT="$(pwd)/trace3" \ + git rev-list --use-bitmap-index --count --all && + grep "\"label\":\"reading_lookup_table\"" trace3 +' + +test_expect_success 'truncated bitmap fails gracefully (lookup table)' ' + test_config pack.writebitmaphashcache false && + git repack -adb && + git rev-list --use-bitmap-index --count --all >expect && + bitmap=$(ls .git/objects/pack/*.bitmap) && + test_when_finished "rm -f $bitmap" && + test_copy_bytes 512 <$bitmap >$bitmap.tmp && + mv -f $bitmap.tmp $bitmap && + git rev-list --use-bitmap-index --count --all >actual 2>stderr && + test_cmp expect actual && + test_i18ngrep corrupted.bitmap.index stderr +' + test_done
Signature · 1 line
gitgitgadget
Re: [PATCH v5 4/6] pack-bitmap: prepare to read lookup table extension
Quoted 23 lines · Abhradeep Chakraborty via GitGitGadget
pack-bitmap.c +19
-0@@ -557,13 +575,238 @@ struct include_data {struct bitmap *seen; }; +struct bitmap_lookup_table_triplet { +uint32_t commit_pos; +uint64_t offset; +uint32_t xor_row; +}; + +struct bitmap_lookup_table_xor_item { +struct object_id oid; +uint64_t offset; +}; + +/* +* Given a `triplet` struct pointer and pointer `p`, this +* function reads the triplet beginning at `p` into the struct. +* Note that this function assumes that there is enough memory +* left for filling the `triplet` struct from `p`. +*/ +static int lookup_table_get_triplet_by_pointer (struct bitmap_lookup_table_triplet *triplet, +const unsigned char *p)
pack-bitmap.c struct include_data { · line 606
Quoted 10 lines
pack-bitmap.c +10
-0+{ +if (!triplet) +return -1 ; + + triplet->commit_pos =get_be32 (p); + p +=sizeof (uint32_t ); + triplet->offset =get_be64 (p); + p +=sizeof (uint64_t ); + triplet->xor_row =get_be32 (p); +return 0 ;
Just noticing this now, but I wonder if we could avoid incrementing p here and instead write something like:
triplet->commit_pos = get_be32(p);
triplet->offset = get_be64(p + sizeof(uint32_t));
triplet->xor_row = get_be64(p + sizeof(uint64_t) + sizeof(uint32_t));I don't have a strong feeling about it, though, it just seems to read a little more directly to me and avoid modifying a variable that is only going to live as long as the function executes (p).
Quoted 6 lines
pack-bitmap.c +6
-0+/* +* This function gets the raw triplet from `row`'th row in the +* lookup table and fills that data to the `triplet`. +*/ +static int lookup_table_get_triplet(struct bitmap_index *bitmap_git, + uint32_t pos,
pack-bitmap.c struct include_data { · line 624
Quoted 10 lines
pack-bitmap.c +10
-0+ struct bitmap_lookup_table_triplet *triplet) +{ +unsigned char *p =NULL ; +if (pos >= bitmap_git->entry_count) +return error (_ ("corrupt bitmap lookup table: triplet position out of index" )); + + p = bitmap_git->table_lookup +st_mult (pos,BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH ); + +return lookup_table_get_triplet_by_pointer (triplet, p); +}
Very nice. This cleans things up nicely by being able to call lookup_table_get_triplet_by_pointer().
Since these are static functions, it doesn't really matter whether or not they are prefixed with 'bitmap_', since they won't be visible outside of pack-bitmap.c's compilation unit. But it may be nice to prefix them with 'bitmap_' just to make it extra clear that these are internal functions meant to be used within the bitmap machinery only.
pack-bitmap.c struct include_data { · line 690
Quoted 13 lines
pack-bitmap.c +13
-0+static struct stored_bitmap *lazy_bitmap_for_commit (struct bitmap_index *bitmap_git, +struct commit *commit) +{ +uint32_t commit_pos, xor_row; +uint64_t offset; +int flags, found; +struct bitmap_lookup_table_triplet triplet; +struct object_id *oid = &commit->object.oid; +struct ewah_bitmap *bitmap; +struct stored_bitmap *xor_bitmap =NULL ; +const int bitmap_header_size =6 ; +static struct bitmap_lookup_table_xor_item *xor_items =NULL ; +static size_t xor_items_nr =0 , xor_items_alloc =0 ;
I had to double check, but xor_items_alloc inherits the same storage class at xor_items_nr, so they are both static size_t's.
pack-bitmap.c struct include_data { · line 694
Quoted 4 lines
pack-bitmap.c +4
-0+static int is_corrupt =0 ; + +if (is_corrupt) +return NULL ;
What is the purpose of this conditional? We don't modify is_corrupt before reading it here, so this should be dead code, unless I'm missing something.
pack-bitmap.c struct include_data { · line 699
Quoted 4 lines
pack-bitmap.c +4
-0+ found =bsearch_pos (bitmap_git, oid, &commit_pos); + +if (!found) +return NULL ;
FWIW, we could eliminate this variable from a particularly long list of stack variables above by just writing:
if (!bsearch_pos(bitmap_git, oid, &commit_pos))
return NULL;
and I think that would be OK.
pack-bitmap.c struct include_data { · line 704
Quoted 4 lines
pack-bitmap.c +4
-0+if (bsearch_triplet_by_pos (commit_pos, bitmap_git, &triplet) <0 ) +return NULL ; + + xor_items_nr =0 ;
This initialization *is* necessary, since the xor_items_nr and xor_items_alloc variable are statically allocated.
pack-bitmap.c struct include_data { · line 708
Quoted 4 lines
pack-bitmap.c +4
-0+ offset = triplet.offset; + xor_row = triplet.xor_row; + +if (xor_row !=0xffffffff ) {
Is this outer conditional needed? I don't think it is. If xor_row is 0xffffffff, then the while loop below won't be entered, and xor_items_nr will be zero, meaning that the second while loop will also be skipped.
So I think we can just as easily get rid of this outermost if-statement and de-dent the main part of this function's body.
Quoted 40 lines
pack-bitmap.c +40
-0+int xor_flags; +khiter_t hash_pos; +struct bitmap_lookup_table_xor_item *xor_item; + +while (xor_row !=0xffffffff ) { +ALLOC_GROW (xor_items, xor_items_nr +1 , xor_items_alloc); + +if (xor_items_nr +1 >= bitmap_git->entry_count) { +error (_ ("corrupt bitmap lookup table: xor chain exceed entry count" )); + goto corrupt; + } + +if (lookup_table_get_triplet (bitmap_git, xor_row, &triplet) <0 ) + goto corrupt; + + xor_item = &xor_items[xor_items_nr]; + xor_item->offset = triplet.offset; + +if (nth_bitmap_object_oid (bitmap_git, &xor_item->oid, triplet.commit_pos) <0 ) { +error (_ ("corrupt bitmap lookup table: commit index %u out of range" ), + triplet.commit_pos); + goto corrupt; + } + + hash_pos =kh_get_oid_map (bitmap_git->bitmaps, xor_item->oid); + +/* +* If desired bitmap is already stored, we don't need +* to iterate further. Because we know that bitmaps +* that are needed to be parsed to parse this bitmap +* has already been stored. So, assign this stored bitmap +* to the xor_bitmap. +*/ +if (hash_pos <kh_end (bitmap_git->bitmaps) && + (xor_bitmap =kh_value (bitmap_git->bitmaps, hash_pos))) +break ; + xor_items_nr++; + xor_row = triplet.xor_row; + } +
pack-bitmap.c struct include_data { · line 758
Quoted 10 lines
pack-bitmap.c +10
-0+while (xor_items_nr) { + xor_item = &xor_items[xor_items_nr -1 ]; + bitmap_git->map_pos = xor_item->offset; +if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) { +error (_ ("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" ), +oid_to_hex (&xor_item->oid)); + goto corrupt; + } + + bitmap_git->map_pos = bitmap_git->map_pos +sizeof (uint32_t ) +sizeof (uint8_t );
Could we write:
bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t)
or similar? Also, a clarifying comment would help explain why we are advancing, what we're skipping past, and why it's OK.
Quoted 22 lines
pack-bitmap.c +22
-0+ xor_flags =read_u8 (bitmap_git->map, &bitmap_git->map_pos); + bitmap =read_bitmap_1 (bitmap_git); + +if (!bitmap) + goto corrupt; + + xor_bitmap =store_bitmap (bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags); + xor_items_nr--; + } + } + + bitmap_git->map_pos = offset; +if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) { +error (_ ("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" ), +oid_to_hex (oid)); + goto corrupt; + } + + bitmap_git->map_pos = bitmap_git->map_pos +sizeof (uint32_t ) +sizeof (uint8_t ); + flags =read_u8 (bitmap_git->map, &bitmap_git->map_pos); + bitmap =read_bitmap_1 (bitmap_git); +
pack-bitmap.c struct include_data { · line 790
Quoted 10 lines
pack-bitmap.c +10
-0+if (!bitmap) + goto corrupt; + +return store_bitmap (bitmap_git, bitmap, oid, xor_bitmap, flags); + +corrupt: +free (xor_items); + is_corrupt =1 ; +return NULL ; +}
Thanks,
Taylor
Re: [PATCH v5 4/6] pack-bitmap: prepare to read lookup table extension
Quoted 10 lines · Taylor Blau
Just noticing this now, but I wonder if we could avoid incrementing
phere and instead write something like:triplet->commit_pos = get_be32(p); triplet->offset = get_be64(p + sizeof(uint32_t)); triplet->xor_row = get_be64(p + sizeof(uint64_t) + sizeof(uint32_t));I don't have a strong feeling about it, though, it just seems to read a little more directly to me and avoid modifying a variable that is only going to live as long as the function executes (p).
Ok, will update.
Quoted 20 lines
Quoted 6 lines
pack-bitmap.c +6
-0+/* +* This function gets the raw triplet from `row`'th row in the +* lookup table and fills that data to the `triplet`. +*/ +static int lookup_table_get_triplet(struct bitmap_index *bitmap_git, + uint32_t pos,pack-bitmap.c struct include_data { · line 624
Quoted 10 lines
pack-bitmap.c +10
-0+ struct bitmap_lookup_table_triplet *triplet) +{ +unsigned char *p =NULL ; +if (pos >= bitmap_git->entry_count) +return error (_ ("corrupt bitmap lookup table: triplet position out of index" )); + + p = bitmap_git->table_lookup +st_mult (pos,BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH ); + +return lookup_table_get_triplet_by_pointer (triplet, p); +}Very nice. This cleans things up nicely by being able to call
lookup_table_get_triplet_by_pointer().
Quoted 5 lines
Since these are static functions, it doesn't really matter whether or not they are prefixed with '
bitmap_', since they won't be visible outside of pack-bitmap.c's compilation unit. But it may be nice to prefix them with 'bitmap_' just to make it extra clear that these are internal functions meant to be used within the bitmap machinery only.
Yeah, sure!
Quoted 8 lines
pack-bitmap.c struct include_data { · line 694
Quoted 4 lines
pack-bitmap.c +4
-0+static int is_corrupt =0 ; + +if (is_corrupt) +return NULL ;What is the purpose of this conditional? We don't modify
is_corruptbefore reading it here, so this should be dead code, unless I'm missing something.
My intention behind this code was -
Initially is_corrupt is 0, so the above code will not execute for the first lazy_bitmap...() call. Now, for some reason, if we get to know that the .bitmap file is corrupted, the function will goto corrupt and is_corrupt will be set to 1.
As is_corrupt is a static variable, its value will be preserved. So, whenr we call lazy_bitmap...() function for the second time (or third time etc.; i.e. bitmap_for_commit under a for loop), we instantly know that .bitmap file is corrupt (by seeing is_corrupt) and we will not do all the computations any more.
Quoted 10 lines
pack-bitmap.c struct include_data { · line 708
Quoted 5 lines
pack-bitmap.c +4
-0+ offset = triplet.offset; + xor_row = triplet.xor_row; + +if (xor_row !=0xffffffff ) {Is this outer conditional needed? I don't think it is. If
xor_rowis0xffffffff, then the while loop below won't be entered, andxor_items_nrwill be zero, meaning that the second while loop will also be skipped.
Yes, you're right - it is not needed. But it guarantees that all the code inside its braces will be run only if has a xor offset causing the allocation of xor_items array as lazy as possible.
Should I remove it?
Quoted 5 lines
Quoted 1 line
+
bitmap_git->map_pos=bitmap_git->map_pos+sizeof(uint32_t)+sizeof(uint8_t);Could we write:
bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t)
Sure!
Thanks :)
Re: [PATCH v5 4/6] pack-bitmap: prepare to read lookup table extension
In reply to Taylor BlauQuoted 11 lines · Taylor Blau
pack-bitmap.c struct include_data { · line 606
Quoted 6 lines · Abhradeep Chakraborty via GitGitGadget
pack-bitmap.c +6
-0+ triplet->commit_pos =get_be32 (p); + p +=sizeof (uint32_t ); + triplet->offset =get_be64 (p); + p +=sizeof (uint64_t ); + triplet->xor_row =get_be32 (p); +return 0 ;Just noticing this now, but I wonder if we could avoid incrementing
phere and instead write something like:
Quoted 7 lines
triplet->commit_pos = get_be32(p); triplet->offset = get_be64(p + sizeof(uint32_t)); triplet->xor_row = get_be64(p + sizeof(uint64_t) + sizeof(uint32_t));I don't have a strong feeling about it, though, it just seems to read a little more directly to me and avoid modifying a variable that is only going to live as long as the function executes (p).
While it may not matter much in this tiny function, the code in the patch sets a better precedent by conforming to a pattern which is more maintainable in situations involving more pieces of data which need to be decoded. It's also easier to reason about than the suggested replacement since you don't have to spend extra cycles double-checking if it's adding the correct number of and correctly-sized offsets at each get_be*() invocation. IMHO, the way the patch already handles this seems preferable.
PATCH v5 5/6 p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Enable pack.writeReverseIndex before running pack-bitmap related performance tests.
The performance difference with pack.writeReverseIndex enabled and with disabled are given below -
With pack.writeReverseIndex
-------------------------------
Test this tree
-------------------------------------------------------------------------
5310.3: repack to disk 296.55(256.53+14.52)
5310.4: simulated clone 15.64(8.88+1.39)
5310.5: simulated fetch 1.65(2.75+0.20)
5310.6: pack to file (bitmap) 48.71(30.20+7.58)
5310.7: rev-list (commits) 0.61(0.41+0.08)
5310.8: rev-list (objects) 4.38(4.26+0.09)
5310.9: rev-list with tag negated via --not 0.07(0.02+0.04)
--all (objects)
5310.10: rev-list with negative tag (objects) 0.05(0.01+0.03)
5310.11: rev-list count with blob:none 0.08(0.03+0.04)
5310.12: rev-list count with blob:limit=1k 7.29(6.92+0.30)
5310.13: rev-list count with tree:0 0.08(0.03+0.04)
5310.14: simulated partial clone 9.45(8.12+0.41)
5310.16: clone (partial bitmap) 17.02(10.61+2.67)
5310.17: pack to file (partial bitmap) 51.91(28.57+7.48)
5310.18: rev-list with tree filter (partial bitmap) 1.00(0.22+0.24)Without pack.writeReverseIndex:
-----------------------------
Test this tree
------------------------------------------------------------------------
5310.3: repack to disk 293.80(251.30+14.30)
5310.4: simulated clone 12.50(5.15+1.36)
5310.5: simulated fetch 1.83(2.90+0.23)
5310.6: pack to file (bitmap) 39.70(20.25+7.14)
5310.7: rev-list (commits) 1.00(0.60+0.13)
5310.8: rev-list (objects) 4.11(4.00+0.10)
5310.9: rev-list with tag negated via --not 0.07(0.02+0.05)
--all (objects)
5310.10: rev-list with negative tag (objects) 0.23(0.16+0.06)
5310.11: rev-list count with blob:none 0.27(0.18+0.08)
5310.12: rev-list count with blob:limit=1k 6.41(5.98+0.41)
5310.13: rev-list count with tree:0 0.26(0.18+0.07)
5310.14: simulated partial clone 4.34(3.29+0.37)
5310.16: clone (partial bitmap) 21.48(15.12+2.42)
5310.17: pack to file (partial bitmap) 47.35(37.80+4.84)5310.18: rev-list with tree filter (partial bitmap) 0.73(0.07+0.21)
--- t/perf/p5310-pack-bitmaps.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
t/perf/p5310-pack-bitmaps.sh +2 -1
@@ -13,7 +13,8 @@ test_perf_large_repo # We intentionally use the deprecated pack.writebitmaps # config so that we can test against older versions of git. test_expect_success 'setup bitmap config' ' - git config pack.writebitmaps true + git config pack.writebitmaps true && + git config pack.writeReverseIndex true ' # we need to create the tag up front such that it is covered by the repack and
Signature · 1 line
gitgitgadget
Re: [PATCH v5 5/6] p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
Quoted 7 lines · Abhradeep Chakraborty via GitGitGadget
From: Abhradeep Chakraborty <[email protected]>
Enable
pack.writeReverseIndexbefore running pack-bitmap related performance tests.The performance difference with
pack.writeReverseIndexenabled and with disabled are given below -
Thanks; this order of changes in the t/perf suite makes sense to me. One note, this sort of change where we're comparing all of the tests in a single t/perf file against themselves before and after some change, it is helpful to do (in t/perf)
./run HEAD . p5310-pack-bitmaps.sh
which compares HEAD to what's in the current tree. You'll get the results side-by-side, which makes them a little easier to scan. You can also aggregate results together from multiple runs with the t/perf/aggregate.perl script.
One gotcha (that has often bitten me in the past) is that when running the perf suite with . as your build target, it uses whatever git binary is sitting in your tree. So make sure that it is both (a) up-to-date, ie., that it is the result of compiling what's currently in your tree, and (b) that it is compiled with the same settings as what you built HEAD with.
I have often scratched my head at why the result of running some perf suite on '.' seems much slower than it should be, only to realize that the "git" binary sitting in my tree was built with -O0 or something.
Thanks,
Taylor
Re: [PATCH v5 5/6] p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
Quoted 28 lines · Taylor Blau
Quoted 7 lines · Abhradeep Chakraborty via GitGitGadget
From: Abhradeep Chakraborty <[email protected]>
Enable
pack.writeReverseIndexbefore running pack-bitmap related performance tests.The performance difference with
pack.writeReverseIndexenabled and with disabled are given below -Thanks; this order of changes in the t/perf suite makes sense to me. One note, this sort of change where we're comparing all of the tests in a single t/perf file against themselves before and after some change, it is helpful to do (in t/perf)
./run HEAD .
p5310-pack-bitmaps.shwhich compares HEAD to what's in the current tree. You'll get the results side-by-side, which makes them a little easier to scan. You can also aggregate results together from multiple runs with the t/perf/aggregate.perl script.
One gotcha (that has often bitten me in the past) is that when running the perf suite with
.as your build target, it uses whatever git binary is sitting in your tree. So make sure that it is both (a) up-to-date, ie., that it is the result of compiling what's currently in your tree, and (b) that it is compiled with the same settings as what you built HEAD with.
Quoted 3 lines
I have often scratched my head at why the result of running some perf suite on '.' seems much slower than it should be, only to realize that the "git" binary sitting in my tree was built with -O0 or something.
Rather than comparing HEAD to your current tree it's generally better to do something like:
GIT_PERF_MAKE_OPTS='-j3' ./run HEAD~ HEAD [...]
Re: [PATCH v5 5/6] p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
Quoted 4 lines · Ævar Arnfjörð Bjarmason
Rather than comparing HEAD to your current tree it's generally better to do something like:
GIT_PERF_MAKE_OPTS='-j3' ./run HEAD~ HEAD [...]
Using the 'run' script fixes the perf test in the worktree and tests different versions of the 'git' executable.
That doesn't work when the change is in the performance test itself.
Thanks,
-Stolee
Re: [PATCH v5 5/6] p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
Quoted 10 lines · Derrick Stolee
Quoted 4 lines · Ævar Arnfjörð Bjarmason
Rather than comparing HEAD to your current tree it's generally better to do something like:
GIT_PERF_MAKE_OPTS='-j3' ./run HEAD~ HEAD [...]Using the 'run' script fixes the perf test in the worktree and tests different versions of the 'git' executable.
That doesn't work when the change is in the performance test itself.
Thanks, I'm clearly wrong about that. I didn't look enough at the context.
But then we're losing the perf test coverage for the case where we don't have the *.rev files. Isn't it better to run both with & without *.rev, perhaps by splitting up the test file? We could make it a function in perf/lib-bitmap.sh that we call both with & without the wanted *.rev repack config.
I suspect that's also subtly broken, in that t/perf assumes that it can re-use the repo for a given <rev>, but this is modifying that repo, so if you run e.g. test Y after this Y, that Y will unexpectedly get a repack'd repo ...
But we could just start the test with a git clone . "$TEST_NAME" or whatever, then repack that with whatever options we want...
Re: [PATCH v5 5/6] p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
Quoted 5 lines · Ævar Arnfjörð Bjarmason
But then we're losing the perf test coverage for the case where we don't have the *.rev files. Isn't it better to run both with & without *.rev, perhaps by splitting up the test file? We could make it a function in
perf/lib-bitmap.shthat we call both with & without the wanted *.rev repack config.
Ok.
Quoted 4 lines
I suspect that's also subtly broken, in that t/perf assumes that it can re-use the repo for a given <rev>, but this is modifying that repo, so if you run e.g. test Y after this Y, that Y will unexpectedly get a repack'd repo ...
Thanks Ævar! This is the problem that I informed Taylor off-list. Will update it.
Quoted 2 lines
But we could just start the test with a git clone . "$TEST_NAME" or whatever, then repack that with whatever options we want...
Thanks :)
PATCH v5 6/6 bitmap-lookup-table: add performance tests for lookup table
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Add performance tests to verify the performance of lookup table with pack.writeReverseIndex enabled. This is to check the performance when the above configuration is set.
Lookup table makes Git run faster in most of the cases. Below is the result of t/perf/p5310-pack-bitmaps.sh.perf/p5326-multi-pack-bitmaps.sh gives similar result. The repository used in the test is linux kernel.
Test this tree
---------------------------------------------------------------------------
5310.4: repack to disk (lookup=false) 296.55(256.53+14.52)
5310.5: simulated clone 15.64(8.88+1.39)
5310.6: simulated fetch 1.65(2.75+0.20)
5310.7: pack to file (bitmap) 48.71(30.20+7.58)
5310.8: rev-list (commits) 0.61(0.41+0.08)
5310.9: rev-list (objects) 4.38(4.26+0.09)
5310.10: rev-list with tag negated via --not 0.07(0.02+0.04)
--all (objects)
5310.11: rev-list with negative tag (objects) 0.05(0.01+0.03)
5310.12: rev-list count with blob:none 0.08(0.03+0.04)
5310.13: rev-list count with blob:limit=1k 7.29(6.92+0.30)
5310.14: rev-list count with tree:0 0.08(0.03+0.04)
5310.15: simulated partial clone 9.45(8.12+0.41)
5310.17: clone (partial bitmap) 21.00(15.04+2.39)
5310.18: pack to file (partial bitmap) 47.98(38.13+5.23)
5310.19: rev-list with tree filter (partial bitmap) 0.70(0.07+0.20)
5310.22: repack to disk (lookup=true) 255.92(188.13+20.47)
5310.23: simulated clone 13.78(8.84+1.09)
5310.24: simulated fetch 0.52(0.63+0.14)
5310.25: pack to file (bitmap) 44.34(28.94+6.84)
5310.26: rev-list (commits) 0.48(0.31+0.06)
5310.27: rev-list (objects) 4.02(3.93+0.07)
5310.28: rev-list with tag negated via --not 0.04(0.00+0.03)
--all (objects)
5310.29: rev-list with negative tag (objects) 0.04(0.00+0.03)
5310.30: rev-list count with blob:none 0.04(0.01+0.03)
5310.31: rev-list count with blob:limit=1k 6.48(6.23+0.22)
5310.32: rev-list count with tree:0 0.04(0.01+0.03)
5310.33: simulated partial clone 8.30(7.21+0.36)
5310.35: clone (partial bitmap) 20.34(15.00+2.41)
5310.36: pack to file (partial bitmap) 46.45(38.05+5.20)
5310.37: rev-list with tree filter (partial bitmap) 0.61(0.06+0.20)Test 4-15 are tested without using lookup table. Same tests are repeated in 16-30 (using lookup table).
--- t/perf/p5310-pack-bitmaps.sh | 65 +++++++++++--------- t/perf/p5326-multi-pack-bitmaps.sh | 95 +++++++++++++++++------------- 2 files changed, 91 insertions(+), 69 deletions(-)
t/perf/p5310-pack-bitmaps.sh +38 -27
@@ -17,39 +17,50 @@ test_expect_success 'setup bitmap config' ' git config pack.writeReverseIndex true ' -# we need to create the tag up front such that it is covered by the repack and -# thus by generated bitmaps. -test_expect_success 'create tags' ' - git tag --message="tag pointing to HEAD" perf-tag HEAD -' +test_bitmap () { + local enabled="$1" -test_perf 'repack to disk' ' - git repack -ad -' + # we need to create the tag up front such that it is covered by the repack and + # thus by generated bitmaps. + test_expect_success 'create tags' ' + git tag --message="tag pointing to HEAD" perf-tag HEAD + ' -test_full_bitmap + test_expect_success "use lookup table: $enabled" ' + git config pack.writeBitmapLookupTable '"$enabled"' + ' -test_expect_success 'create partial bitmap state' ' - # pick a commit to represent the repo tip in the past - cutoff=$(git rev-list HEAD~100 -1) && - orig_tip=$(git rev-parse HEAD) && + test_perf "repack to disk (lookup=$enabled)" ' + git repack -ad + ' - # now kill off all of the refs and pretend we had - # just the one tip - rm -rf .git/logs .git/refs/* .git/packed-refs && - git update-ref HEAD $cutoff && + test_full_bitmap - # and then repack, which will leave us with a nice - # big bitmap pack of the "old" history, and all of - # the new history will be loose, as if it had been pushed - # up incrementally and exploded via unpack-objects - git repack -Ad && + test_expect_success "create partial bitmap state (lookup=$enabled)" ' + # pick a commit to represent the repo tip in the past + cutoff=$(git rev-list HEAD~100 -1) && + orig_tip=$(git rev-parse HEAD) && - # and now restore our original tip, as if the pushes - # had happened - git update-ref HEAD $orig_tip -' + # now kill off all of the refs and pretend we had + # just the one tip + rm -rf .git/logs .git/refs/* .git/packed-refs && + git update-ref HEAD $cutoff && + + # and then repack, which will leave us with a nice + # big bitmap pack of the "old" history, and all of + # the new history will be loose, as if it had been pushed + # up incrementally and exploded via unpack-objects + git repack -Ad && + + # and now restore our original tip, as if the pushes + # had happened + git update-ref HEAD $orig_tip + ' + + test_partial_bitmap +} -test_partial_bitmap +test_bitmap false +test_bitmap true test_done
t/perf/p5326-multi-pack-bitmaps.sh +53 -42
100 lines not on this page · raw message
Signature · 1 line
gitgitgadget
v6 cover bitmap: integrate a lookup table extension to the bitmap format
In reply to Abhradeep Chakraborty via GitGitGadgetWhen parsing the .bitmap file, git loads all the bitmaps one by one even if some of the bitmaps are not necessary. We can remove this overhead by loading only the necessary bitmaps. A look up table extension can solve this issue.
Changes since v5:
As the failure in the test case is not due to this code, I think it makes no sense to delay the patch further.
* The performance test changes were not accurate as the second test_bitmap_cases call using the repo built for the previous call. This version fixes that.
* Taylor suggested some minor changes. Those are addressed in this version.
Changes since v4:
* There was a CI failing test for linux-sha256 in the previous version. Fixed now.
Changes since v3:
* The common code from both lookup_table_get_triplet() and bsearch_triplet_by_pos are moved to lookup_table_get_triplet_by_pointer function
* parameter names of triplet_cmp function is changes (as suggested by Martin)
* xor_items array is now work as reusable static buffer.
* I moved the filling commit_positions array part (from pack-bitmap-write.c) to bitmap_writer_finish function. Because we had to iterate two times for commit positions - one in write_selected_commits_v1 and another in write_lookup_table function. Hope this is acceptable :)
* changes in performance tests (as suggested by Taylor)
Changes since v2:
* Log messages related issues are fixed.
* pack.writeBitmapLookupTable is now by default disabled.
* Documentations are improved.
* xor_row is used instead of xor_pos in triplets.
* In pack-bitmap-write.c, off_t * is used for offsets array (Instead of uint64_t *).
* struct bitmap_lookup_table_triplet is introduced and functions Like triplet_get_offset() and triplet_get_xor_pos() are removed.
* table_size is getting subtracted from index_end irrespective of the value of GIT_TEST_READ_COMMIT_TABLE.
* xor stack filling loop will stop iterating if a xor bitmap is already stored/parsed.
* The stack will now store bitmap_lookup_table_xor_item items Of plain xor_row.
* bitmap related test files are reformatted to allow repeating of tests with bitmap extension enabled.
* comments are added.
Changes since v1:
This is the second version which addressed all (I think) the reviews. Please notify me if some reviews are not addressed :)
* The table size is decreased and the format has also changed. It now contains nr_entries triplets of size 4+8+4 bytes. Each triplet contains the following things - (1) 4 byte commit position (in the pack-index or midx) (2) 8 byte offset and (3) 4 byte xor triplet (i.e. with whose bitmap the current triplet's bitmap has to xor) position.
* Performance tests are splitted into two commits. First contains the actual performance tests and second enables the pack.writeReverseIndex (as suggested by Taylor).
* st_*() functions are used.
* commit order is changed according to Derrick's suggestion.
* Iterative approach is used instead of recursive approach to parse xor bitmaps. (As suggested by Derrick).
* Some minor bug fixes of previous version.
Initial version:
The proposed table has:
* a list of nr_entries object ids. These objects are commits that has bitmaps. Ids are stored in lexicographic order (for better searching).
* a list of <offset, xor-offset> pairs (4-byte integers, network-byte order). The i'th pair denotes the offset and xor-offset(respectively) of the bitmap of i'th commit in the previous list. These two informations are necessary because only in this way bitmaps can be found without parsing all the bitmap.
* a 4-byte integer for table specific flags (none exists currently).
Whenever git want to parse the bitmap for a specific commit, it will first refer to the table and will look for the offset and xor-offset for that commit. Git will then try to parse the bitmap located at the offset position. The xor-offset can be used to find the xor-bitmap for the bitmap(if any).
Abhradeep Chakraborty (6):
Documentation/technical: describe bitmap lookup table extension
bitmap: move get commit positions code to bitmap_writer_finish pack-bitmap-write.c: write lookup table extension
pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
pack-bitmap: prepare to read lookup table extension
bitmap-lookup-table: add performance tests for lookup table
Documentation/config/pack.txt | 7 + Documentation/technical/bitmap-format.txt | 39 ++ builtin/multi-pack-index.c | 7 + builtin/pack-objects.c | 8 + midx.c | 3 + midx.h | 1 + pack-bitmap-write.c | 114 +++- pack-bitmap.c | 290 +++++++- pack-bitmap.h | 14 +- t/perf/lib-bitmap.sh | 31 + t/perf/p5310-pack-bitmaps.sh | 78 +-- t/perf/p5311-pack-bitmaps-fetch.sh | 74 +- t/perf/p5312-pack-bitmaps-revs.sh | 35 + t/perf/p5326-multi-pack-bitmaps.sh | 103 +-- t/t5310-pack-bitmaps.sh | 786 ++++++++++++---------- t/t5311-pack-bitmaps-shallow.sh | 53 +- t/t5326-multi-pack-bitmaps.sh | 421 +++++++----- t/t5327-multi-pack-bitmaps-rev.sh | 24 +- 18 files changed, 1378 insertions(+), 710 deletions(-) create mode 100755 t/perf/p5312-pack-bitmaps-revs.sh
base-commit: afa70145a25e81faa685dc0b465e52b45d2444bd
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1266%2FAbhra303%2Fbitmap-commit-table-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1266/Abhra303/bitmap-commit-table-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/1266
Range-diff vs v5:
1: 33aca8f3dc8 ! 1: 67b71be8c85 Documentation/technical: describe bitmap lookup table extension
@@ Commit message
## Documentation/technical/bitmap-format.txt ##
@@ Documentation/technical/bitmap-format.txt: MIDXs, both the bit-cache and rev-cache extensions are required.
- pack/MIDX. The format and meaning of the name-hash is
- described below.
+ pack/MIDX. The format and meaning of the name-hash is
+ described below.
-+ ** {empty}
-+ BITMAP_OPT_LOOKUP_TABLE (0x10): :::
-+ If present, the end of the bitmap file contains a table
-+ containing a list of N <commit_pos, offset, xor_row>
-+ triplets. The format and meaning of the table is described
-+ below.
++ ** {empty}
++ BITMAP_OPT_LOOKUP_TABLE (0x10): :::
++ If present, the end of the bitmap file contains a table
++ containing a list of N <commit_pos, offset, xor_row>
++ triplets. The format and meaning of the table is described
++ below.
++
+NOTE: Unlike the xor_offset used to compress an individual bitmap, +xor_row stores an *absolute* index into the lookup table, not a location +relative to the current entry.
+
- 4-byte entry count (network byte order)
+ 4-byte entry count (network byte order): ::
+ The total count of entries (bitmapped commits) in this bitmap index.
- The total count of entries (bitmapped commits) in this bitmap index.
@@ Documentation/technical/bitmap-format.txt: Note that this hashing scheme is tied to the BITMAP_OPT_HASH_CACHE flag.
If implementations want to choose a different hashing scheme, they are
free to do so, but MUST allocate a new header flag (because comparing
-: ----------- > 2: 92ca58fbeeb bitmap: move `get commit positions` code to `bitmap_writer_finish`
2: a913e6a2cb3 ! 3: 090becaabe0 pack-bitmap-write.c: write lookup table extension
@@ Commit message
## pack-bitmap-write.c ##
@@ pack-bitmap-write.c: static const struct object_id *oid_access(size_t pos, const void *table)
-
static void write_selected_commits_v1(struct hashfile *f,
struct pack_idx_entry **index,
-- uint32_t index_nr)
-+ uint32_t index_nr,
-+ off_t *offsets,
-+ uint32_t *commit_positions)
+ uint32_t index_nr,
+- uint32_t *commit_positions)
++ uint32_t *commit_positions,
++ off_t *offsets)
{
int i;
for (i = 0; i < writer.selected_nr; ++i) {
struct bitmapped_commit *stored = &writer.selected[i];
-- int commit_pos =
-- oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
+ if (offsets)
+ offsets[i] = hashfile_total(f);
-
-- if (commit_pos < 0)
-- BUG("trying to write commit not in index");
--
-- hashwrite_be32(f, commit_pos);
-+ hashwrite_be32(f, commit_positions[i]);
++
+ hashwrite_be32(f, commit_positions[i]);
hashwrite_u8(f, stored->xor_offset);
hashwrite_u8(f, stored->flags);
-
@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
}
}
@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
+static void write_lookup_table(struct hashfile *f,
+ struct pack_idx_entry **index,
+ uint32_t index_nr,
-+ off_t *offsets,
-+ uint32_t *commit_positions)
++ uint32_t *commit_positions,
++ off_t *offsets)
+{
+ uint32_t i;
+ uint32_t *table, *table_inv;
@@ pack-bitmap-write.c: static void write_selected_commits_v1(struct hashfile *f,
struct pack_idx_entry **index,
uint32_t index_nr)
@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
- {
- static uint16_t default_version = 1;
- static uint16_t flags = BITMAP_OPT_FULL_DAG;
-+ off_t *offsets = NULL;
struct strbuf tmp_file = STRBUF_INIT;
struct hashfile *f;
-+ uint32_t *commit_positions = NULL;
+ uint32_t *commit_positions = NULL;
++ off_t *offsets = NULL;
+ uint32_t i;
struct bitmap_disk_header header;
-
@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
- dump_bitmap(f, writer.trees);
dump_bitmap(f, writer.blobs);
dump_bitmap(f, writer.tags);
-- write_selected_commits_v1(f, index, index_nr);
-+
-+ ALLOC_ARRAY(commit_positions, writer.selected_nr);
-+ for (uint32_t i = 0; i < writer.selected_nr; ++i) {
-+ struct bitmapped_commit *stored = &writer.selected[i];
-+ int commit_pos = oid_pos(&stored->commit->object.oid, index, index_nr, oid_access);
-+
-+ if (commit_pos < 0)
-+ BUG(_("trying to write commit not in index"));
-+
-+ commit_positions[i] = commit_pos;
-+ }
-+
+
+ if (options & BITMAP_OPT_LOOKUP_TABLE)
+ CALLOC_ARRAY(offsets, index_nr);
+
-+ write_selected_commits_v1(f, index, index_nr, offsets, commit_positions);
+ ALLOC_ARRAY(commit_positions, writer.selected_nr);
+
+ for (i = 0; i < writer.selected_nr; i++) {
+@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
+ commit_positions[i] = commit_pos;
+ }
+
+- write_selected_commits_v1(f, index, index_nr, commit_positions);
++ write_selected_commits_v1(f, index, index_nr, commit_positions, offsets);
+
+ if (options & BITMAP_OPT_LOOKUP_TABLE)
-+ write_lookup_table(f, index, index_nr, offsets, commit_positions);
++ write_lookup_table(f, index, index_nr, commit_positions, offsets);
if (options & BITMAP_OPT_HASH_CACHE)
write_hash_cache(f, index, index_nr);
@@ pack-bitmap-write.c: void bitmap_writer_finish(struct pack_idx_entry **index,
- die_errno("unable to rename temporary bitmap file to '%s'", filename);
strbuf_release(&tmp_file);
+ free(commit_positions);
+ free(offsets);
-+ free(commit_positions);
}
## pack-bitmap.h ##
3: 59b465e5a78 ! 4: b2b7c5c1703 pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
@@ builtin/pack-objects.c: static int git_pack_config(const char *k, const char *v,
return 0;
## midx.c ##
-@@ midx.c: static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,
+@@ midx.c: static int write_midx_bitmap(const char *midx_name,
if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
options |= BITMAP_OPT_HASH_CACHE;
+ if (flags & MIDX_WRITE_BITMAP_LOOKUP_TABLE)
+ options |= BITMAP_OPT_LOOKUP_TABLE;
+
- prepare_midx_packing_data(&pdata, ctx);
-
- commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, ctx);
+ /*
+ * Build the MIDX-order index based on pdata.objects (which is already
+ * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
## midx.h ##
@@ midx.h: struct multi_pack_index {
@@ t/t5327-multi-pack-bitmaps-rev.sh: GIT_TEST_MIDX_READ_RIDX=0
-midx_bitmap_core rev
-midx_bitmap_partial_tests rev
+test_midx_bitmap_rev () {
-+ writeLookupTable=false
-+
-+ for i in "$@"
-+ do
-+ case $i in
-+ "pack.writeBitmapLookupTable") writeLookupTable=true;;
-+ esac
-+ done
-+
-+ test_expect_success 'setup bitmap config' '
-+ rm -rf * .git &&
-+ git init &&
-+ git config pack.writeBitmapLookupTable '"$writeLookupTable"'
-+ '
-+
-+ midx_bitmap_core rev
-+ midx_bitmap_partial_tests rev
-+ }
-+
-+ test_midx_bitmap_rev
-+ test_midx_bitmap_rev "pack.writeBitmapLookupTable"
++ writeLookupTable=false
++
++ for i in "$@"
++ do
++ case $i in
++ "pack.writeBitmapLookupTable") writeLookupTable=true;;
++ esac
++ done
++
++ test_expect_success 'setup bitmap config' '
++ rm -rf * .git &&
++ git init &&
++ git config pack.writeBitmapLookupTable '"$writeLookupTable"'
++ '
++
++ midx_bitmap_core rev
++ midx_bitmap_partial_tests rev
++}
++
++test_midx_bitmap_rev
++test_midx_bitmap_rev "pack.writeBitmapLookupTable"
test_done
4: 6918f0860ad ! 5: 79842ca590c pack-bitmap: prepare to read lookup table extension
@@ pack-bitmap.c: static struct stored_bitmap *store_bitmap(struct bitmap_index *in
+ * shouldn't be duplicated commits in the index.
+ */
if (ret == 0) {
-- error("Duplicate entry in bitmap index: %s", oid_to_hex(oid));
-+ error(_("duplicate entry in bitmap index: %s"), oid_to_hex(oid));
+ error(_("duplicate entry in bitmap index: '%s'"), oid_to_hex(oid));
return NULL;
- }
-
@@ pack-bitmap.c: static int load_bitmap(struct bitmap_index *bitmap_git)
!(bitmap_git->tags = read_bitmap_1(bitmap_git)))
goto failed;
@@ pack-bitmap.c: struct include_data {
+ * Note that this function assumes that there is enough memory
+ * left for filling the `triplet` struct from `p`.
+ */
-+static int lookup_table_get_triplet_by_pointer(struct bitmap_lookup_table_triplet *triplet,
-+ const unsigned char *p)
++static int bitmap_lookup_table_get_triplet_by_pointer(struct bitmap_lookup_table_triplet *triplet,
++ const unsigned char *p)
+{
+ if (!triplet)
+ return -1;
@@ pack-bitmap.c: struct include_data {
+ * This function gets the raw triplet from `row`'th row in the
+ * lookup table and fills that data to the `triplet`.
+ */
-+static int lookup_table_get_triplet(struct bitmap_index *bitmap_git,
-+ uint32_t pos,
-+ struct bitmap_lookup_table_triplet *triplet)
++static int bitmap_lookup_table_get_triplet(struct bitmap_index *bitmap_git,
++ uint32_t pos,
++ struct bitmap_lookup_table_triplet *triplet)
+{
+ unsigned char *p = NULL;
+ if (pos >= bitmap_git->entry_count)
@@ pack-bitmap.c: struct include_data {
+
+ p = bitmap_git->table_lookup + st_mult(pos, BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH);
+
-+ return lookup_table_get_triplet_by_pointer(triplet, p);
++ return bitmap_lookup_table_get_triplet_by_pointer(triplet, p);
+}
+
+/*
@@ pack-bitmap.c: struct include_data {
+ return 0;
+}
+
-+static uint32_t bsearch_pos(struct bitmap_index *bitmap_git,
++static uint32_t bitmap_bsearch_pos(struct bitmap_index *bitmap_git,
+ struct object_id *oid,
+ uint32_t *result)
+{
@@ pack-bitmap.c: struct include_data {
+ * object from the raw triplet. Returns 1 on success and 0 on
+ * failure.
+ */
-+static int bsearch_triplet_by_pos(uint32_t commit_pos,
++static int bitmap_bsearch_triplet_by_pos(uint32_t commit_pos,
+ struct bitmap_index *bitmap_git,
+ struct bitmap_lookup_table_triplet *triplet)
+{
@@ pack-bitmap.c: struct include_data {
+ if (!p)
+ return -1;
+
-+ return lookup_table_get_triplet_by_pointer(triplet, p);
++ return bitmap_lookup_table_get_triplet_by_pointer(triplet, p);
+}
+
+static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_git,
-+ struct commit *commit)
++ struct commit *commit)
+{
+ uint32_t commit_pos, xor_row;
+ uint64_t offset;
-+ int flags, found;
++ int flags;
+ struct bitmap_lookup_table_triplet triplet;
+ struct object_id *oid = &commit->object.oid;
+ struct ewah_bitmap *bitmap;
@@ pack-bitmap.c: struct include_data {
+ static struct bitmap_lookup_table_xor_item *xor_items = NULL;
+ static size_t xor_items_nr = 0, xor_items_alloc = 0;
+ static int is_corrupt = 0;
++ int xor_flags;
++ khiter_t hash_pos;
++ struct bitmap_lookup_table_xor_item *xor_item;
+
+ if (is_corrupt)
+ return NULL;
+
-+ found = bsearch_pos(bitmap_git, oid, &commit_pos);
-+
-+ if (!found)
++ if (!bitmap_bsearch_pos(bitmap_git, oid, &commit_pos))
+ return NULL;
+
-+ if (bsearch_triplet_by_pos(commit_pos, bitmap_git, &triplet) < 0)
++ if (bitmap_bsearch_triplet_by_pos(commit_pos, bitmap_git, &triplet) < 0)
+ return NULL;
+
+ xor_items_nr = 0;
+ offset = triplet.offset;
+ xor_row = triplet.xor_row;
+
-+ if (xor_row != 0xffffffff) {
-+ int xor_flags;
-+ khiter_t hash_pos;
-+ struct bitmap_lookup_table_xor_item *xor_item;
-+
-+ while (xor_row != 0xffffffff) {
-+ ALLOC_GROW(xor_items, xor_items_nr + 1, xor_items_alloc);
-+
-+ if (xor_items_nr + 1 >= bitmap_git->entry_count) {
-+ error(_("corrupt bitmap lookup table: xor chain exceed entry count"));
-+ goto corrupt;
-+ }
-+
-+ if (lookup_table_get_triplet(bitmap_git, xor_row, &triplet) < 0)
-+ goto corrupt;
-+
-+ xor_item = &xor_items[xor_items_nr];
-+ xor_item->offset = triplet.offset;
-+
-+ if (nth_bitmap_object_oid(bitmap_git, &xor_item->oid, triplet.commit_pos) < 0) {
-+ error(_("corrupt bitmap lookup table: commit index %u out of range"),
-+ triplet.commit_pos);
-+ goto corrupt;
-+ }
-+
-+ hash_pos = kh_get_oid_map(bitmap_git->bitmaps, xor_item->oid);
-+
-+ /*
-+ * If desired bitmap is already stored, we don't need
-+ * to iterate further. Because we know that bitmaps
-+ * that are needed to be parsed to parse this bitmap
-+ * has already been stored. So, assign this stored bitmap
-+ * to the xor_bitmap.
-+ */
-+ if (hash_pos < kh_end(bitmap_git->bitmaps) &&
-+ (xor_bitmap = kh_value(bitmap_git->bitmaps, hash_pos)))
-+ break;
-+ xor_items_nr++;
-+ xor_row = triplet.xor_row;
++ while (xor_row != 0xffffffff) {
++ ALLOC_GROW(xor_items, xor_items_nr + 1, xor_items_alloc);
++
++ if (xor_items_nr + 1 >= bitmap_git->entry_count) {
++ error(_("corrupt bitmap lookup table: xor chain exceed entry count"));
++ goto corrupt;
+ }
+
-+ while (xor_items_nr) {
-+ xor_item = &xor_items[xor_items_nr - 1];
-+ bitmap_git->map_pos = xor_item->offset;
-+ if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) {
-+ error(_("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""),
-+ oid_to_hex(&xor_item->oid));
-+ goto corrupt;
-+ }
++ if (bitmap_lookup_table_get_triplet(bitmap_git, xor_row, &triplet) < 0)
++ goto corrupt;
++
++ xor_item = &xor_items[xor_items_nr];
++ xor_item->offset = triplet.offset;
+
-+ bitmap_git->map_pos = bitmap_git->map_pos + sizeof(uint32_t) + sizeof(uint8_t);
-+ xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
-+ bitmap = read_bitmap_1(bitmap_git);
++ if (nth_bitmap_object_oid(bitmap_git, &xor_item->oid, triplet.commit_pos) < 0) {
++ error(_("corrupt bitmap lookup table: commit index %u out of range"),
++ triplet.commit_pos);
++ goto corrupt;
++ }
+
-+ if (!bitmap)
-+ goto corrupt;
++ hash_pos = kh_get_oid_map(bitmap_git->bitmaps, xor_item->oid);
++
++ /*
++ * If desired bitmap is already stored, we don't need
++ * to iterate further. Because we know that bitmaps
++ * that are needed to be parsed to parse this bitmap
++ * has already been stored. So, assign this stored bitmap
++ * to the xor_bitmap.
++ */
++ if (hash_pos < kh_end(bitmap_git->bitmaps) &&
++ (xor_bitmap = kh_value(bitmap_git->bitmaps, hash_pos)))
++ break;
++ xor_items_nr++;
++ xor_row = triplet.xor_row;
++ }
+
-+ xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags);
-+ xor_items_nr--;
++ while (xor_items_nr) {
++ xor_item = &xor_items[xor_items_nr - 1];
++ bitmap_git->map_pos = xor_item->offset;
++ if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) {
++ error(_("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\""),
++ oid_to_hex(&xor_item->oid));
++ goto corrupt;
+ }
++
++ bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
++ xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
++ bitmap = read_bitmap_1(bitmap_git);
++
++ if (!bitmap)
++ goto corrupt;
++
++ xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags);
++ xor_items_nr--;
+ }
+
+ bitmap_git->map_pos = offset;
@@ pack-bitmap.c: struct include_data {
+ goto corrupt;
+ }
+
-+ bitmap_git->map_pos = bitmap_git->map_pos + sizeof(uint32_t) + sizeof(uint8_t);
++ /*
++ * Don't bother reading the commit's index position or its xor
++ * offset:
++ *
++ * - The commit's index position is irrelevant to us, since
++ * load_bitmap_entries_v1 only uses it to learn the object
++ * id which is used to compute the hashmap's key. We already
++ * have an object id, so no need to look it up again.
++ *
++ * - The xor_offset is unusable for us, since it specifies how
++ * many entries previous to ours we should look at. This
++ * makes sense when reading the bitmaps sequentially (as in
++ * load_bitmap_entries_v1()), since we can keep track of
++ * each bitmap as we read them.
++ *
++ * But it can't work for us, since the bitmap's don't have a
++ * fixed size. So we learn the position of the xor'd bitmap
++ * from the commit table (and resolve it to a bitmap in the
++ * above if-statement).
++ *
++ * Instead, we can skip ahead and immediately read the flags and
++ * ewah bitmap.
++ */
++ bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t);
+ flags = read_u8(bitmap_git->map, &bitmap_git->map_pos);
+ bitmap = read_bitmap_1(bitmap_git);
+
@@ pack-bitmap.c: struct include_data {
@@ pack-bitmap.c: void test_bitmap_walk(struct rev_info *revs)
if (revs->pending.nr != 1)
- die("you must specify exactly one commit to test");
+ die(_("you must specify exactly one commit to test"));
-- fprintf(stderr, "Bitmap v%d test (%d entries loaded)\n",
+- fprintf_ln(stderr, "Bitmap v%d test (%d entries loaded)",
- bitmap_git->version, bitmap_git->entry_count);
-+ fprintf(stderr, "Bitmap v%d test (%d entries%s)",
++ fprintf_ln(stderr, "Bitmap v%d test (%d entries%s)",
+ bitmap_git->version,
+ bitmap_git->entry_count,
+ bitmap_git->table_lookup ? "" : " loaded");
@@ pack-bitmap.c: void test_bitmap_walk(struct rev_info *revs)
struct object_id oid;
MAYBE_UNUSED void *value;
+ struct bitmap_index *bitmap_git = prepare_bitmap_git(r);
-+
+
+ if (!bitmap_git)
+ die(_("failed to load bitmap indexes"));
+
+ /*
+ * As this function is only used to print bitmap selected
+ * commits, we don't have to read the commit table.
+ */
-
- if (!bitmap_git)
- die("failed to load bitmap indexes");
-
+ if (bitmap_git->table_lookup) {
+ if (load_bitmap_entries_v1(bitmap_git) < 0)
+ die(_("failed to load bitmap indexes"));
+ }
+
kh_foreach(bitmap_git->bitmaps, oid, value, {
- printf("%s\n", oid_to_hex(&oid));
+ printf_ln("%s", oid_to_hex(&oid));
});
## pack-bitmap.h ##
5: e7ef420f321 < -: ----------- p5310-pack-bitmaps.sh: enable `pack.writeReverseIndex`
6: 6628001241d ! 6: b460516b306 bitmap-lookup-table: add performance tests for lookup table @@ Metadata
## Commit message ##
bitmap-lookup-table: add performance tests for lookup table
- Add performance tests to verify the performance of lookup table with
- pack.writeReverseIndex enabled. This is to check the performance
- when the above configuration is set.
+ Add performance tests to verify the performance of lookup table.
+ p5310-pack-bitmaps.sh contain tests with and without lookup table.
+ p5312-pack-bitmaps-revs.sh contain same tests with and without
+ lookup table but with pack.writeReverseIndex enabled.
Lookup table makes Git run faster in most of the cases. Below is the result of t/perf/p5310-pack-bitmaps.sh.perf/p5326-multi-pack-bitmaps.sh gives similar result. The repository used in the test is linux kernel.
- Test this tree
- ---------------------------------------------------------------------------
- 5310.4: repack to disk (lookup=false) 296.55(256.53+14.52)
- 5310.5: simulated clone 15.64(8.88+1.39)
- 5310.6: simulated fetch 1.65(2.75+0.20)
- 5310.7: pack to file (bitmap) 48.71(30.20+7.58)
- 5310.8: rev-list (commits) 0.61(0.41+0.08)
- 5310.9: rev-list (objects) 4.38(4.26+0.09)
- 5310.10: rev-list with tag negated via --not 0.07(0.02+0.04)
+ Test this tree
+ -----------------------------------------------------------------------
+ 5310.4: enable lookup table: false 0.01(0.00+0.00)
+ 5310.5: repack to disk 320.89(230.20+23.45)
+ 5310.6: simulated clone 14.04(5.78+1.79)
+ 5310.7: simulated fetch 1.95(3.05+0.20)
+ 5310.8: pack to file (bitmap) 44.73(20.55+7.45)
+ 5310.9: rev-list (commits) 0.78(0.46+0.10)
+ 5310.10: rev-list (objects) 4.07(3.97+0.08)
+ 5310.11: rev-list with tag negated via --not 0.06(0.02+0.03)
--all (objects)
- 5310.11: rev-list with negative tag (objects) 0.05(0.01+0.03)
- 5310.12: rev-list count with blob:none 0.08(0.03+0.04)
- 5310.13: rev-list count with blob:limit=1k 7.29(6.92+0.30)
- 5310.14: rev-list count with tree:0 0.08(0.03+0.04)
- 5310.15: simulated partial clone 9.45(8.12+0.41)
- 5310.17: clone (partial bitmap) 21.00(15.04+2.39)
- 5310.18: pack to file (partial bitmap) 47.98(38.13+5.23)
- 5310.19: rev-list with tree filter (partial bitmap) 0.70(0.07+0.20)
- 5310.22: repack to disk (lookup=true) 255.92(188.13+20.47)
- 5310.23: simulated clone 13.78(8.84+1.09)
- 5310.24: simulated fetch 0.52(0.63+0.14)
- 5310.25: pack to file (bitmap) 44.34(28.94+6.84)
- 5310.26: rev-list (commits) 0.48(0.31+0.06)
- 5310.27: rev-list (objects) 4.02(3.93+0.07)
- 5310.28: rev-list with tag negated via --not 0.04(0.00+0.03)
+ 5310.12: rev-list with negative tag (objects) 0.21(0.15+0.05)
+ 5310.13: rev-list count with blob:none 0.24(0.17+0.06)
+ 5310.14: rev-list count with blob:limit=1k 7.07(5.92+0.48)
+ 5310.15: rev-list count with tree:0 0.25(0.17+0.07)
+ 5310.16: simulated partial clone 5.67(3.28+0.64)
+ 5310.18: clone (partial bitmap) 16.05(8.34+1.86)
+ 5310.19: pack to file (partial bitmap) 59.76(27.22+7.43)
+ 5310.20: rev-list with tree filter (partial bitmap) 0.90(0.18+0.16)
+ 5310.24: enable lookup table: true 0.01(0.00+0.00)
+ 5310.25: repack to disk 319.73(229.30+23.01)
+ 5310.26: simulated clone 13.69(5.72+1.78)
+ 5310.27: simulated fetch 1.84(3.02+0.16)
+ 5310.28: pack to file (bitmap) 45.63(20.67+7.50)
+ 5310.29: rev-list (commits) 0.56(0.39+0.8)
+ 5310.30: rev-list (objects) 3.77(3.74+0.08)
+ 5310.31: rev-list with tag negated via --not 0.05(0.02+0.03)
--all (objects)
- 5310.29: rev-list with negative tag (objects) 0.04(0.00+0.03)
- 5310.30: rev-list count with blob:none 0.04(0.01+0.03)
- 5310.31: rev-list count with blob:limit=1k 6.48(6.23+0.22)
- 5310.32: rev-list count with tree:0 0.04(0.01+0.03)
- 5310.33: simulated partial clone 8.30(7.21+0.36)
- 5310.35: clone (partial bitmap) 20.34(15.00+2.41)
- 5310.36: pack to file (partial bitmap) 46.45(38.05+5.20)
- 5310.37: rev-list with tree filter (partial bitmap) 0.61(0.06+0.20)
+ 5310.32: rev-list with negative tag (objects) 0.21(0.15+0.05)
+ 5310.33: rev-list count with blob:none 0.23(0.17+0.05)
+ 5310.34: rev-list count with blob:limit=1k 6.65(5.72+0.40)
+ 5310.35: rev-list count with tree:0 0.23(0.16+0.06)
+ 5310.36: simulated partial clone 5.57(3.26+0.59)
+ 5310.38: clone (partial bitmap) 15.89(8.39+1.84)
+ 5310.39: pack to file (partial bitmap) 58.32(27.55+7.47)
+ 5310.40: rev-list with tree filter (partial bitmap) 0.73(0.18+0.15)
Test 4-15 are tested without using lookup table. Same tests are repeated in 16-30 (using lookup table).
@@ Commit message
+ ## t/perf/lib-bitmap.sh ##
+@@ t/perf/lib-bitmap.sh: test_partial_bitmap () {
+ --filter=tree:0 >/dev/null
+ '
+ }
++
++test_pack_bitmap () {
++ test_perf "repack to disk" '
++ git repack -ad
++ '
++
++ test_full_bitmap
++
++ test_expect_success "create partial bitmap state" '
++ # pick a commit to represent the repo tip in the past
++ cutoff=$(git rev-list HEAD~100 -1) &&
++ orig_tip=$(git rev-parse HEAD) &&
++
++ # now kill off all of the refs and pretend we had
++ # just the one tip
++ rm -rf .git/logs .git/refs/* .git/packed-refs &&
++ git update-ref HEAD $cutoff &&
++
++ # and then repack, which will leave us with a nice
++ # big bitmap pack of the "old" history, and all of
++ # the new history will be loose, as if it had been pushed
++ # up incrementally and exploded via unpack-objects
++ git repack -Ad &&
++
++ # and now restore our original tip, as if the pushes
++ # had happened
++ git update-ref HEAD $orig_tip
++ '
++
++ test_partial_bitmap
++}
+
## t/perf/p5310-pack-bitmaps.sh ##
-@@ t/perf/p5310-pack-bitmaps.sh: test_expect_success 'setup bitmap config' '
- git config pack.writeReverseIndex true
- '
+@@ t/perf/p5310-pack-bitmaps.sh: test_description='Tests pack performance using bitmaps'
+ . ./perf-lib.sh
+ . "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
+-test_perf_large_repo
+-
+-# note that we do everything through config,
+-# since we want to be able to compare bitmap-aware
+-# git versus non-bitmap git
+-#
+-# We intentionally use the deprecated pack.writebitmaps
+-# config so that we can test against older versions of git. +-test_expect_success 'setup bitmap config' '
+- git config pack.writebitmaps true
+-'
+-
-# we need to create the tag up front such that it is covered by the repack and -# thus by generated bitmaps.
-test_expect_success 'create tags' '
- git tag --message="tag pointing to HEAD" perf-tag HEAD
-'
-+test_bitmap () {
-+ local enabled="$1"
-
+-
-test_perf 'repack to disk' '
- git repack -ad
-'
-+ # we need to create the tag up front such that it is covered by the repack and
-+ # thus by generated bitmaps.
-+ test_expect_success 'create tags' '
-+ git tag --message="tag pointing to HEAD" perf-tag HEAD
-+ '
-
+-
-test_full_bitmap
-+ test_expect_success "use lookup table: $enabled" '
-+ git config pack.writeBitmapLookupTable '"$enabled"'
-+ '
-
+-
-test_expect_success 'create partial bitmap state' '
- # pick a commit to represent the repo tip in the past
- cutoff=$(git rev-list HEAD~100 -1) &&
- orig_tip=$(git rev-parse HEAD) &&
-+ test_perf "repack to disk (lookup=$enabled)" '
-+ git repack -ad
-+ '
-
+-
- # now kill off all of the refs and pretend we had
- # just the one tip
- rm -rf .git/logs .git/refs/* .git/packed-refs &&
- git update-ref HEAD $cutoff &&
-+ test_full_bitmap
-
+-
- # and then repack, which will leave us with a nice
- # big bitmap pack of the "old" history, and all of
- # the new history will be loose, as if it had been pushed
- # up incrementally and exploded via unpack-objects
- git repack -Ad &&
-+ test_expect_success "create partial bitmap state (lookup=$enabled)" '
-+ # pick a commit to represent the repo tip in the past
-+ cutoff=$(git rev-list HEAD~100 -1) &&
-+ orig_tip=$(git rev-parse HEAD) &&
-
+-
- # and now restore our original tip, as if the pushes
- # had happened
- git update-ref HEAD $orig_tip
-'
-+ # now kill off all of the refs and pretend we had
-+ # just the one tip
-+ rm -rf .git/logs .git/refs/* .git/packed-refs &&
-+ git update-ref HEAD $cutoff &&
+-
+-test_partial_bitmap
++test_lookup_pack_bitmap () {
++ test_expect_success 'start the test from scratch' '
++ rm -rf * .git
++ '
+
-+ # and then repack, which will leave us with a nice
-+ # big bitmap pack of the "old" history, and all of
-+ # the new history will be loose, as if it had been pushed
-+ # up incrementally and exploded via unpack-objects
-+ git repack -Ad &&
++ test_perf_large_repo
+
-+ # and now restore our original tip, as if the pushes
-+ # had happened
-+ git update-ref HEAD $orig_tip
++ # note that we do everything through config,
++ # since we want to be able to compare bitmap-aware
++ # git versus non-bitmap git
++ #
++ # We intentionally use the deprecated pack.writebitmaps
++ # config so that we can test against older versions of git.
++ test_expect_success 'setup bitmap config' '
++ git config pack.writebitmaps true
+ '
+
-+ test_partial_bitmap
++ # we need to create the tag up front such that it is covered by the repack and
++ # thus by generated bitmaps.
++ test_expect_success 'create tags' '
++ git tag --message="tag pointing to HEAD" perf-tag HEAD
++ '
++
++ test_perf "enable lookup table: $1" '
++ git config pack.writeBitmapLookupTable '"$1"'
++ '
++
++ test_pack_bitmap
+}
++
++test_lookup_pack_bitmap false
++test_lookup_pack_bitmap true
--test_partial_bitmap
-+test_bitmap false
-+test_bitmap true
+ test_done
+
+ ## t/perf/p5311-pack-bitmaps-fetch.sh ##
+@@
+ test_description='performance of fetches from bitmapped packs'
+ . ./perf-lib.sh
+
+-test_perf_default_repo
+-
+-test_expect_success 'create bitmapped server repo' '
+- git config pack.writebitmaps true &&
+- git repack -ad
+-'
+-
+-# simulate a fetch from a repository that last fetched N days ago, for +-# various values of N. We do so by following the first-parent chain, +-# and assume the first entry in the chain that is N days older than the current +-# HEAD is where the HEAD would have been then.
+-for days in 1 2 4 8 16 32 64 128; do
+- title=$(printf '%10s' "($days days)")
+- test_expect_success "setup revs from $days days ago" '
+- now=$(git log -1 --format=%ct HEAD) &&
+- then=$(($now - ($days * 86400))) &&
+- tip=$(git rev-list -1 --first-parent --until=$then HEAD) &&
+- {
+- echo HEAD &&
+- echo ^$tip
+- } >revs
++test_fetch_bitmaps () {
++ test_expect_success 'setup test directory' '
++ rm -fr * .git
+ '
+
+- test_perf "server $title" '
+- git pack-objects --stdout --revs \
+- --thin --delta-base-offset \
+- <revs >tmp.pack
+- '
++ test_perf_default_repo
+
+- test_size "size $title" '
+- wc -c <tmp.pack
++ test_expect_success 'create bitmapped server repo' '
++ git config pack.writebitmaps true &&
++ git config pack.writeBitmapLookupTable '"$1"' &&
++ git repack -ad
+ '
+
+- test_perf "client $title" '
+- git index-pack --stdin --fix-thin <tmp.pack
+- '
+-done
++ # simulate a fetch from a repository that last fetched N days ago, for
++ # various values of N. We do so by following the first-parent chain,
++ # and assume the first entry in the chain that is N days older than the current
++ # HEAD is where the HEAD would have been then.
++ for days in 1 2 4 8 16 32 64 128; do
++ title=$(printf '%10s' "($days days)")
++ test_expect_success "setup revs from $days days ago" '
++ now=$(git log -1 --format=%ct HEAD) &&
++ then=$(($now - ($days * 86400))) &&
++ tip=$(git rev-list -1 --first-parent --until=$then HEAD) &&
++ {
++ echo HEAD &&
++ echo ^$tip
++ } >revs
++ '
++
++ test_perf "server $title (lookup=$1)" '
++ git pack-objects --stdout --revs \
++ --thin --delta-base-offset \
++ <revs >tmp.pack
++ '
++
++ test_size "size $title" '
++ wc -c <tmp.pack
++ '
++
++ test_perf "client $title (lookup=$1)" '
++ git index-pack --stdin --fix-thin <tmp.pack
++ '
++ done
++}
++
++test_fetch_bitmaps true
++test_fetch_bitmaps false
test_done
+ ## t/perf/p5312-pack-bitmaps-revs.sh (new) ##
+@@
++#!/bin/sh
++
++test_description='Tests pack performance using bitmaps (rev index enabled)' ++. ./perf-lib.sh
++. "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
++
++test_lookup_pack_bitmap () {
++ test_expect_success 'start the test from scratch' '
++ rm -rf * .git
++ '
++
++ test_perf_large_repo
++
++ test_expect_success 'setup bitmap config' '
++ git config pack.writebitmaps true &&
++ git config pack.writeReverseIndex true
++ '
++
++ # we need to create the tag up front such that it is covered by the repack and
++ # thus by generated bitmaps.
++ test_expect_success 'create tags' '
++ git tag --message="tag pointing to HEAD" perf-tag HEAD
++ '
++
++ test_perf "enable lookup table: $1" '
++ git config pack.writeBitmapLookupTable '"$1"'
++ '
++
++ test_pack_bitmap
++}
++
++test_lookup_pack_bitmap false
++test_lookup_pack_bitmap true
++
++test_done
+
## t/perf/p5326-multi-pack-bitmaps.sh ##
@@ t/perf/p5326-multi-pack-bitmaps.sh: test_description='Tests performance using midx bitmaps'
+ . ./perf-lib.sh
+ . "${TEST_DIRECTORY}/perf/lib-bitmap.sh"
- test_perf_large_repo
-
+-test_perf_large_repo
+-
-# we need to create the tag up front such that it is covered by the repack and -# thus by generated bitmaps.
-test_expect_success 'create tags' '
@@ t/perf/p5326-multi-pack-bitmaps.sh: test_description='Tests performance using mi
+test_bitmap () {
+ local enabled="$1"
+
++ test_expect_success "remove existing repo (lookup=$enabled)" '
++ rm -fr * .git
++ '
++
++ test_perf_large_repo
++
+ # we need to create the tag up front such that it is covered by the repack and
+ # thus by generated bitmaps.
+ test_expect_success 'create tags' '
Signature · 1 line
gitgitgadget
PATCH v6 1/6 Documentation/technical: describe bitmap lookup table extension
From: Abhradeep Chakraborty <[email protected]>
When reading bitmap file, Git loads each and every bitmap one by one even if all the bitmaps are not required. A "bitmap lookup table" extension to the bitmap format can reduce the overhead of loading bitmaps which stores a list of bitmapped commit id pos (in the midx or pack, along with their offset and xor offset. This way Git can load only the necessary bitmaps without loading the previous bitmaps.
Older versions of Git ignore the lookup table extension and don't throw any kind of warning or error while parsing the bitmap file.
Add some information for the new "bitmap lookup table" extension in the bitmap-format documentation.
--- Documentation/technical/bitmap-format.txt | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+)
Documentation/technical/bitmap-format.txt +39 -0
@@ -72,6 +72,17 @@ MIDXs, both the bit-cache and rev-cache extensions are required. pack/MIDX. The format and meaning of the name-hash is described below. + ** {empty} + BITMAP_OPT_LOOKUP_TABLE (0x10): ::: + If present, the end of the bitmap file contains a table + containing a list of `N` <commit_pos, offset, xor_row> + triplets. The format and meaning of the table is described + below. ++ +NOTE: Unlike the xor_offset used to compress an individual bitmap, +`xor_row` stores an *absolute* index into the lookup table, not a location +relative to the current entry. + 4-byte entry count (network byte order): :: The total count of entries (bitmapped commits) in this bitmap index.
@@ -216,3 +227,31 @@ Note that this hashing scheme is tied to the BITMAP_OPT_HASH_CACHE flag. If implementations want to choose a different hashing scheme, they are free to do so, but MUST allocate a new header flag (because comparing hashes made under two different schemes would be pointless). + +Commit lookup table +------------------- + +If the BITMAP_OPT_LOOKUP_TABLE flag is set, the last `N * (4 + 8 + 4)` +bytes (preceding the name-hash cache and trailing hash) of the `.bitmap` +file contains a lookup table specifying the information needed to get +the desired bitmap from the entries without parsing previous unnecessary +bitmaps. + +For a `.bitmap` containing `nr_entries` reachability bitmaps, the table +contains a list of `nr_entries` <commit_pos, offset, xor_row> triplets +(sorted in the ascending order of `commit_pos`). The content of i'th +triplet is - + + * {empty} + commit_pos (4 byte integer, network byte order): :: + It stores the object position of a commit (in the midx or pack + index). + + * {empty} + offset (8 byte integer, network byte order): :: + The offset from which that commit's bitmap can be read. + + * {empty} + xor_row (4 byte integer, network byte order): :: + The position of the triplet whose bitmap is used to compress + this one, or `0xffffffff` if no such bitmap exists.
Signature · 1 line
gitgitgadget
PATCH v6 2/6 bitmap: move `get commit positions` code to `bitmap_writer_finish`
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
The write_selected_commits_v1 function takes care of writing commit positions along with their corresponding bitmaps in the disk. It is OK because this search commit position of a given commit algorithm is needed only once here. But in later changes of the lookup table extension series, we need same commit positions which means we have to run the above mentioned algorithm one more time.
Move the search commit position of a given commit algorithm to bitmap_writer_finish() and use the commit_positions array to get commit positions of their corresponding bitmaps.
--- pack-bitmap-write.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-)
pack-bitmap-write.c +20 -9
@@ -650,20 +650,15 @@ static const struct object_id *oid_access(size_t pos, const void *table)static void write_selected_commits_v1 (struct hashfile *f,struct pack_idx_entry **index, -uint32_t index_nr) +uint32_t index_nr, +uint32_t *commit_positions) {int i;for (i =0 ; i < writer.selected_nr; ++i) {struct bitmapped_commit *stored = &writer.selected[i]; -int commit_pos = -oid_pos (&stored->commit->object.oid, index, index_nr, oid_access); - -if (commit_pos <0 ) -BUG ("trying to write commit not in index" ); - -hashwrite_be32 (f, commit_pos); +hashwrite_be32 (f, commit_positions[i]);hashwrite_u8 (f, stored->xor_offset);hashwrite_u8 (f, stored->flags);
@@ -697,6 +692,8 @@ void bitmap_writer_finish(struct pack_idx_entry **index,static uint16_t flags =BITMAP_OPT_FULL_DAG ;struct strbuf tmp_file =STRBUF_INIT ;struct hashfile *f; +uint32_t *commit_positions =NULL ; +uint32_t i;struct bitmap_disk_header header;
@@ -715,7 +712,20 @@ void bitmap_writer_finish(struct pack_idx_entry **index,dump_bitmap (f, writer.trees);dump_bitmap (f, writer.blobs);dump_bitmap (f, writer.tags); -write_selected_commits_v1 (f, index, index_nr); + +ALLOC_ARRAY (commit_positions, writer.selected_nr); + +for (i =0 ; i < writer.selected_nr; i++) { +struct bitmapped_commit *stored = &writer.selected[i]; +int commit_pos =oid_pos (&stored->commit->object.oid, index, index_nr, oid_access); + +if (commit_pos <0 ) +BUG (_ ("trying to write commit not in index" )); + + commit_positions[i] = commit_pos; + } + +write_selected_commits_v1 (f, index, index_nr, commit_positions);if (options &BITMAP_OPT_HASH_CACHE )write_hash_cache (f, index, index_nr);
@@ -730,4 +740,5 @@ void bitmap_writer_finish(struct pack_idx_entry **index,die_errno ("unable to rename temporary bitmap file to '%s'" , filename);strbuf_release (&tmp_file); +free (commit_positions); }
Signature · 1 line
gitgitgadget
PATCH v6 3/6 pack-bitmap-write.c: write lookup table extension
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
The bitmap lookup table extension was documented by an earlier change, but Git does not yet know how to write that extension.
Teach Git to write bitmap lookup table extension. The table contains the list of N <commit_pos, offset, xor_row>` triplets. These triplets are sorted according to their commit pos (ascending order). The meaning of each data in the i'th triplet is given below:
- commit_pos stores commit position (in the pack-index or midx). It is a 4 byte network byte order unsigned integer.
- offset is the position (in the bitmap file) from which that commit's bitmap can be read.
- xor_row is the position of the triplet in the lookup table whose bitmap is used to compress this bitmap, or 0xffffffff if no such bitmap exists.
--- pack-bitmap-write.c | 91 ++++++++++++++++++++++++++++++++++++++++++++- pack-bitmap.h | 5 ++- 2 files changed, 92 insertions(+), 4 deletions(-)
pack-bitmap-write.c +89 -2
@@ -651,13 +651,17 @@ static const struct object_id *oid_access(size_t pos, const void *table)static void write_selected_commits_v1 (struct hashfile *f,struct pack_idx_entry **index,uint32_t index_nr, -uint32_t *commit_positions) +uint32_t *commit_positions, +off_t *offsets) {int i;for (i =0 ; i < writer.selected_nr; ++i) {struct bitmapped_commit *stored = &writer.selected[i]; +if (offsets) + offsets[i] =hashfile_total (f); +hashwrite_be32 (f, commit_positions[i]);hashwrite_u8 (f, stored->xor_offset);hashwrite_u8 (f, stored->flags);
@@ -666,6 +670,81 @@ static void write_selected_commits_v1(struct hashfile *f, } } +static int table_cmp (const void *_va,const void *_vb,void *_data) +{ +uint32_t *commit_positions = _data; +uint32_t a = commit_positions[*(uint32_t *)_va]; +uint32_t b = commit_positions[*(uint32_t *)_vb]; + +if (a > b) +return 1 ; +else if (a < b) +return -1 ; + +return 0 ; +} + +static void write_lookup_table (struct hashfile *f, +struct pack_idx_entry **index, +uint32_t index_nr, +uint32_t *commit_positions, +off_t *offsets) +{ +uint32_t i; +uint32_t *table, *table_inv; + +ALLOC_ARRAY (table, writer.selected_nr); +ALLOC_ARRAY (table_inv, writer.selected_nr); + +for (i =0 ; i < writer.selected_nr; i++) + table[i] = i; + +/* +* At the end of this sort table[j] = i means that the i'th +* bitmap corresponds to j'th bitmapped commit (among the selected +* commits) in lex order of OIDs. +*/ +QSORT_S (table, writer.selected_nr, table_cmp, commit_positions); + +/* table_inv helps us discover that relationship (i'th bitmap +* to j'th commit by j = table_inv[i]) +*/ +for (i =0 ; i < writer.selected_nr; i++) + table_inv[table[i]] = i; + +trace2_region_enter ("pack-bitmap-write" ,"writing_lookup_table" , the_repository); +for (i =0 ; i < writer.selected_nr; i++) { +struct bitmapped_commit *selected = &writer.selected[table[i]]; +uint32_t xor_offset = selected->xor_offset; +uint32_t xor_row; + +if (xor_offset) { +/* +* xor_index stores the index (in the bitmap entries) +* of the corresponding xor bitmap. But we need to convert +* this index into lookup table's index. So, table_inv[xor_index] +* gives us the index position w.r.t. the lookup table. +* +* If "k = table[i] - xor_offset" then the xor base is the k'th +* bitmap. `table_inv[k]` gives us the position of that bitmap +* in the lookup table. +*/ +uint32_t xor_index = table[i] - xor_offset; + xor_row = table_inv[xor_index]; + }else { + xor_row =0xffffffff ; + } + +hashwrite_be32 (f, commit_positions[table[i]]); +hashwrite_be64 (f, (uint64_t )offsets[table[i]]); +hashwrite_be32 (f, xor_row); + } +trace2_region_leave ("pack-bitmap-write" ,"writing_lookup_table" , the_repository); + +free (table); +free (table_inv); +} +static void write_hash_cache (struct hashfile *f,struct pack_idx_entry **index,uint32_t index_nr)
@@ -693,6 +772,7 @@ void bitmap_writer_finish(struct pack_idx_entry **index,struct strbuf tmp_file =STRBUF_INIT ;struct hashfile *f;uint32_t *commit_positions =NULL ; +off_t *offsets =NULL ;uint32_t i;struct bitmap_disk_header header;
@@ -713,6 +793,9 @@ void bitmap_writer_finish(struct pack_idx_entry **index,dump_bitmap (f, writer.blobs);dump_bitmap (f, writer.tags); +if (options &BITMAP_OPT_LOOKUP_TABLE ) +CALLOC_ARRAY (offsets, index_nr); +ALLOC_ARRAY (commit_positions, writer.selected_nr);for (i =0 ; i < writer.selected_nr; i++) {
@@ -725,7 +808,10 @@ void bitmap_writer_finish(struct pack_idx_entry **index, commit_positions[i] = commit_pos; } -write_selected_commits_v1 (f, index, index_nr, commit_positions); +write_selected_commits_v1 (f, index, index_nr, commit_positions, offsets); + +if (options &BITMAP_OPT_LOOKUP_TABLE ) +write_lookup_table (f, index, index_nr, commit_positions, offsets);if (options &BITMAP_OPT_HASH_CACHE )write_hash_cache (f, index, index_nr);
@@ -741,4 +827,5 @@ void bitmap_writer_finish(struct pack_idx_entry **index,strbuf_release (&tmp_file);free (commit_positions); +free (offsets); }
pack-bitmap.h +3 -2
@@ -24,8 +24,9 @@ struct bitmap_disk_header {#define NEEDS_BITMAP (1u<<22)enum pack_bitmap_opts { -BITMAP_OPT_FULL_DAG =1 , -BITMAP_OPT_HASH_CACHE =4 , +BITMAP_OPT_FULL_DAG =0x1 , +BITMAP_OPT_HASH_CACHE =0x4 , +BITMAP_OPT_LOOKUP_TABLE =0x10 , };enum pack_bitmap_flags {
Signature · 1 line
gitgitgadget
PATCH v6 4/6 pack-bitmap-write: learn pack.writeBitmapLookupTable and add tests
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Teach Git to provide a way for users to enable/disable bitmap lookup table extension by providing a config option named 'writeBitmapLookupTable'. Default is false.
Also add test to verify writting of lookup table.
--- Documentation/config/pack.txt | 7 + builtin/multi-pack-index.c | 7 + builtin/pack-objects.c | 8 + midx.c | 3 + midx.h | 1 + t/t5310-pack-bitmaps.sh | 792 ++++++++++++++++-------------- t/t5311-pack-bitmaps-shallow.sh | 53 +- t/t5326-multi-pack-bitmaps.sh | 421 +++++++++------- t/t5327-multi-pack-bitmaps-rev.sh | 24 +- 9 files changed, 733 insertions(+), 583 deletions(-)
Documentation/config/pack.txt +7 -0
@@ -164,6 +164,13 @@ When writing a multi-pack reachability bitmap, no new namehashes are computed; instead, any namehashes stored in an existing bitmap are permuted into their appropriate location when writing a new bitmap. +pack.writeBitmapLookupTable:: + When true, Git will include a "lookup table" section in the + bitmap index (if one is written). This table is used to defer + loading individual bitmaps as late as possible. This can be + beneficial in repositories that have relatively large bitmap + indexes. Defaults to false. + pack.writeReverseIndex:: When true, git will write a corresponding .rev file (see: link:../technical/pack-format.html[Documentation/technical/pack-format.txt])
builtin/multi-pack-index.c +7 -0
@@ -87,6 +87,13 @@ static int git_multi_pack_index_write_config(const char *var, const char *value, opts.flags &= ~MIDX_WRITE_BITMAP_HASH_CACHE ; } +if (!strcmp (var,"pack.writebitmaplookuptable" )) { +if (git_config_bool (var, value)) + opts.flags |=MIDX_WRITE_BITMAP_LOOKUP_TABLE ; +else + opts.flags &= ~MIDX_WRITE_BITMAP_LOOKUP_TABLE ; + } +/* * We should never make a fall-back call to 'git_default_config', since * this was already called in 'cmd_multi_pack_index()'.
builtin/pack-objects.c +8 -0
@@ -3148,6 +3148,14 @@ static int git_pack_config(const char *k, const char *v, void *cb)else write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE ; } + +if (!strcmp (k,"pack.writebitmaplookuptable" )) { +if (git_config_bool (k, v)) + write_bitmap_options |=BITMAP_OPT_LOOKUP_TABLE ; +else + write_bitmap_options &= ~BITMAP_OPT_LOOKUP_TABLE ; + } +if (!strcmp (k,"pack.usebitmaps" )) { use_bitmap_index_default =git_config_bool (k, v);return 0 ;
midx.c +3 -0
@@ -1070,6 +1070,9 @@ static int write_midx_bitmap(const char *midx_name,if (flags &MIDX_WRITE_BITMAP_HASH_CACHE ) options |=BITMAP_OPT_HASH_CACHE ; +if (flags &MIDX_WRITE_BITMAP_LOOKUP_TABLE ) + options |=BITMAP_OPT_LOOKUP_TABLE ; +/* * Build the MIDX-order index based on pdata.objects (which is already * in MIDX order; c.f., 'midx_pack_order_cmp()' for the definition of
midx.h +1 -0
@@ -47,6 +47,7 @@ struct multi_pack_index {#define MIDX_WRITE_REV_INDEX (1 << 1)#define MIDX_WRITE_BITMAP (1 << 2)#define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3) +#define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)const unsigned char *get_midx_checksum (struct multi_pack_index *m);void get_midx_filename (struct strbuf *out,const char *object_dir);
t/t5310-pack-bitmaps.sh +410 -382
807 lines not on this page · raw message
t/t5311-pack-bitmaps-shallow.sh +35 -18
58 lines not on this page · raw message
t/t5326-multi-pack-bitmaps.sh +240 -181
513 lines not on this page · raw message
t/t5327-multi-pack-bitmaps-rev.sh +22 -2
@@ -17,7 +17,27 @@ GIT_TEST_MIDX_READ_RIDX=0 export GIT_TEST_MIDX_WRITE_REV export GIT_TEST_MIDX_READ_RIDX -midx_bitmap_core rev -midx_bitmap_partial_tests rev +test_midx_bitmap_rev () { + writeLookupTable=false + + for i in "$@" + do + case $i in + "pack.writeBitmapLookupTable") writeLookupTable=true;; + esac + done + + test_expect_success 'setup bitmap config' ' + rm -rf * .git && + git init && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' + ' + + midx_bitmap_core rev + midx_bitmap_partial_tests rev +} + +test_midx_bitmap_rev +test_midx_bitmap_rev "pack.writeBitmapLookupTable" test_done
Signature · 1 line
gitgitgadget
PATCH v6 5/6 pack-bitmap: prepare to read lookup table extension
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Earlier change teaches Git to write bitmap lookup table. But Git does not know how to parse them.
Teach Git to parse the existing bitmap lookup table. The older versions of Git are not affected by it. Those versions ignore the lookup table.
--- pack-bitmap.c | 290 ++++++++++++++++++++++++++++++++++++++-- pack-bitmap.h | 9 ++ t/t5310-pack-bitmaps.sh | 22 +++ 3 files changed, 312 insertions(+), 9 deletions(-)
pack-bitmap.c +281 -9
@@ -83,6 +83,12 @@ struct bitmap_index {/* The checksum of the packfile or MIDX; points into map. */ const unsigned char *checksum; +/* +* If not NULL, this point into the commit table extension +* (within the memory mapped region `map`). +*/ +unsigned char *table_lookup; +/* * Extended index. *
@@ -186,6 +192,16 @@ static int load_bitmap_header(struct bitmap_index *index) index->hashes = (void *)(index_end - cache_size); index_end -= cache_size; } + +if (flags &BITMAP_OPT_LOOKUP_TABLE ) { +size_t table_size =st_mult (ntohl (header->entry_count), +BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH ); +if (table_size > index_end - index->map - header_size) +return error (_ ("corrupted bitmap index file (too short to fit lookup table)" )); +if (git_env_bool ("GIT_TEST_READ_COMMIT_TABLE" ,1 )) + index->table_lookup = (void *)(index_end - table_size); + index_end -= table_size; + } } index->entry_count =ntohl (header->entry_count);
@@ -212,9 +228,11 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index, hash_pos =kh_put_oid_map (index->bitmaps, stored->oid, &ret); -/* a 0 return code means the insertion succeeded with no changes, -* because the SHA1 already existed on the map. this is bad, there -* shouldn't be duplicated commits in the index */ +/* +* A 0 return code means the insertion succeeded with no changes, +* because the SHA1 already existed on the map. This is bad, there +* shouldn't be duplicated commits in the index. +*/ if (ret ==0 ) {error (_ ("duplicate entry in bitmap index: '%s'" ),oid_to_hex (oid));return NULL ;
@@ -482,7 +500,7 @@ static int load_bitmap(struct bitmap_index *bitmap_git) !(bitmap_git->tags = read_bitmap_1(bitmap_git))) goto failed; -if (load_bitmap_entries_v1 (bitmap_git) <0 ) +if (!bitmap_git->table_lookup &&load_bitmap_entries_v1 (bitmap_git) <0 ) goto failed;return 0 ;
@@ -570,13 +588,256 @@ struct include_data {struct bitmap *seen; }; +struct bitmap_lookup_table_triplet { +uint32_t commit_pos; +uint64_t offset; +uint32_t xor_row; +}; + +struct bitmap_lookup_table_xor_item { +struct object_id oid; +uint64_t offset; +}; + +/* +* Given a `triplet` struct pointer and pointer `p`, this +* function reads the triplet beginning at `p` into the struct. +* Note that this function assumes that there is enough memory +* left for filling the `triplet` struct from `p`. +*/ +static int bitmap_lookup_table_get_triplet_by_pointer (struct bitmap_lookup_table_triplet *triplet, +const unsigned char *p) +{ +if (!triplet) +return -1 ; + + triplet->commit_pos =get_be32 (p); + p +=sizeof (uint32_t ); + triplet->offset =get_be64 (p); + p +=sizeof (uint64_t ); + triplet->xor_row =get_be32 (p); +return 0 ; +} + +/* +* This function gets the raw triplet from `row`'th row in the +* lookup table and fills that data to the `triplet`. +*/ +static int bitmap_lookup_table_get_triplet (struct bitmap_index *bitmap_git, +uint32_t pos, +struct bitmap_lookup_table_triplet *triplet) +{ +unsigned char *p =NULL ; +if (pos >= bitmap_git->entry_count) +return error (_ ("corrupt bitmap lookup table: triplet position out of index" )); + + p = bitmap_git->table_lookup +st_mult (pos,BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH ); + +return bitmap_lookup_table_get_triplet_by_pointer (triplet, p); +} + +/* +* Searches for a matching triplet. `commit_pos` is a pointer +* to the wanted commit position value. `table_entry` points to +* a triplet in lookup table. The first 4 bytes of each +* triplet (pointed by `table_entry`) are compared with `*commit_pos`. +*/ +static int triplet_cmp (const void *commit_pos,const void *table_entry) +{ + +uint32_t a = *(uint32_t *)commit_pos; +uint32_t b =get_be32 (table_entry); +if (a > b) +return 1 ; +else if (a < b) +return -1 ; + +return 0 ; +} + +static uint32_t bitmap_bsearch_pos (struct bitmap_index *bitmap_git, +struct object_id *oid, +uint32_t *result) +{ +int found; + +if (bitmap_is_midx (bitmap_git)) + found =bsearch_midx (oid, bitmap_git->midx, result); +else + found =bsearch_pack (oid, bitmap_git->pack, result); + +return found; +} + +/* +* `bsearch_triplet_by_pos` function searches for the raw triplet +* having commit position same as `commit_pos` and fills `triplet` +* object from the raw triplet. Returns 1 on success and 0 on +* failure. +*/ +static int bitmap_bsearch_triplet_by_pos (uint32_t commit_pos, +struct bitmap_index *bitmap_git, +struct bitmap_lookup_table_triplet *triplet) +{ +unsigned char *p =bsearch (&commit_pos, bitmap_git->table_lookup, bitmap_git->entry_count, +BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH , triplet_cmp); + +if (!p) +return -1 ; + +return bitmap_lookup_table_get_triplet_by_pointer (triplet, p); +} + +static struct stored_bitmap *lazy_bitmap_for_commit (struct bitmap_index *bitmap_git, +struct commit *commit) +{ +uint32_t commit_pos, xor_row; +uint64_t offset; +int flags; +struct bitmap_lookup_table_triplet triplet; +struct object_id *oid = &commit->object.oid; +struct ewah_bitmap *bitmap; +struct stored_bitmap *xor_bitmap =NULL ; +const int bitmap_header_size =6 ; +static struct bitmap_lookup_table_xor_item *xor_items =NULL ; +static size_t xor_items_nr =0 , xor_items_alloc =0 ; +static int is_corrupt =0 ; +int xor_flags; +khiter_t hash_pos; +struct bitmap_lookup_table_xor_item *xor_item; + +if (is_corrupt) +return NULL ; + +if (!bitmap_bsearch_pos (bitmap_git, oid, &commit_pos)) +return NULL ; + +if (bitmap_bsearch_triplet_by_pos (commit_pos, bitmap_git, &triplet) <0 ) +return NULL ; + + xor_items_nr =0 ; + offset = triplet.offset; + xor_row = triplet.xor_row; + +while (xor_row !=0xffffffff ) { +ALLOC_GROW (xor_items, xor_items_nr +1 , xor_items_alloc); + +if (xor_items_nr +1 >= bitmap_git->entry_count) { +error (_ ("corrupt bitmap lookup table: xor chain exceed entry count" )); + goto corrupt; + } + +if (bitmap_lookup_table_get_triplet (bitmap_git, xor_row, &triplet) <0 ) + goto corrupt; + + xor_item = &xor_items[xor_items_nr]; + xor_item->offset = triplet.offset; + +if (nth_bitmap_object_oid (bitmap_git, &xor_item->oid, triplet.commit_pos) <0 ) { +error (_ ("corrupt bitmap lookup table: commit index %u out of range" ), + triplet.commit_pos); + goto corrupt; + } + + hash_pos =kh_get_oid_map (bitmap_git->bitmaps, xor_item->oid); + +/* +* If desired bitmap is already stored, we don't need +* to iterate further. Because we know that bitmaps +* that are needed to be parsed to parse this bitmap +* has already been stored. So, assign this stored bitmap +* to the xor_bitmap. +*/ +if (hash_pos <kh_end (bitmap_git->bitmaps) && + (xor_bitmap =kh_value (bitmap_git->bitmaps, hash_pos))) +break ; + xor_items_nr++; + xor_row = triplet.xor_row; + } + +while (xor_items_nr) { + xor_item = &xor_items[xor_items_nr -1 ]; + bitmap_git->map_pos = xor_item->offset; +if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) { +error (_ ("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" ), +oid_to_hex (&xor_item->oid)); + goto corrupt; + } + + bitmap_git->map_pos +=sizeof (uint32_t ) +sizeof (uint8_t ); + xor_flags =read_u8 (bitmap_git->map, &bitmap_git->map_pos); + bitmap =read_bitmap_1 (bitmap_git); + +if (!bitmap) + goto corrupt; + + xor_bitmap =store_bitmap (bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags); + xor_items_nr--; + } + + bitmap_git->map_pos = offset; +if (bitmap_git->map_size - bitmap_git->map_pos < bitmap_header_size) { +error (_ ("corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" ), +oid_to_hex (oid)); + goto corrupt; + } + +/* +* Don't bother reading the commit's index position or its xor +* offset: +* +* - The commit's index position is irrelevant to us, since +* load_bitmap_entries_v1 only uses it to learn the object +* id which is used to compute the hashmap's key. We already +* have an object id, so no need to look it up again. +* +* - The xor_offset is unusable for us, since it specifies how +* many entries previous to ours we should look at. This +* makes sense when reading the bitmaps sequentially (as in +* load_bitmap_entries_v1()), since we can keep track of +* each bitmap as we read them. +* +* But it can't work for us, since the bitmap's don't have a +* fixed size. So we learn the position of the xor'd bitmap +* from the commit table (and resolve it to a bitmap in the +* above if-statement). +* +* Instead, we can skip ahead and immediately read the flags and +* ewah bitmap. +*/ + bitmap_git->map_pos +=sizeof (uint32_t ) +sizeof (uint8_t ); + flags =read_u8 (bitmap_git->map, &bitmap_git->map_pos); + bitmap =read_bitmap_1 (bitmap_git); + +if (!bitmap) + goto corrupt; + +return store_bitmap (bitmap_git, bitmap, oid, xor_bitmap, flags); + +corrupt: +free (xor_items); + is_corrupt =1 ; +return NULL ; +} +struct ewah_bitmap *bitmap_for_commit (struct bitmap_index *bitmap_git,struct commit *commit) {khiter_t hash_pos =kh_get_oid_map (bitmap_git->bitmaps, commit->object.oid); -if (hash_pos >=kh_end (bitmap_git->bitmaps)) -return NULL ; +if (hash_pos >=kh_end (bitmap_git->bitmaps)) { +struct stored_bitmap *bitmap =NULL ; +if (!bitmap_git->table_lookup) +return NULL ; + +trace2_region_enter ("pack-bitmap" ,"reading_lookup_table" , the_repository); +/* NEEDSWORK: cache misses aren't recorded */ + bitmap =lazy_bitmap_for_commit (bitmap_git, commit); +trace2_region_leave ("pack-bitmap" ,"reading_lookup_table" , the_repository); +if (!bitmap) +return NULL ; +return lookup_stored_bitmap (bitmap); + }return lookup_stored_bitmap (kh_value (bitmap_git->bitmaps, hash_pos)); }
@@ -1712,8 +1973,10 @@ void test_bitmap_walk(struct rev_info *revs)if (revs->pending.nr !=1 )die (_ ("you must specify exactly one commit to test" )); -fprintf_ln (stderr,"Bitmap v%d test (%d entries loaded)" , - bitmap_git->version, bitmap_git->entry_count); +fprintf_ln (stderr,"Bitmap v%d test (%d entries%s)" , + bitmap_git->version, + bitmap_git->entry_count, + bitmap_git->table_lookup ?"" :" loaded" ); root = revs->pending.objects[0 ].item; bm =bitmap_for_commit (bitmap_git, (struct commit *)root);
@@ -1766,13 +2029,22 @@ void test_bitmap_walk(struct rev_info *revs)int test_bitmap_commits (struct repository *r) { -struct bitmap_index *bitmap_git =prepare_bitmap_git (r);struct object_id oid; MAYBE_UNUSED void *value; +struct bitmap_index *bitmap_git =prepare_bitmap_git (r);if (!bitmap_git)die (_ ("failed to load bitmap indexes" )); +/* +* As this function is only used to print bitmap selected +* commits, we don't have to read the commit table. +*/ +if (bitmap_git->table_lookup) { +if (load_bitmap_entries_v1 (bitmap_git) <0 ) +die (_ ("failed to load bitmap indexes" )); + } +kh_foreach (bitmap_git->bitmaps, oid, value, {printf_ln ("%s" ,oid_to_hex (&oid)); });
pack-bitmap.h +9 -0
@@ -23,6 +23,15 @@ struct bitmap_disk_header {#define NEEDS_BITMAP (1u<<22) +/* +* The width in bytes of a single triplet in the lookup table +* extension: +* (commit_pos, offset, xor_row) +* +* whose fields ar 32-, 64-, 32- bits wide, respectively. +*/ +#define BITMAP_LOOKUP_TABLE_TRIPLET_WIDTH (16) +enum pack_bitmap_opts {BITMAP_OPT_FULL_DAG =0x1 ,BITMAP_OPT_HASH_CACHE =0x4 ,
t/t5310-pack-bitmaps.sh +22 -0
@@ -258,6 +258,7 @@ test_bitmap_cases () { test_expect_success 'truncated bitmap fails gracefully (ewah)' ' test_config pack.writebitmaphashcache false && + test_config pack.writebitmaplookuptable false && git repack -ad && git rev-list --use-bitmap-index --count --all >expect && bitmap=$(ls .git/objects/pack/*.bitmap) &&
@@ -270,6 +271,7 @@ test_bitmap_cases () { ' test_expect_success 'truncated bitmap fails gracefully (cache)' ' + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && git repack -ad && git rev-list --use-bitmap-index --count --all >expect && bitmap=$(ls .git/objects/pack/*.bitmap) &&
@@ -453,4 +455,24 @@ test_expect_success 'verify writing bitmap lookup table when enabled' ' grep "\"label\":\"writing_lookup_table\"" trace2 ' +test_expect_success 'lookup table is actually used to traverse objects' ' + git repack -adb && + GIT_TRACE2_EVENT="$(pwd)/trace3" \ + git rev-list --use-bitmap-index --count --all && + grep "\"label\":\"reading_lookup_table\"" trace3 +' + +test_expect_success 'truncated bitmap fails gracefully (lookup table)' ' + test_config pack.writebitmaphashcache false && + git repack -adb && + git rev-list --use-bitmap-index --count --all >expect && + bitmap=$(ls .git/objects/pack/*.bitmap) && + test_when_finished "rm -f $bitmap" && + test_copy_bytes 512 <$bitmap >$bitmap.tmp && + mv -f $bitmap.tmp $bitmap && + git rev-list --use-bitmap-index --count --all >actual 2>stderr && + test_cmp expect actual && + test_i18ngrep corrupted.bitmap.index stderr +' + test_done
Signature · 1 line
gitgitgadget
PATCH v6 6/6 bitmap-lookup-table: add performance tests for lookup table
In reply to Abhradeep Chakraborty via GitGitGadgetFrom: Abhradeep Chakraborty <[email protected]>
Add performance tests to verify the performance of lookup table. p5310-pack-bitmaps.sh contain tests with and without lookup table. p5312-pack-bitmaps-revs.sh contain same tests with and without lookup table but with pack.writeReverseIndex enabled.
Lookup table makes Git run faster in most of the cases. Below is the result of t/perf/p5310-pack-bitmaps.sh.perf/p5326-multi-pack-bitmaps.sh gives similar result. The repository used in the test is linux kernel.
Test this tree
-----------------------------------------------------------------------
5310.4: enable lookup table: false 0.01(0.00+0.00)
5310.5: repack to disk 320.89(230.20+23.45)
5310.6: simulated clone 14.04(5.78+1.79)
5310.7: simulated fetch 1.95(3.05+0.20)
5310.8: pack to file (bitmap) 44.73(20.55+7.45)
5310.9: rev-list (commits) 0.78(0.46+0.10)
5310.10: rev-list (objects) 4.07(3.97+0.08)
5310.11: rev-list with tag negated via --not 0.06(0.02+0.03)
--all (objects)
5310.12: rev-list with negative tag (objects) 0.21(0.15+0.05)
5310.13: rev-list count with blob:none 0.24(0.17+0.06)
5310.14: rev-list count with blob:limit=1k 7.07(5.92+0.48)
5310.15: rev-list count with tree:0 0.25(0.17+0.07)
5310.16: simulated partial clone 5.67(3.28+0.64)
5310.18: clone (partial bitmap) 16.05(8.34+1.86)
5310.19: pack to file (partial bitmap) 59.76(27.22+7.43)
5310.20: rev-list with tree filter (partial bitmap) 0.90(0.18+0.16)
5310.24: enable lookup table: true 0.01(0.00+0.00)
5310.25: repack to disk 319.73(229.30+23.01)
5310.26: simulated clone 13.69(5.72+1.78)
5310.27: simulated fetch 1.84(3.02+0.16)
5310.28: pack to file (bitmap) 45.63(20.67+7.50)
5310.29: rev-list (commits) 0.56(0.39+0.8)
5310.30: rev-list (objects) 3.77(3.74+0.08)
5310.31: rev-list with tag negated via --not 0.05(0.02+0.03)
--all (objects)
5310.32: rev-list with negative tag (objects) 0.21(0.15+0.05)
5310.33: rev-list count with blob:none 0.23(0.17+0.05)
5310.34: rev-list count with blob:limit=1k 6.65(5.72+0.40)
5310.35: rev-list count with tree:0 0.23(0.16+0.06)
5310.36: simulated partial clone 5.57(3.26+0.59)
5310.38: clone (partial bitmap) 15.89(8.39+1.84)
5310.39: pack to file (partial bitmap) 58.32(27.55+7.47)
5310.40: rev-list with tree filter (partial bitmap) 0.73(0.18+0.15)Test 4-15 are tested without using lookup table. Same tests are repeated in 16-30 (using lookup table).
--- t/perf/lib-bitmap.sh | 31 +++++++++ t/perf/p5310-pack-bitmaps.sh | 78 +++++++++------------- t/perf/p5311-pack-bitmaps-fetch.sh | 74 ++++++++++++--------- t/perf/p5312-pack-bitmaps-revs.sh | 35 ++++++++++ t/perf/p5326-multi-pack-bitmaps.sh | 103 +++++++++++++++++------------ 5 files changed, 199 insertions(+), 122 deletions(-) create mode 100755 t/perf/p5312-pack-bitmaps-revs.sh
t/perf/lib-bitmap.sh +31 -0
@@ -67,3 +67,34 @@ test_partial_bitmap () { --filter=tree:0 >/dev/null ' } + +test_pack_bitmap () { + test_perf "repack to disk" ' + git repack -ad + ' + + test_full_bitmap + + test_expect_success "create partial bitmap state" ' + # pick a commit to represent the repo tip in the past + cutoff=$(git rev-list HEAD~100 -1) && + orig_tip=$(git rev-parse HEAD) && + + # now kill off all of the refs and pretend we had + # just the one tip + rm -rf .git/logs .git/refs/* .git/packed-refs && + git update-ref HEAD $cutoff && + + # and then repack, which will leave us with a nice + # big bitmap pack of the "old" history, and all of + # the new history will be loose, as if it had been pushed + # up incrementally and exploded via unpack-objects + git repack -Ad && + + # and now restore our original tip, as if the pushes + # had happened + git update-ref HEAD $orig_tip + ' + + test_partial_bitmap +}
t/perf/p5310-pack-bitmaps.sh +32 -46
83 lines not on this page · raw message
t/perf/p5311-pack-bitmaps-fetch.sh +42 -32
84 lines not on this page · raw message
t/perf/p5312-pack-bitmaps-revs.sh new file +35 -0
@@ -0,0 +1,35 @@ +#!/bin/sh + +test_description='Tests pack performance using bitmaps (rev index enabled)' +. ./perf-lib.sh +. "${TEST_DIRECTORY}/perf/lib-bitmap.sh" + +test_lookup_pack_bitmap () { + test_expect_success 'start the test from scratch' ' + rm -rf * .git + ' + + test_perf_large_repo + + test_expect_success 'setup bitmap config' ' + git config pack.writebitmaps true && + git config pack.writeReverseIndex true + ' + + # we need to create the tag up front such that it is covered by the repack and + # thus by generated bitmaps. + test_expect_success 'create tags' ' + git tag --message="tag pointing to HEAD" perf-tag HEAD + ' + + test_perf "enable lookup table: $1" ' + git config pack.writeBitmapLookupTable '"$1"' + ' + + test_pack_bitmap +} + +test_lookup_pack_bitmap false +test_lookup_pack_bitmap true + +test_done
t/perf/p5326-multi-pack-bitmaps.sh +59 -44
108 lines not on this page · raw message
Signature · 1 line
gitgitgadget
"Abhradeep Chakraborty via GitGitGadget" <[email protected]>
Quoted 7 lines · writes:
When parsing the .bitmap file, git loads all the bitmaps one by one even if some of the bitmaps are not necessary. We can remove this overhead by loading only the necessary bitmaps. A look up table extension can solve this issue.
Changes since v5:
Quoted 7 lines
As the failure in the test case is not due to this code, I think it makes no sense to delay the patch further.
* The performance test changes were not accurate as the second
test_bitmap_casescall using the repo built for the previous call. This version fixes that.
* Taylor suggested some minor changes. Those are addressed in this version.
The discussion on v5 was quite active, but we haven't seen any traffic on this round. Is everybody happy with what we see here?
Hi Junio,
Quoted 13 lines · Junio C Hamano
"Abhradeep Chakraborty via GitGitGadget" <[email protected]>
Quoted 10 lines · writes:
When parsing the .bitmap file, git loads all the bitmaps one by one even if some of the bitmaps are not necessary. We can remove this overhead by loading only the necessary bitmaps. A look up table extension can solve this issue.
Changes since v5:
As the failure in the test case is not due to this code, I think it makes no sense to delay the patch further.
Quoted 7 lines
Quoted 4 lines
* The performance test changes were not accurate as the second
test_bitmap_casescall using the repo built for the previous call. This version fixes that.
* Taylor suggested some minor changes. Those are addressed in this version.The discussion on v5 was quite active, but we haven't seen any traffic on this round. Is everybody happy with what we see here?
The part of the lively discussion in which I participated exclusively focused on the failed CI runs and trying to get to the bottom of this bug.
Taylor contributed <[email protected]> to address the bug. While he seems grateful for my help, I am honestly puzzled because I lack too much knowledge about the code to have been of assistance in any meaningful way.
My participation in this thread should not be mistaken for a review: I am woefully unfamiliar with the bitmap design (let alone code) and would therefore not _dare_ to offer anything that I would claim is a code review.
Ciao,
Dscho
Quoted 4 lines · Johannes Schindelin
Taylor contributed <[email protected]> to address the bug. While he seems grateful for my help, I am honestly puzzled because I lack too much knowledge about the code to have been of assistance in any meaningful way.
I was grateful ;-). Your contributions were quite helpful, especially making the bug more easily reproducible (doubly so since that test *could* have failed on master since its introduction, but didn't).
Pinning down some of the effects of the bug and documenting those were helpful, too.
Quoted 4 lines
My participation in this thread should not be mistaken for a review: I am woefully unfamiliar with the bitmap design (let alone code) and would therefore not _dare_ to offer anything that I would claim is a code review.
Reviewing Abhradeep's patches are on my list of things to get to, hopefully today. I had hoped to get to it last week after getting back from vacation, but was stymied by the aforementioned bug.
Thanks,
Taylor
Hi Abhradeep,
Quoted 9 lines · Abhradeep Chakraborty via GitGitGadget
Changes since v5:
As the failure in the test case is not due to this code, I think it makes no sense to delay the patch further.
* The performance test changes were not accurate as the second
test_bitmap_casescall using the repo built for the previous call. This version fixes that.
* Taylor suggested some minor changes. Those are addressed in this version.
Apologies for my slow reaction time reviewing this series. Between looking at that preferred pack bug you and Dscho spotted to catching up after my vacation, it has taken me longer than I wanted to to take a look at this.
I read through v6 carefully and am happy with the current state of things. I think there are some small incremental clean-ups that we could do on top, but they need not block this series, especially since the new code is made opt-in behind a configuration knob.
This series all looks great to me, and the performance numbers that you achieved at the end are a nice payoff for all of your hard work. Well done!
Thanks,
Taylor
Quoted 5 lines · Taylor Blau
This series all looks great to me, and the performance numbers that you achieved at the end are a nice payoff for all of your hard work. Well done!
Reviewed-by Taylor Blau <[email protected]>
Thanks, both.