1 #include "iwkv.h"
2 #include "iwlog.h"
3 #include "iwutils.h"
4 #include "iwkv_tests.h"
5 #include "iwkv_internal.h"
6 #include "iwth.h"
7
8 iwrc iwal_test_checkpoint(IWKV iwkv);
9
10 #define KBUFSZ 1024
11 #define VBUFSZ 1024
12 static char kbuf[KBUFSZ];
13 static char vbuf[VBUFSZ];
14
init_suite(void)15 int init_suite(void) {
16 unlink("./iwkv_test8_1_bkp.db-wal");
17 unlink("./iwkv_test8_1.db-wal");
18 unlink("./iwkv_test8_2_bkp.db-wal");
19 unlink("./iwkv_test8_2_check.db-wal");
20 unlink("./iwkv_test8_2.db-wal");
21 unlink("./iwkv_test8_1_bkp.db");
22 unlink("./iwkv_test8_2_bkp.db");
23 unlink("./iwkv_test8_2_check.db");
24 unlink("./iwkv_test8_2.db");
25 return iwkv_init();
26 }
27
clean_suite(void)28 int clean_suite(void) {
29 return 0;
30 }
31
iwkv_test8_1()32 static void iwkv_test8_1() {
33 IWKV iwkv;
34 IWDB db;
35 IWKV_val key = {0};
36 IWKV_val val = {0};
37 IWKV_OPTS opts = {
38 .path = "iwkv_test8_1.db",
39 .oflags = IWKV_TRUNC,
40 .wal = {
41 .enabled = true
42 }
43 };
44 uint64_t ts;
45
46 iwrc rc = iwkv_open(&opts, &iwkv);
47 CU_ASSERT_EQUAL_FATAL(rc, 0);
48 rc = iwkv_db(iwkv, 1, 0, &db);
49 CU_ASSERT_EQUAL_FATAL(rc, 0);
50
51 for (int i = 0; i < 1000; ++i) {
52 snprintf(kbuf, KBUFSZ, "%d", i);
53 snprintf(vbuf, VBUFSZ, "%03dval", i);
54 key.data = kbuf;
55 key.size = strlen(key.data);
56 val.data = vbuf;
57 val.size = strlen(val.data);
58 rc = iwkv_put(db, &key, &val, 0);
59 CU_ASSERT_EQUAL_FATAL(rc, 0);
60 }
61 rc = iwkv_close(&iwkv);
62 CU_ASSERT_EQUAL_FATAL(rc, 0);
63
64 // Now reopen
65 opts.oflags &= ~IWKV_TRUNC;
66 rc = iwkv_open(&opts, &iwkv);
67 CU_ASSERT_EQUAL_FATAL(rc, 0);
68 rc = iwkv_online_backup(iwkv, &ts, "iwkv_test8_1_bkp.db");
69 if (rc) iwlog_ecode_error3(rc);
70 CU_ASSERT_EQUAL_FATAL(rc, 0);
71 rc = iwkv_close(&iwkv);
72 CU_ASSERT_EQUAL_FATAL(rc, 0);
73
74 // Open backup
75 opts.path = "iwkv_test8_1_bkp.db";
76 rc = iwkv_open(&opts, &iwkv);
77 CU_ASSERT_EQUAL_FATAL(rc, 0);
78 rc = iwkv_db(iwkv, 1, 0, &db);
79 CU_ASSERT_EQUAL_FATAL(rc, 0);
80 for (int i = 0; i < 1000; ++i) {
81 int cret = 0;
82 snprintf(kbuf, KBUFSZ, "%d", i);
83 snprintf(vbuf, VBUFSZ, "%03dval", i);
84 key.data = kbuf;
85 key.size = strlen(key.data);
86 int vlen = strlen(vbuf);
87 rc = iwkv_get(db, &key, &val);
88 CU_ASSERT_EQUAL_FATAL(rc, 0);
89 IW_CMP(cret, vbuf, vlen, val.data, val.size);
90 CU_ASSERT_EQUAL_FATAL(cret, 0);
91 iwkv_val_dispose(&val);
92 }
93 rc = iwkv_close(&iwkv);
94 CU_ASSERT_EQUAL_FATAL(rc, 0);
95 }
96
97 typedef struct T82 {
98 pthread_t t;
99 pthread_barrier_t barrier;
100 pthread_cond_t cond;
101 pthread_mutex_t mtx;
102 IWKV iwkv;
103 IWKV iwkvcheck;
104 } T82;
105
t82(void * ctx_)106 static void *t82(void *ctx_) {
107 T82 *ctx = ctx_;
108 IWKV_val key = {0};
109 IWKV_val val = {0};
110
111 iwrc rc = iwkv_open(&(IWKV_OPTS) {
112 .path = "iwkv_test8_2_check.db",
113 .oflags = IWKV_TRUNC,
114 }, &ctx->iwkvcheck);
115 CU_ASSERT_EQUAL_FATAL(rc, 0);
116
117 IWDB db, dbc;
118 rc = iwkv_db(ctx->iwkv, 1, 0, &db);
119 CU_ASSERT_EQUAL_FATAL(rc, 0);
120
121 rc = iwkv_db(ctx->iwkvcheck, 1, 0, &dbc);
122 CU_ASSERT_EQUAL_FATAL(rc, 0);
123
124 int i = 0;
125 for (; i < 500000; ++i) {
126 snprintf(kbuf, KBUFSZ, "%dkey", i);
127 key.data = kbuf;
128 key.size = strlen(key.data);
129
130 uint64_t ts;
131 rc = iwp_current_time_ms(&ts, false);
132 CU_ASSERT_EQUAL_FATAL(rc, 0);
133 val.data = &ts;
134 val.size = sizeof(ts);
135
136 rc = iwkv_put(db, &key, &val, 0);
137 CU_ASSERT_EQUAL_FATAL(rc, 0);
138
139 rc = iwkv_put(dbc, &key, &val, 0);
140 CU_ASSERT_EQUAL_FATAL(rc, 0);
141 }
142
143 pthread_barrier_wait(&ctx->barrier);
144
145 int c = i + 10000;
146 for (; i < c; ++i) {
147
148 if (i == c - 9800) { // Force checkpoint during online-backup
149 rc = iwal_test_checkpoint(ctx->iwkv);
150 CU_ASSERT_EQUAL_FATAL(rc, 0);
151 }
152
153 snprintf(kbuf, KBUFSZ, "%dkey", i);
154 key.data = kbuf;
155 key.size = strlen(key.data);
156
157 uint64_t ts;
158 rc = iwp_current_time_ms(&ts, false);
159 CU_ASSERT_EQUAL_FATAL(rc, 0);
160 val.data = &ts;
161 val.size = sizeof(ts);
162
163 rc = iwkv_put(db, &key, &val, 0);
164 CU_ASSERT_EQUAL_FATAL(rc, 0);
165
166 rc = iwkv_put(dbc, &key, &val, 0);
167 CU_ASSERT_EQUAL_FATAL(rc, 0);
168 }
169
170 rc = iwkv_close(&ctx->iwkvcheck);
171 CU_ASSERT_EQUAL_FATAL(rc, 0);
172 return 0;
173 }
174
iwkv_test8_2()175 static void iwkv_test8_2() {
176 IWKV_OPTS opts = {
177 .path = "iwkv_test8_2.db",
178 .oflags = IWKV_TRUNC,
179 .wal = {
180 .enabled = true
181 }
182 };
183
184 T82 ctx = {0};
185 iwrc rc = iwkv_open(&opts, &ctx.iwkv);
186 CU_ASSERT_EQUAL_FATAL(rc, 0);
187
188 int rci = pthread_barrier_init(&ctx.barrier, 0, 2);
189 CU_ASSERT_EQUAL_FATAL(rci, 0);
190 rci = pthread_create(&ctx.t, 0, t82, &ctx);
191 CU_ASSERT_EQUAL_FATAL(rci, 0);
192
193 pthread_barrier_wait(&ctx.barrier);
194
195 uint64_t bkts = 0, ts = 0;
196 rc = iwkv_online_backup(ctx.iwkv, &bkts, "iwkv_test8_2_bkp.db");
197 CU_ASSERT_EQUAL_FATAL(rc, 0);
198
199
200 pthread_join(ctx.t, 0);
201 rc = iwkv_close(&ctx.iwkv);
202 CU_ASSERT_EQUAL_FATAL(rc, 0);
203
204 size_t sp;
205 int cnt1 = 0, cnt2 = 0;
206 IWKV iwkv;
207 IWKV_cursor cur;
208 IWDB db;
209
210 // Now restore our backup
211 opts.path = "iwkv_test8_2_bkp.db";
212 opts.oflags &= ~IWKV_TRUNC;
213 rc = iwkv_open(&opts, &iwkv);
214 CU_ASSERT_EQUAL_FATAL(rc, 0);
215 rc = iwkv_db(iwkv, 1, 0, &db);
216 CU_ASSERT_EQUAL_FATAL(rc, 0);
217 rc = iwkv_cursor_open(db, &cur, IWKV_CURSOR_BEFORE_FIRST, 0);
218 CU_ASSERT_EQUAL_FATAL(rc, 0);
219 do {
220 rc = iwkv_cursor_to(cur, IWKV_CURSOR_NEXT);
221 if (!rc) {
222 iwkv_cursor_copy_val(cur, &ts, sizeof(ts), &sp);
223 CU_ASSERT_EQUAL_FATAL(sp, sizeof(ts));
224 if (ts < bkts) {
225 cnt1++;
226 }
227 }
228 } while (!rc);
229 CU_ASSERT_EQUAL_FATAL(rc, IWKV_ERROR_NOTFOUND);
230 iwkv_cursor_close(&cur);
231 rc = iwkv_close(&iwkv);
232 CU_ASSERT_EQUAL_FATAL(rc, 0);
233
234 // Check DB
235 opts.path = "iwkv_test8_2_check.db";
236 rc = iwkv_open(&opts, &iwkv);
237 CU_ASSERT_EQUAL_FATAL(rc, 0);
238 rc = iwkv_db(iwkv, 1, 0, &db);
239 CU_ASSERT_EQUAL_FATAL(rc, 0);
240 rc = iwkv_cursor_open(db, &cur, IWKV_CURSOR_BEFORE_FIRST, 0);
241 CU_ASSERT_EQUAL_FATAL(rc, 0);
242 do {
243 rc = iwkv_cursor_to(cur, IWKV_CURSOR_NEXT);
244 if (!rc) {
245 iwkv_cursor_copy_val(cur, &ts, sizeof(ts), &sp);
246 CU_ASSERT_EQUAL_FATAL(sp, sizeof(ts));
247 if (ts < bkts) {
248 cnt2++;
249 }
250 }
251 } while (!rc);
252 CU_ASSERT_EQUAL_FATAL(rc, IWKV_ERROR_NOTFOUND);
253 iwkv_cursor_close(&cur);
254 rc = iwkv_close(&iwkv);
255 CU_ASSERT_EQUAL_FATAL(rc, 0);
256
257 fprintf(stderr, "\n%d", cnt1);
258 fprintf(stderr, "\n%d\n", cnt2);
259
260 CU_ASSERT_TRUE(cnt1 > 500000);
261 CU_ASSERT_EQUAL(cnt1, cnt2);
262
263 pthread_barrier_destroy(&ctx.barrier);
264 }
265
main()266 int main() {
267 CU_pSuite pSuite = NULL;
268
269 /* Initialize the CUnit test registry */
270 if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
271
272 /* Add a suite to the registry */
273 pSuite = CU_add_suite("iwkv_test8", init_suite, clean_suite);
274
275 if (NULL == pSuite) {
276 CU_cleanup_registry();
277 return CU_get_error();
278 }
279
280 /* Add the tests to the suite */
281 if (
282 (NULL == CU_add_test(pSuite, "iwkv_test8_1", iwkv_test8_1)) ||
283 (NULL == CU_add_test(pSuite, "iwkv_test8_2", iwkv_test8_2))
284 ) {
285 CU_cleanup_registry();
286 return CU_get_error();
287 }
288
289 /* Run all tests using the CUnit Basic interface */
290 CU_basic_set_mode(CU_BRM_VERBOSE);
291 CU_basic_run_tests();
292 int ret = CU_get_error() || CU_get_number_of_failures();
293 CU_cleanup_registry();
294 return ret;
295 }
296