diff options
author | Jeff King <peff@peff.net> | 2019-02-15 04:43:30 -0500 |
---|---|---|
committer | Jeff King <peff@peff.net> | 2019-02-15 04:43:30 -0500 |
commit | 5df823f02fc6f6a5e50aa303b13021cf021a7b61 (patch) | |
tree | 2acebad539ac425ca18cba47f97e508a4927a2ab | |
parent | 83d40605047577988b95bae2f048abe2eea6192a (diff) | |
download | libgit2-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.c | 13 |
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; } |