summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2019-02-15 10:56:50 +0100
committerPatrick Steinhardt <ps@pks.im>2019-02-15 11:30:45 +0100
commit833338144a6fd8b639b22a2d25b9cba9c767163c (patch)
treec321c0044227eaf3dd20bebef4a194bb8eecaf8c
parent32063d82a14742896c933ce31bac2d0656e410ca (diff)
downloadlibgit2-833338144a6fd8b639b22a2d25b9cba9c767163c.tar.gz
refdb_fs: do not lazily copy packed ref cache
When creating a new iterator, we eagerly load loose refs but only lazily create a copy of packed refs. The lazy load only happens as soon as we have iterated over all loose refs, opening up a potentially wide window for races. This may lead to an inconsistent view e.g. when the caller decides to reload packed references somewhen between iterating the loose refs, which is unexpected. Fix the issue by eagerly copying the sorted cache. Note that right now, we are heavily dependent on ordering here: we first need to reload packed refs, then we have to load loose refs and only as a last step are we allowed to copy the cache. This is because loading loose refs has the side-effect of setting the `PACKED_SHADOWED` flag in the packed refs cache, which we require to avoid outputting packed refs that already exist as loose refs.
-rw-r--r--src/refdb_fs.c19
1 files changed, 6 insertions, 13 deletions
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index c7df6f20a..cf4231d65 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -611,11 +611,6 @@ static int refdb_fs_backend__iterator_next(
git_error_clear();
}
- if (!iter->cache) {
- if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
- return error;
- }
-
error = GIT_ITEROVER;
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
@@ -654,11 +649,6 @@ static int refdb_fs_backend__iterator_next_name(
git_error_clear();
}
- if (!iter->cache) {
- if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
- return error;
- }
-
error = GIT_ITEROVER;
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
@@ -687,9 +677,6 @@ static int refdb_fs_backend__iterator(
assert(backend);
- if ((error = packed_reload(backend)) < 0)
- goto out;
-
iter = git__calloc(1, sizeof(refdb_fs_iter));
GIT_ERROR_CHECK_ALLOC(iter);
@@ -704,9 +691,15 @@ static int refdb_fs_backend__iterator(
goto out;
}
+ if ((error = packed_reload(backend)) < 0)
+ goto out;
+
if ((error = iter_load_loose_paths(backend, iter)) < 0)
goto out;
+ if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
+ goto out;
+
iter->parent.next = refdb_fs_backend__iterator_next;
iter->parent.next_name = refdb_fs_backend__iterator_next_name;
iter->parent.free = refdb_fs_backend__iterator_free;