Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-02-12 02:45:37 +0400
committerRussell Belfer <rb@github.com>2014-04-18 01:43:45 +0400
commit40ed499039f887ebcb0b5badf0157519148398b8 (patch)
treeabf8307b9960aed3eb6911fadc26bb0627b7ecf2 /tests/threads
parent3b4c401a38ce912d5be8c9bf4ab1c4912a4f08bd (diff)
Add diff threading tests and attr file cache locks
This adds a basic test of doing simultaneous diffs on multiple threads and adds basic locking for the attr file cache because that was the immediate problem that arose from these tests.
Diffstat (limited to 'tests/threads')
-rw-r--r--tests/threads/diff.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/tests/threads/diff.c b/tests/threads/diff.c
new file mode 100644
index 000000000..33afc58ac
--- /dev/null
+++ b/tests/threads/diff.c
@@ -0,0 +1,152 @@
+#include "clar_libgit2.h"
+#include "thread-utils.h"
+
+static git_repository *g_repo;
+static git_tree *a, *b;
+static git_atomic counts[4];
+
+void test_threads_diff__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+static void run_in_parallel(
+ int repeats, int threads, void *(*func)(void *),
+ void (*before_test)(void), void (*after_test)(void))
+{
+ int r, t, *id = git__calloc(threads, sizeof(int));
+#ifdef GIT_THREADS
+ git_thread *th = git__calloc(threads, sizeof(git_thread));
+#else
+ void *th = NULL;
+#endif
+
+ cl_assert(id != NULL && th != NULL);
+
+ for (r = 0; r < repeats; ++r) {
+ g_repo = cl_git_sandbox_reopen(); /* reopen sandbox to flush caches */
+
+ if (before_test) before_test();
+
+ for (t = 0; t < threads; ++t) {
+ id[t] = t;
+#ifdef GIT_THREADS
+ cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t]));
+#else
+ cl_assert(func(&id[t]) == &id[t]);
+#endif
+ }
+
+#ifdef GIT_THREADS
+ for (t = 0; t < threads; ++t)
+ cl_git_pass(git_thread_join(th[t], NULL));
+ memset(th, 0, threads * sizeof(git_thread));
+#endif
+
+ if (after_test) after_test();
+ }
+
+ git__free(id);
+ git__free(th);
+}
+
+static void setup_trees(void)
+{
+ cl_git_pass(git_revparse_single(
+ (git_object **)&a, g_repo, "0017bd4ab1^{tree}"));
+ cl_git_pass(git_revparse_single(
+ (git_object **)&b, g_repo, "26a125ee1b^{tree}"));
+
+ memset(counts, 0, sizeof(counts));
+}
+
+#define THREADS 20
+
+static void free_trees(void)
+{
+ git_tree_free(a); a = NULL;
+ git_tree_free(b); b = NULL;
+
+ cl_assert_equal_i(288, git_atomic_get(&counts[0]));
+ cl_assert_equal_i(112, git_atomic_get(&counts[1]));
+ cl_assert_equal_i( 80, git_atomic_get(&counts[2]));
+ cl_assert_equal_i( 96, git_atomic_get(&counts[3]));
+}
+
+static void *run_index_diffs(void *arg)
+{
+ int thread = *(int *)arg;
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff *diff = NULL;
+ size_t i;
+ int exp[4] = { 0, 0, 0, 0 };
+
+// fprintf(stderr, "%d >>>\n", thread);
+
+ switch (thread & 0x03) {
+ case 0: /* diff index to workdir */;
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+ break;
+ case 1: /* diff tree 'a' to index */;
+ cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts));
+ break;
+ case 2: /* diff tree 'b' to index */;
+ cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts));
+ break;
+ case 3: /* diff index to workdir (explicit index) */;
+ {
+ git_index *idx;
+ cl_git_pass(git_repository_index(&idx, g_repo));
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, idx, &opts));
+ git_index_free(idx);
+ break;
+ }
+ }
+
+// fprintf(stderr, "%d <<<\n", thread);
+
+ /* keep some diff stats to make sure results are as expected */
+
+ i = git_diff_num_deltas(diff);
+ git_atomic_add(&counts[0], (int32_t)i);
+ exp[0] = (int)i;
+
+ while (i > 0) {
+ switch (git_diff_get_delta(diff, --i)->status) {
+ case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&counts[1]); break;
+ case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&counts[2]); break;
+ case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&counts[3]); break;
+ default: break;
+ }
+ }
+
+// fprintf(stderr, "%2d: [%d] total %d (M %d A %d D %d)\n",
+// thread, (int)(thread & 0x03), exp[0], exp[1], exp[2], exp[3]);
+
+ switch (thread & 0x03) {
+ case 0: case 3:
+ cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(4, exp[1]);
+ cl_assert_equal_i(0, exp[2]); cl_assert_equal_i(4, exp[3]);
+ break;
+ case 1:
+ cl_assert_equal_i(12, exp[0]); cl_assert_equal_i(3, exp[1]);
+ cl_assert_equal_i(7, exp[2]); cl_assert_equal_i(2, exp[3]);
+ break;
+ case 2:
+ cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(3, exp[1]);
+ cl_assert_equal_i(3, exp[2]); cl_assert_equal_i(2, exp[3]);
+ break;
+ }
+
+ git_diff_free(diff);
+
+ return arg;
+}
+
+void test_threads_diff__concurrent_diffs(void)
+{
+ g_repo = cl_git_sandbox_init("status");
+
+ run_in_parallel(
+ 20, 32, run_index_diffs, setup_trees, free_trees);
+}