Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dfcba09

Browse files
committed
Merge pull request libgit2#2395 from libgit2/cmn/ref-iter-concurrent
Concurrent ref iterator access
2 parents bccb36e + 2d945f8 commit dfcba09

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

src/refdb_fs.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ typedef struct {
458458
git_pool pool;
459459
git_vector loose;
460460

461+
git_sortedcache *cache;
461462
size_t loose_pos;
462463
size_t packed_pos;
463464
} refdb_fs_iter;
@@ -468,6 +469,7 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
468469

469470
git_vector_free(&iter->loose);
470471
git_pool_clear(&iter->pool);
472+
git_sortedcache_free(iter->cache);
471473
git__free(iter);
472474
}
473475

@@ -539,10 +541,14 @@ static int refdb_fs_backend__iterator_next(
539541
giterr_clear();
540542
}
541543

542-
git_sortedcache_rlock(backend->refcache);
544+
if (!iter->cache) {
545+
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
546+
return error;
547+
}
543548

544-
while (iter->packed_pos < git_sortedcache_entrycount(backend->refcache)) {
545-
ref = git_sortedcache_entry(backend->refcache, iter->packed_pos++);
549+
error = GIT_ITEROVER;
550+
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
551+
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
546552
if (!ref) /* stop now if another thread deleted refs and we past end */
547553
break;
548554

@@ -556,7 +562,6 @@ static int refdb_fs_backend__iterator_next(
556562
break;
557563
}
558564

559-
git_sortedcache_runlock(backend->refcache);
560565
return error;
561566
}
562567

@@ -579,10 +584,14 @@ static int refdb_fs_backend__iterator_next_name(
579584
giterr_clear();
580585
}
581586

582-
git_sortedcache_rlock(backend->refcache);
587+
if (!iter->cache) {
588+
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
589+
return error;
590+
}
583591

584-
while (iter->packed_pos < git_sortedcache_entrycount(backend->refcache)) {
585-
ref = git_sortedcache_entry(backend->refcache, iter->packed_pos++);
592+
error = GIT_ITEROVER;
593+
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
594+
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
586595
if (!ref) /* stop now if another thread deleted refs and we past end */
587596
break;
588597

@@ -596,7 +605,6 @@ static int refdb_fs_backend__iterator_next_name(
596605
break;
597606
}
598607

599-
git_sortedcache_runlock(backend->refcache);
600608
return error;
601609
}
602610

tests/refs/iterator.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,36 @@ void test_refs_iterator__foreach_name_can_cancel(void)
186186
-333);
187187
cl_assert_equal_i(0, cancel_after);
188188
}
189+
190+
void test_refs_iterator__concurrent_delete(void)
191+
{
192+
git_reference_iterator *iter;
193+
size_t full_count = 0, concurrent_count = 0;
194+
const char *name;
195+
int error;
196+
197+
git_repository_free(repo);
198+
repo = cl_git_sandbox_init("testrepo");
199+
200+
cl_git_pass(git_reference_iterator_new(&iter, repo));
201+
while ((error = git_reference_next_name(&name, iter)) == 0) {
202+
full_count++;
203+
}
204+
205+
git_reference_iterator_free(iter);
206+
cl_assert_equal_i(GIT_ITEROVER, error);
207+
208+
cl_git_pass(git_reference_iterator_new(&iter, repo));
209+
while ((error = git_reference_next_name(&name, iter)) == 0) {
210+
cl_git_pass(git_reference_remove(repo, name));
211+
concurrent_count++;
212+
}
213+
214+
git_reference_iterator_free(iter);
215+
cl_assert_equal_i(GIT_ITEROVER, error);
216+
217+
cl_assert_equal_i(full_count, concurrent_count);
218+
219+
cl_git_sandbox_cleanup();
220+
repo = NULL;
221+
}

0 commit comments

Comments
 (0)