From: "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, me@ttaylorr.com,
Derrick Stolee <derrickstolee@github.com>,
Derrick Stolee <derrickstolee@github.com>
Subject: [PATCH] repack: only repack .packs that exist
Date: Tue, 20 Jun 2023 19:03:02 +0000 [thread overview]
Message-ID: <pull.1546.git.1687287782439.gitgitgadget@gmail.com> (raw)
From: Derrick Stolee <derrickstolee@github.com>
In 73320e49add (builtin/repack.c: only collect fully-formed packs,
2023-06-07), we switched the check for which packs to collect by
starting at the .idx files and looking for matching .pack files. This
avoids trying to repack pack-files that have not had their pack-indexes
installed yet.
However, it does cause maintenance to halt if we find the (problematic,
but not insurmountable) case of a .idx file without a corresponding
.pack file. In an environment where packfile maintenance is a critical
function, such a hard stop is costly and requires human intervention to
resolve (by deleting the .idx file).
This was not the case before. We successfully repacked through this
scenario until the recent change to scan for .idx files.
Further, if we are actually in a case where objects are missing, we
detect this at a different point during the reachability walk.
In other cases, Git prepares its list of packfiles by scanning .idx
files and then only adds it to the packfile list if the corresponding
.pack file exists. It even does so without a warning! (See
add_packed_git() in packfile.c for details.)
This case is much less likely to occur than the failures seen before
73320e49add. Packfiles are "installed" by writing the .pack file before
the .idx and that process can be interrupted. Packfiles _should_ be
deleted by deleting the .idx first, followed by the .pack file, but
unlink_pack_path() does not do this: it deletes the .pack _first_,
allowing a window where this process could be interrupted. We leave the
consideration of changing this order as a separate concern. Knowing that
this condition is possible from interrupted Git processes and not other
tools lends some weight that Git should be more flexible around this
scenario.
Add a check to see if the .pack file exists before adding it to the list
for repacking. This will stop a number of maintenance failures seen in
production but fixed by deleting the .idx files.
This brings us closer to the case before 73320e49add in that 'git
repack' will not fail when there is an orphaned .idx file, at least, not
due to the way we scan for packfiles. In the case that the .pack file
was erroneously deleted without copies of its objects in other installed
packfiles, then 'git repack' will fail due to the reachable object walk.
This does resolve the case where automated repacks will no longer be
halted on this case. The tests in t7700 show both these successful
scenarios and the case of failing if the .pack was truly required.
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
---
[RFC] repack: only repack .packs that exist
This is based on tb/collect-pack-filenames-fix.
This is an RFC since there is some internal disagreement as to whether
this is a safe scenario to "ignore" during a repack.
I'm of the opinion that blocking on the case where there are no missing
objects is unnecessary noise, and matches our behavior before the change
to scan for '.idx' files.
I'm submitting this to the list to gather more opinions about the safety
and/or necessity of this change before moving forward with a full
review.
This is related to the deletion of .packs before .idx files that I
submitted as [1]
[1]
https://lore.kernel.org/git/pull.1547.git.1687287675248.gitgitgadget@gmail.com
Thanks, -Stolee
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1546%2Fderrickstolee%2Frepack-ignore-idx-no-pack-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1546/derrickstolee/repack-ignore-idx-no-pack-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1546
builtin/repack.c | 3 +++
t/t7700-repack.sh | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/builtin/repack.c b/builtin/repack.c
index 1e21a21ea82..b1695c9b2eb 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -123,6 +123,9 @@ static void collect_pack_filenames(struct string_list *fname_nonkept_list,
strbuf_add(&buf, e->d_name, len);
strbuf_addstr(&buf, ".pack");
+ if (!file_exists(mkpath("%s/%s", packdir, buf.buf)))
+ continue;
+
for (i = 0; i < extra_keep->nr; i++)
if (!fspathcmp(buf.buf, extra_keep->items[i].string))
break;
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 08b5ba0c150..e780efe5e0c 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -239,6 +239,10 @@ test_expect_success 'repack --keep-pack' '
mv "$from" "$to" || return 1
done &&
+ # A .idx file without a .pack should not stop us from
+ # repacking what we can.
+ touch .git/objects/pack/pack-does-not-exist.idx &&
+
git repack --cruft -d --keep-pack $P1 --keep-pack $P4 &&
ls .git/objects/pack/*.pack >newer-counts &&
@@ -247,6 +251,36 @@ test_expect_success 'repack --keep-pack' '
)
'
+test_expect_success 'repacking fails when missing .pack actually means missing objects' '
+ test_create_repo idx-without-pack &&
+ (
+ cd idx-without-pack &&
+
+ # Avoid producing difference packs to delta/base choices
+ git config pack.window 0 &&
+ P1=$(commit_and_pack 1) &&
+ P2=$(commit_and_pack 2) &&
+ P3=$(commit_and_pack 3) &&
+ P4=$(commit_and_pack 4) &&
+ ls .git/objects/pack/*.pack >old-counts &&
+ test_line_count = 4 old-counts &&
+
+ # Remove one .pack file
+ rm .git/objects/pack/$P2 &&
+
+ ls .git/objects/pack >before-pack-dir &&
+
+ test_must_fail git fsck &&
+ test_must_fail git repack --cruft -d 2>err &&
+ grep "bad object" err &&
+
+ # Before failing, the repack did not modify the
+ # pack directory.
+ ls .git/objects/pack >after-pack-dir &&
+ test_cmp before-pack-dir after-pack-dir
+ )
+'
+
test_expect_success 'bitmaps are created by default in bare repos' '
git clone --bare .git bare.git &&
rm -f bare.git/objects/pack/*.bitmap &&
base-commit: 73320e49add4b56aba9bf5236a216498fa8ccc22
--
gitgitgadget
next reply other threads:[~2023-06-20 19:03 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-20 19:03 Derrick Stolee via GitGitGadget [this message]
2023-06-21 9:01 ` [PATCH] repack: only repack .packs that exist Taylor Blau
2023-06-27 7:54 ` Jeff King
2023-06-29 9:24 ` Taylor Blau
2023-07-02 13:11 ` Jeff King
2023-07-10 19:39 ` Taylor Blau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.1546.git.1687287782439.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=derrickstolee@github.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=me@ttaylorr.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).