void test_refs_delete__packed_only(void) { // can delete a just packed reference git_reference *ref; git_refdb *refdb; git_oid id; const char *new_ref = "refs/heads/new_ref"; git_oid_fromstr(&id, current_master_tip); /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &id, 0)); git_reference_free(ref); /* Lookup the reference */ cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref)); /* Ensure it's a loose reference */ cl_assert(reference_is_packed(ref) == 0); /* Pack all existing references */ cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); /* Reload the reference from disk */ git_reference_free(ref); cl_git_pass(git_reference_lookup(&ref, g_repo, new_ref)); /* Ensure it's a packed reference */ cl_assert(reference_is_packed(ref) == 1); /* This should pass */ cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); }
void test_refs_rename__overwrite(void) { // can not overwrite name of existing reference git_reference *ref, *ref_one, *ref_one_new, *ref_two; git_refdb *refdb; git_oid id; cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); cl_assert(git_reference_type(ref) & GIT_REF_OID); git_oid_cpy(&id, git_reference_target(ref)); /* Create loose references */ cl_git_pass(git_reference_create(&ref_one, g_repo, ref_one_name, &id, 0, NULL)); cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0, NULL)); /* Pack everything */ cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); /* Attempt to create illegal reference */ cl_git_fail(git_reference_create(&ref_one_new, g_repo, ref_one_name_new, &id, 0, NULL)); /* Illegal reference couldn't be created so this is supposed to fail */ cl_git_fail(git_reference_lookup(&ref_one_new, g_repo, ref_one_name_new)); git_reference_free(ref); git_reference_free(ref_one); git_reference_free(ref_one_new); git_reference_free(ref_two); git_refdb_free(refdb); }
static void *create_refs(void *arg) { int *id = arg, i; git_oid head; char name[128]; git_reference *ref[10]; cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); for (i = 0; i < 10; ++i) { p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", *id, i); cl_git_pass(git_reference_create(&ref[i], g_repo, name, &head, 0, NULL)); if (i == 5) { git_refdb *refdb; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); } } for (i = 0; i < 10; ++i) git_reference_free(ref[i]); giterr_clear(); return arg; }
int git_transaction_new(git_transaction **out, git_repository *repo) { int error; git_pool pool; git_transaction *tx = NULL; assert(out && repo); if ((error = git_pool_init(&pool, 1, 0)) < 0) return error; tx = git_pool_mallocz(&pool, sizeof(git_transaction)); if (!tx) { error = -1; goto on_error; } if ((error = git_strmap_alloc(&tx->locks)) < 0) { error = -1; goto on_error; } if ((error = git_repository_refdb(&tx->db, repo)) < 0) goto on_error; memcpy(&tx->pool, &pool, sizeof(git_pool)); tx->repo = repo; *out = tx; return 0; on_error: git_pool_clear(&pool); return error; }
static void *delete_refs(void *arg) { int *id = arg, i; git_reference *ref; char name[128]; for (i = 0; i < 10; ++i) { p_snprintf( name, sizeof(name), "refs/heads/thread-%03d-%02d", (*id) & ~0x3, i); if (!git_reference_lookup(&ref, g_repo, name)) { cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); } if (i == 5) { git_refdb *refdb; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); } } giterr_clear(); return arg; }
static void packall(void) { git_refdb *refdb; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); }
void test_threads_refdb__iterator(void) { int r, t; git_thread th[THREADS]; int id[THREADS]; git_oid head; git_reference *ref; char name[128]; git_refdb *refdb; g_repo = cl_git_sandbox_init("testrepo2"); cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); /* make a bunch of references */ for (r = 0; r < 200; ++r) { p_snprintf(name, sizeof(name), "refs/heads/direct-%03d", r); cl_git_pass(git_reference_create(&ref, g_repo, name, &head, 0, NULL)); git_reference_free(ref); } cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); g_expected = 206; for (r = 0; r < REPEAT; ++r) { g_repo = cl_git_sandbox_reopen(); /* reopen to flush caches */ for (t = 0; t < THREADS; ++t) { id[t] = t; #ifdef GIT_THREADS cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); #else th[t] = t; iterate_refs(&id[t]); #endif } #ifdef GIT_THREADS for (t = 0; t < THREADS; ++t) { cl_git_pass(git_thread_join(&th[t], NULL)); } #endif memset(th, 0, sizeof(th)); } }
static void *create_refs(void *arg) { int i, error; struct th_data *data = (struct th_data *) arg; git_oid head; char name[128]; git_reference *ref[NREFS]; git_repository *repo; cl_git_thread_pass(data, git_repository_open(&repo, data->path)); do { error = git_reference_name_to_id(&head, repo, "HEAD"); } while (error == GIT_ELOCKED); cl_git_thread_pass(data, error); for (i = 0; i < NREFS; ++i) { p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", data->id, i); do { error = git_reference_create(&ref[i], repo, name, &head, 0, NULL); } while (error == GIT_ELOCKED); cl_git_thread_pass(data, error); if (concurrent_compress && i == NREFS/2) { git_refdb *refdb; cl_git_thread_pass(data, git_repository_refdb(&refdb, repo)); do { error = git_refdb_compress(refdb); } while (error == GIT_ELOCKED); cl_git_thread_pass(data, error); git_refdb_free(refdb); } } for (i = 0; i < NREFS; ++i) git_reference_free(ref[i]); git_repository_free(repo); git_error_clear(); return arg; }
static void *delete_refs(void *arg) { int i, error; struct th_data *data = (struct th_data *) arg; git_reference *ref; char name[128]; git_repository *repo; cl_git_thread_pass(data, git_repository_open(&repo, data->path)); for (i = 0; i < NREFS; ++i) { p_snprintf( name, sizeof(name), "refs/heads/thread-%03d-%02d", (data->id) & ~0x3, i); if (!git_reference_lookup(&ref, repo, name)) { do { error = git_reference_delete(ref); } while (error == GIT_ELOCKED); /* Sometimes we race with other deleter threads */ if (error == GIT_ENOTFOUND) error = 0; cl_git_thread_pass(data, error); git_reference_free(ref); } if (concurrent_compress && i == NREFS/2) { git_refdb *refdb; cl_git_thread_pass(data, git_repository_refdb(&refdb, repo)); do { error = git_refdb_compress(refdb); } while (error == GIT_ELOCKED); cl_git_thread_pass(data, error); git_refdb_free(refdb); } } git_repository_free(repo); git_error_clear(); return arg; }
static void count_fsyncs(size_t *create_count, size_t *compress_count) { git_reference *ref = NULL; git_refdb *refdb; git_oid id; p_fsync__cnt = 0; git_oid_fromstr(&id, current_master_tip); cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message")); git_reference_free(ref); *create_count = p_fsync__cnt; p_fsync__cnt = 0; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); *compress_count = p_fsync__cnt; p_fsync__cnt = 0; }
void test_threads_refdb__edit_while_iterate(void) { int r, t; int id[THREADS]; git_oid head; git_reference *ref; char name[128]; git_refdb *refdb; #ifdef GIT_THREADS git_thread th[THREADS]; #endif g_repo = cl_git_sandbox_init("testrepo2"); cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); /* make a bunch of references */ for (r = 0; r < 50; ++r) { p_snprintf(name, sizeof(name), "refs/heads/starter-%03d", r); cl_git_pass(git_reference_create(&ref, g_repo, name, &head, 0, NULL)); git_reference_free(ref); } cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); g_expected = -1; g_repo = cl_git_sandbox_reopen(); /* reopen to flush caches */ for (t = 0; t < THREADS; ++t) { void *(*fn)(void *arg); switch (t & 0x3) { case 0: fn = create_refs; break; case 1: fn = delete_refs; break; default: fn = iterate_refs; break; } id[t] = t; /* It appears with all reflog writing changes, etc., that this * test has started to fail quite frequently, so let's disable it * for now by just running on a single thread... */ /* #ifdef GIT_THREADS */ /* cl_git_pass(git_thread_create(&th[t], fn, &id[t])); */ /* #else */ fn(&id[t]); /* #endif */ } #ifdef GIT_THREADS /* for (t = 0; t < THREADS; ++t) { */ /* cl_git_pass(git_thread_join(th[t], NULL)); */ /* } */ memset(th, 0, sizeof(th)); for (t = 0; t < THREADS; ++t) { id[t] = t; cl_git_pass(git_thread_create(&th[t], iterate_refs, &id[t])); } for (t = 0; t < THREADS; ++t) { cl_git_pass(git_thread_join(&th[t], NULL)); } #endif }
void test_threads_refdb__edit_while_iterate(void) { int r, t; struct th_data th_data[THREADS]; git_oid head; git_reference *ref; char name[128]; git_refdb *refdb; #ifdef GIT_THREADS git_thread th[THREADS]; #endif g_repo = cl_git_sandbox_init("testrepo2"); cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); /* make a bunch of references */ for (r = 0; r < 50; ++r) { p_snprintf(name, sizeof(name), "refs/heads/starter-%03d", r); cl_git_pass(git_reference_create(&ref, g_repo, name, &head, 0, NULL)); git_reference_free(ref); } cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); g_expected = -1; g_repo = cl_git_sandbox_reopen(); /* reopen to flush caches */ for (t = 0; t < THREADS; ++t) { void *(*fn)(void *arg); switch (t & 0x3) { case 0: fn = create_refs; break; case 1: fn = delete_refs; break; default: fn = iterate_refs; break; } th_data[t].id = t; th_data[t].path = git_repository_path(g_repo); #ifdef GIT_THREADS cl_git_pass(git_thread_create(&th[t], fn, &th_data[t])); #else fn(&th_data[t]); #endif } #ifdef GIT_THREADS for (t = 0; t < THREADS; ++t) { cl_git_pass(git_thread_join(&th[t], NULL)); cl_git_thread_check(&th_data[t]); } memset(th, 0, sizeof(th)); for (t = 0; t < THREADS; ++t) { th_data[t].id = t; cl_git_pass(git_thread_create(&th[t], iterate_refs, &th_data[t])); } for (t = 0; t < THREADS; ++t) { cl_git_pass(git_thread_join(&th[t], NULL)); cl_git_thread_check(&th_data[t]); } #endif }