• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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