1 #include "iwkv.h"
2 #include "iwlog.h"
3 #include "iwutils.h"
4 #include "iwcfg.h"
5
6 #include <CUnit/Basic.h>
7 #include <pthread.h>
8 #include <stdatomic.h>
9 #include <unistd.h>
10
11 typedef struct VN {
12 int kn; // key number
13 int vs; // value seed
14 } VN;
15
16 typedef struct CTX {
17 VN *vn;
18 int vnsz;
19 pthread_cond_t cond;
20 pthread_mutex_t mtx;
21 int readynum;
22 const int thrnum;
23 IWDB db;
24 } CTX;
25
26 typedef struct TASK {
27 CTX *ctx;
28 int start;
29 int cnt;
30 pthread_t thr;
31 } TASK;
32
init_suite(void)33 int init_suite(void) {
34 iwrc rc = iwkv_init();
35 return rc;
36 }
37
clean_suite(void)38 int clean_suite(void) {
39 return 0;
40 }
41
logstage(FILE * f,const char * name,IWDB db)42 static int logstage(FILE *f, const char *name, IWDB db) {
43 int rci = fprintf(f, "\n#### Stage: %s\n", name);
44 iwkvd_db(f, db, /*IWKVD_PRINT_NO_LEVEVELS*/ 0, 0);
45 fflush(f);
46 return rci < 0 ? rci : 0;
47 }
48
iwkv_test1_worker(void * op)49 static void *iwkv_test1_worker(void *op) {
50 TASK *t = op;
51 CTX *ctx = t->ctx;
52 int mynum;
53 int rci = pthread_mutex_lock(&ctx->mtx);
54 CU_ASSERT_EQUAL_FATAL(rci, 0);
55 ++ctx->readynum;
56 mynum = ctx->readynum;
57 if (mynum == ctx->thrnum) {
58 pthread_cond_broadcast(&ctx->cond);
59 } else {
60 pthread_cond_wait(&ctx->cond, &ctx->mtx);
61 }
62 pthread_mutex_unlock(&ctx->mtx);
63
64 IWKV_val key, val;
65 for (int i = 0; i < t->cnt; ++i) {
66 uint64_t k = t->start + i;
67 uint64_t v = k;
68 key.size = sizeof(uint64_t);
69 key.data = &k;
70 val.size = sizeof(uint64_t);
71 val.data = &v;
72 iwrc rc = iwkv_put(ctx->db, &key, &val, 0);
73 CU_ASSERT_EQUAL_FATAL(rc, 0);
74 }
75 return 0;
76 }
77
iwkv_test3_impl(int thrnum,int recth,bool wal)78 static void iwkv_test3_impl(int thrnum, int recth, bool wal) {
79 FILE *f = fopen("iwkv_test3_1.log", "w+");
80 CU_ASSERT_PTR_NOT_NULL(f);
81 const int nrecs = thrnum * recth;
82 TASK *tasks = calloc(thrnum, sizeof(*tasks));
83 VN *arr = calloc(nrecs, sizeof(*arr));
84 CTX ctx = {
85 .vn = arr,
86 .vnsz = nrecs,
87 .mtx = PTHREAD_MUTEX_INITIALIZER,
88 .cond = PTHREAD_COND_INITIALIZER,
89 .thrnum = thrnum
90 };
91 for (int i = 0; i < nrecs; ++i) {
92 arr[i].kn = i;
93 arr[i].vs = iwu_rand_range(256);
94 }
95 // shuffle
96 for (int i = 0; i < nrecs; ++i) {
97 uint32_t tgt = iwu_rand_range(nrecs);
98 int knt = arr[tgt].kn;
99 arr[tgt].kn = arr[i].kn;
100 arr[i].kn = knt;
101 }
102 for (int i = nrecs - 1; i >= 0; --i) {
103 uint32_t tgt = iwu_rand_range(nrecs);
104 int knt = arr[tgt].kn;
105 arr[tgt].kn = arr[i].kn;
106 arr[i].kn = knt;
107 }
108
109 IWKV_OPTS opts = {
110 .path = "iwkv_test3_1.db",
111 .oflags = IWKV_TRUNC,
112 .wal = {
113 .enabled = wal,
114 .checkpoint_buffer_sz = 1024 * 1024
115 }
116 };
117 IWKV iwkv;
118 IWKV_val key, val;
119 iwrc rc = iwkv_open(&opts, &iwkv);
120 CU_ASSERT_EQUAL_FATAL(rc, 0);
121
122 rc = iwkv_db(iwkv, 1, IWDB_VNUM64_KEYS, &ctx.db);
123 CU_ASSERT_EQUAL_FATAL(rc, 0);
124
125 for (int i = 0; i < thrnum; ++i) {
126 tasks[i].ctx = &ctx;
127 tasks[i].start = i * recth;
128 tasks[i].cnt = recth;
129 int rci = pthread_create(&tasks[i].thr, 0, iwkv_test1_worker, &tasks[i]);
130 CU_ASSERT_EQUAL_FATAL(rci, 0);
131 }
132 for (int i = 0; i < thrnum; ++i) {
133 int rci = pthread_join(tasks[i].thr, 0);
134 CU_ASSERT_EQUAL_FATAL(rci, 0);
135 }
136 fprintf(stderr, "\nChecking DB....");
137 int ec = 0;
138 for (int i = 0; i < nrecs; ++i) {
139 uint64_t k = i, v;
140 key.data = &k;
141 key.size = sizeof(uint64_t);
142 rc = iwkv_get(ctx.db, &key, &val);
143 if (rc) {
144 ec++;
145 fprintf(stderr, "\nwk=%d\n", i);
146 iwlog_ecode_error3(rc);
147 //break;
148 } else {
149 CU_ASSERT_EQUAL_FATAL(val.size, sizeof(uint64_t));
150 memcpy(&v, val.data, sizeof(uint64_t));
151 CU_ASSERT_EQUAL_FATAL(v, i);
152 }
153 iwkv_val_dispose(&val);
154 }
155 pthread_cond_destroy(&ctx.cond);
156 pthread_mutex_destroy(&ctx.mtx);
157 free(arr);
158 free(tasks);
159 rc = iwkv_close(&iwkv);
160 fprintf(stderr, "ec=%d\n", ec);
161 CU_ASSERT_EQUAL_FATAL(rc, 0);
162 fclose(f);
163 }
164
iwkv_test3_1(void)165 static void iwkv_test3_1(void) {
166 iwkv_test3_impl(4, 30000, false);
167 }
168
iwkv_test3_2(void)169 static void iwkv_test3_2(void) {
170 iwkv_test3_impl(4, 30000, true);
171 }
172
main()173 int main() {
174 CU_pSuite pSuite = NULL;
175
176 /* Initialize the CUnit test registry */
177 if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
178
179 /* Add a suite to the registry */
180 pSuite = CU_add_suite("iwkv_test3", init_suite, clean_suite);
181
182 if (NULL == pSuite) {
183 CU_cleanup_registry();
184 return CU_get_error();
185 }
186
187 /* Add the tests to the suite */
188 if (
189 (NULL == CU_add_test(pSuite, "iwkv_test3_1", iwkv_test3_1)) ||
190 (NULL == CU_add_test(pSuite, "iwkv_test3_2", iwkv_test3_2))
191 ) {
192 CU_cleanup_registry();
193 return CU_get_error();
194 }
195
196 /* Run all tests using the CUnit Basic interface */
197 CU_basic_set_mode(CU_BRM_VERBOSE);
198 CU_basic_run_tests();
199 int ret = CU_get_error() || CU_get_number_of_failures();
200 CU_cleanup_registry();
201 return ret;
202 }
203