summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2019-02-15 04:43:30 -0500
committerJeff King <peff@peff.net>2019-02-15 04:43:30 -0500
commit5df823f02fc6f6a5e50aa303b13021cf021a7b61 (patch)
tree2acebad539ac425ca18cba47f97e508a4927a2ab
parent83d40605047577988b95bae2f048abe2eea6192a (diff)
downloadlibgit2-packed-refs-race.tar.gz
refdb_fs: load packed-refs only when necessarypacked-refs-race
When checking if a ref exists, we load the packed-refs file and then return true if the ref is found either loose or in the packed-refs cache. This is subject to the same race described in the previous commit, where a simultaneous pack-refs may migrate a ref from loose to packed and cause us to see neither. We can fix it by making sure we load packed-refs only after checking the loose store. As a bonus, this is a minor optimization: we'll avoid even looking at the packed-refs file if we see a loose version.
-rw-r--r--src/refdb_fs.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 3ac7e8347..d8447eea6 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -333,14 +333,17 @@ static int refdb_fs_backend__exists(
assert(backend);
- if ((error = packed_reload(backend)) < 0 ||
- (error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
+ if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
return error;
+ *exists = git_path_isfile(ref_path.ptr);
+ git_buf_dispose(&ref_path);
- *exists = git_path_isfile(ref_path.ptr) ||
- (git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
+ if (!*exists) {
+ if ((error = packed_reload(backend)) < 0)
+ return error;
+ *exists = git_sortedcache_lookup(backend->refcache, ref_name) != NULL;
+ }
- git_buf_dispose(&ref_path);
return 0;
}