Skip to content

Commit 320572c

Browse files
pks-tgitster
authored andcommitted
packfile: explain ordering of how we look up auxiliary pack files
When adding a packfile to an object database we perform four syscalls: - Three calls to access(3p) are done to check for auxiliary data structures. - One call to stat(3p) is done to check for the ".pack" itself. One curious bit is that we perform the access(3p) calls before checking for the packfile itself, but if the packfile doesn't exist we discard all results. The access(3p) calls are thus essentially wasted, so one may be triggered to reorder those calls so that we can short-circuit the other syscalls in case the packfile does not exist. The order in which we look up files is quite important though to help avoid races: - When installing a packfile we move auxiliary data structures into place before we install the ".idx" file. - When deleting a packfile we first delete the ".idx" and ".pack" files before deleting auxiliary data structures. As such, to avoid any races with concurrently created or deleted packs we need to make sure that we _first_ read auxiliary data structures before we read the corresponding ".idx" or ".pack" file. Otherwise it may easily happen that we return a populated but misclassified pack. Add a comment to `add_packed_git()` to make future readers aware of this ordering requirement. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8613c2b commit 320572c

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

packfile.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,17 @@ struct packed_git *add_packed_git(struct repository *r, const char *path,
737737
p = alloc_packed_git(r, alloc);
738738
memcpy(p->pack_name, path, path_len);
739739

740+
/*
741+
* Note that we have to check auxiliary data structures before we check
742+
* for the ".pack" file to exist to avoid races with a packfile that is
743+
* in the process of being deleted. The ".pack" file is unlinked before
744+
* its auxiliary data structures, so we know that we either get a
745+
* consistent snapshot of all data structures or that we'll fail to
746+
* stat(3p) the packfile itself and thus return `NULL`.
747+
*
748+
* As such, we cannot bail out before the access(3p) calls in case the
749+
* packfile doesn't exist without doing two stat(3p) calls for it.
750+
*/
740751
xsnprintf(p->pack_name + path_len, alloc - path_len, ".keep");
741752
if (!access(p->pack_name, F_OK))
742753
p->pack_keep = 1;

0 commit comments

Comments
 (0)