mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-09 15:00:04 +00:00
Merge pull request #2395 from libgit2/cmn/ref-iter-concurrent
Concurrent ref iterator access
This commit is contained in:
commit
dfcba09e67
@ -458,6 +458,7 @@ typedef struct {
|
||||
git_pool pool;
|
||||
git_vector loose;
|
||||
|
||||
git_sortedcache *cache;
|
||||
size_t loose_pos;
|
||||
size_t packed_pos;
|
||||
} refdb_fs_iter;
|
||||
@ -468,6 +469,7 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
|
||||
|
||||
git_vector_free(&iter->loose);
|
||||
git_pool_clear(&iter->pool);
|
||||
git_sortedcache_free(iter->cache);
|
||||
git__free(iter);
|
||||
}
|
||||
|
||||
@ -539,10 +541,14 @@ static int refdb_fs_backend__iterator_next(
|
||||
giterr_clear();
|
||||
}
|
||||
|
||||
git_sortedcache_rlock(backend->refcache);
|
||||
if (!iter->cache) {
|
||||
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
while (iter->packed_pos < git_sortedcache_entrycount(backend->refcache)) {
|
||||
ref = git_sortedcache_entry(backend->refcache, iter->packed_pos++);
|
||||
error = GIT_ITEROVER;
|
||||
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
|
||||
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
|
||||
if (!ref) /* stop now if another thread deleted refs and we past end */
|
||||
break;
|
||||
|
||||
@ -556,7 +562,6 @@ static int refdb_fs_backend__iterator_next(
|
||||
break;
|
||||
}
|
||||
|
||||
git_sortedcache_runlock(backend->refcache);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -579,10 +584,14 @@ static int refdb_fs_backend__iterator_next_name(
|
||||
giterr_clear();
|
||||
}
|
||||
|
||||
git_sortedcache_rlock(backend->refcache);
|
||||
if (!iter->cache) {
|
||||
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
while (iter->packed_pos < git_sortedcache_entrycount(backend->refcache)) {
|
||||
ref = git_sortedcache_entry(backend->refcache, iter->packed_pos++);
|
||||
error = GIT_ITEROVER;
|
||||
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
|
||||
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
|
||||
if (!ref) /* stop now if another thread deleted refs and we past end */
|
||||
break;
|
||||
|
||||
@ -596,7 +605,6 @@ static int refdb_fs_backend__iterator_next_name(
|
||||
break;
|
||||
}
|
||||
|
||||
git_sortedcache_runlock(backend->refcache);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -186,3 +186,36 @@ void test_refs_iterator__foreach_name_can_cancel(void)
|
||||
-333);
|
||||
cl_assert_equal_i(0, cancel_after);
|
||||
}
|
||||
|
||||
void test_refs_iterator__concurrent_delete(void)
|
||||
{
|
||||
git_reference_iterator *iter;
|
||||
size_t full_count = 0, concurrent_count = 0;
|
||||
const char *name;
|
||||
int error;
|
||||
|
||||
git_repository_free(repo);
|
||||
repo = cl_git_sandbox_init("testrepo");
|
||||
|
||||
cl_git_pass(git_reference_iterator_new(&iter, repo));
|
||||
while ((error = git_reference_next_name(&name, iter)) == 0) {
|
||||
full_count++;
|
||||
}
|
||||
|
||||
git_reference_iterator_free(iter);
|
||||
cl_assert_equal_i(GIT_ITEROVER, error);
|
||||
|
||||
cl_git_pass(git_reference_iterator_new(&iter, repo));
|
||||
while ((error = git_reference_next_name(&name, iter)) == 0) {
|
||||
cl_git_pass(git_reference_remove(repo, name));
|
||||
concurrent_count++;
|
||||
}
|
||||
|
||||
git_reference_iterator_free(iter);
|
||||
cl_assert_equal_i(GIT_ITEROVER, error);
|
||||
|
||||
cl_assert_equal_i(full_count, concurrent_count);
|
||||
|
||||
cl_git_sandbox_cleanup();
|
||||
repo = NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user