1 //
2 /**************************************************************************************************
3 * IOWOW library
4 *
5 * MIT License
6 *
7 * Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *************************************************************************************************/
27
28
29 #include "iowow.h"
30 #include "log/iwlog.h"
31 #include "fs/iwfsmfile.h"
32 #include "utils/iwutils.h"
33 #include "platform/iwp.h"
34
35 #include "iwcfg.h"
36 #include <CUnit/Basic.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <pthread.h>
41
42 static pthread_mutex_t records_mtx;
43
44 #define UNLINK() \
45 unlink("test_fsm_open_close.fsm"); \
46 unlink("test_fsm_uniform_alloc.fsm"); \
47 unlink("test_block_allocation1.fsm"); \
48 unlink("test_block_allocation2.fsm")
49
init_suite(void)50 int init_suite(void) {
51 pthread_mutex_init(&records_mtx, 0);
52 int rc = iw_init();
53 UNLINK();
54 return rc;
55 }
56
clean_suite(void)57 int clean_suite(void) {
58 pthread_mutex_destroy(&records_mtx);
59 UNLINK();
60 return 0;
61 }
62
63 uint64_t iwfs_fsmdbg_number_of_free_areas(IWFS_FSM *f);
64 uint64_t iwfs_fsmdbg_find_next_set_bit(
65 const uint64_t *addr,
66 uint64_t offset_bit,
67 uint64_t max_offset_bit,
68 int *found);
69 uint64_t iwfs_fsmdbg_find_prev_set_bit(
70 const uint64_t *addr,
71 uint64_t offset_bit,
72 uint64_t min_offset_bit,
73 int *found);
74 void iwfs_fsmdbg_dump_fsm_tree(IWFS_FSM *f, const char *hdr);
75 iwrc iwfs_fsmdbg_state(IWFS_FSM *f, IWFS_FSMDBG_STATE *d);
76 iwrc iwfs_fsmdb_dump_fsm_bitmap(IWFS_FSM *f, int blimit);
77
test_fsm_bitmap(void)78 void test_fsm_bitmap(void) {
79 #define BMSZ1 16
80 uint64_t buf[BMSZ1];
81 memset(buf, 0, BMSZ1 * sizeof(uint64_t));
82 int found = 0;
83
84 uint64_t val = IW_HTOILL(0x3UL); /* 0000011 */
85 uint64_t res = iwfs_fsmdbg_find_next_set_bit(&val, 0, sizeof(uint64_t) * 8, &found);
86 CU_ASSERT_EQUAL(found, 1);
87 CU_ASSERT_EQUAL(res, 0);
88
89 res = iwfs_fsmdbg_find_next_set_bit(&val, 1, sizeof(uint64_t) * 8, &found);
90 CU_ASSERT_EQUAL(found, 1);
91 CU_ASSERT_EQUAL(res, 1);
92
93 res = iwfs_fsmdbg_find_next_set_bit(&val, 2, sizeof(uint64_t) * 8, &found);
94 CU_ASSERT_EQUAL(found, 0);
95 CU_ASSERT_EQUAL(res, 0);
96
97 val = 0x3UL << 2; /* 0001100 */
98 val = IW_HTOILL(val);
99 res = iwfs_fsmdbg_find_next_set_bit(&val, 0, sizeof(uint64_t) * 8, &found);
100 CU_ASSERT_EQUAL(found, 1);
101 CU_ASSERT_EQUAL(res, 2);
102
103 val = 0x3UL << 2; /* 0001100 */
104 val = IW_HTOILL(val);
105 res = iwfs_fsmdbg_find_next_set_bit(&val, 2, sizeof(uint64_t) * 8, &found);
106 CU_ASSERT_EQUAL(found, 1);
107 CU_ASSERT_EQUAL(res, 2);
108
109 val = 0x3UL << 2; /* 0001100 */
110 val = IW_HTOILL(val);
111 res = iwfs_fsmdbg_find_next_set_bit(&val, 3, sizeof(uint64_t) * 8, &found);
112 CU_ASSERT_EQUAL(found, 1);
113 CU_ASSERT_EQUAL(res, 3);
114
115 val = 0x3UL << 2; /* 0001100 */
116 val = IW_HTOILL(val);
117 res = iwfs_fsmdbg_find_next_set_bit(&val, 4, sizeof(uint64_t) * 8, &found);
118 CU_ASSERT_EQUAL(found, 0);
119 CU_ASSERT_EQUAL(res, 0);
120
121 val = 0x3UL << 2; /* 0001100 */
122 val = IW_HTOILL(val);
123 res = iwfs_fsmdbg_find_prev_set_bit(&val, 2, 0, &found);
124 CU_ASSERT_EQUAL(found, 0);
125 CU_ASSERT_EQUAL(res, 0);
126
127 val = 0x3UL << 2; /* 0001100 */
128 val = IW_HTOILL(val);
129 res = iwfs_fsmdbg_find_prev_set_bit(&val, 3, 0, &found);
130 CU_ASSERT_EQUAL(found, 1);
131 CU_ASSERT_EQUAL(res, 2);
132
133 val = 0x2UL; /* 00000010 */
134 val = IW_HTOILL(val);
135 res = iwfs_fsmdbg_find_next_set_bit(&val, 0, sizeof(uint64_t) * 8, &found);
136 CU_ASSERT_EQUAL(found, 1);
137 CU_ASSERT_EQUAL(res, 1);
138
139 val = 0x2UL; /* 00000010 */
140 val = IW_HTOILL(val);
141 res = iwfs_fsmdbg_find_next_set_bit(&val, 1, sizeof(uint64_t) * 8, &found);
142 CU_ASSERT_EQUAL(found, 1);
143 CU_ASSERT_EQUAL(res, 1);
144
145 val = 0x4UL; /* 00000100 */
146 val = IW_HTOILL(val);
147 res = iwfs_fsmdbg_find_next_set_bit(&val, 0, sizeof(uint64_t) * 8, &found);
148 CU_ASSERT_EQUAL(found, 1);
149 CU_ASSERT_EQUAL(res, 2);
150
151 val = 0x4UL; /* 00000100 */
152 val = IW_HTOILL(val);
153 res = iwfs_fsmdbg_find_next_set_bit(&val, 1, sizeof(uint64_t) * 8, &found);
154 CU_ASSERT_EQUAL(found, 1);
155 CU_ASSERT_EQUAL(res, 2);
156
157 val = 0x4UL; /* 00000100 */
158 val = IW_HTOILL(val);
159 res = iwfs_fsmdbg_find_next_set_bit(&val, 2, sizeof(uint64_t) * 8, &found);
160 CU_ASSERT_EQUAL(found, 1);
161 CU_ASSERT_EQUAL(res, 2);
162
163 val = ~0UL;
164 val = IW_HTOILL(val);
165 res = iwfs_fsmdbg_find_prev_set_bit(&val, 0, 0, &found);
166 CU_ASSERT_EQUAL(found, 0);
167 CU_ASSERT_EQUAL(res, 0);
168
169 val = 0x1UL; /* 00000001 */
170 val = IW_HTOILL(val);
171 res = iwfs_fsmdbg_find_prev_set_bit(&val, 1, 0, &found);
172 CU_ASSERT_EQUAL(found, 1);
173 CU_ASSERT_EQUAL(res, 0);
174
175 val = 0x2UL; /* 00000010 */
176 val = IW_HTOILL(val);
177 res = iwfs_fsmdbg_find_prev_set_bit(&val, 10, 0, &found);
178 CU_ASSERT_EQUAL(found, 1);
179 CU_ASSERT_EQUAL(res, 1);
180
181 buf[0] = IW_HTOILL(0x1UL);
182 res = iwfs_fsmdbg_find_prev_set_bit(buf, sizeof(uint64_t) * 8 + 15, 0, &found);
183 CU_ASSERT_EQUAL(found, 1);
184 CU_ASSERT_EQUAL(res, 0);
185
186 buf[0] = IW_HTOILL(0x2UL);
187 res = iwfs_fsmdbg_find_prev_set_bit(buf, sizeof(uint64_t) * 8 + 15, 0, &found);
188 CU_ASSERT_EQUAL(found, 1);
189 CU_ASSERT_EQUAL(res, 1);
190
191 buf[0] = IW_HTOILL(0x4UL);
192 res = iwfs_fsmdbg_find_prev_set_bit(buf, sizeof(uint64_t) * 8 + 15, 0, &found);
193 CU_ASSERT_EQUAL(found, 1);
194 CU_ASSERT_EQUAL(res, 2);
195
196 buf[0] = IW_HTOILL(0x8UL);
197 res = iwfs_fsmdbg_find_prev_set_bit(buf, sizeof(uint64_t) * 8 + 15, 0, &found);
198 CU_ASSERT_EQUAL(found, 1);
199 CU_ASSERT_EQUAL(res, 3);
200
201 buf[1] = IW_HTOILL(0x2UL);
202 res = iwfs_fsmdbg_find_prev_set_bit(buf, 2 * sizeof(uint64_t) * 8 + 17, 0, &found);
203 CU_ASSERT_EQUAL(found, 1);
204 CU_ASSERT_EQUAL(res, 64 + 1);
205
206 /* 0[0100000000000..|00]000 */
207 buf[0] = IW_HTOILL(0x4UL);
208 buf[1] = IW_HTOILL(0x0UL);
209 buf[2] = IW_HTOILL(0x0UL);
210 res = iwfs_fsmdbg_find_prev_set_bit(buf, (sizeof(uint64_t) * 8 + 2), 0, &found);
211 CU_ASSERT_EQUAL(found, 1);
212 CU_ASSERT_EQUAL(res, 2);
213
214 buf[0] = IW_HTOILL(0x4UL);
215 buf[1] = IW_HTOILL(0x4UL);
216 buf[2] = IW_HTOILL(0x0UL);
217 res = iwfs_fsmdbg_find_prev_set_bit(buf, sizeof(uint64_t) * 8 + 5, 0, &found);
218 CU_ASSERT_EQUAL(found, 1);
219 CU_ASSERT_EQUAL(res, 64 + 2);
220 }
221
test_fsm_open_close(void)222 void test_fsm_open_close(void) {
223 iwrc rc;
224 IWFS_FSM_OPTS opts = {
225 .exfile = {
226 .file = { .path = "test_fsm_open_close.fsm", .lock_mode = IWP_WLOCK },
227 .rspolicy = iw_exfile_szpolicy_fibo,
228 .initial_size = 0
229 },
230 .bpow = 6,
231 .hdrlen = 64,
232 .oflags = IWFSM_STRICT
233 };
234
235 size_t aunit = iwp_alloc_unit();
236 IWFS_FSMDBG_STATE state1, state2;
237 IWFS_FSM fsm;
238 rc = iwfs_fsmfile_open(&fsm, &opts);
239 CU_ASSERT_FALSE_FATAL(rc);
240 rc = iwfs_fsmdbg_state(&fsm, &state1);
241 CU_ASSERT_FALSE(rc);
242 CU_ASSERT_TRUE((aunit * 8 - state1.lfbklen) * 64 == 2 * aunit); // allocated first 2 pages
243 rc = fsm.close(&fsm);
244 CU_ASSERT_FALSE_FATAL(rc);
245
246 rc = iwfs_fsmfile_open(&fsm, &opts);
247 CU_ASSERT_FALSE_FATAL(rc);
248 rc = iwfs_fsmdbg_state(&fsm, &state2);
249 CU_ASSERT_FALSE(rc);
250 CU_ASSERT_TRUE((aunit * 8 - state2.lfbklen) * 64 == 2 * aunit);
251 CU_ASSERT_EQUAL(state1.bmlen, state2.bmlen);
252 CU_ASSERT_EQUAL(state1.bmoff, state2.bmoff);
253 CU_ASSERT_EQUAL(state1.lfbklen, state2.lfbklen);
254 CU_ASSERT_EQUAL(state1.lfbkoff, state2.lfbkoff);
255 CU_ASSERT_EQUAL(state1.state.block_size, state2.state.block_size);
256 CU_ASSERT_EQUAL(state1.state.blocks_num, state2.state.blocks_num);
257 CU_ASSERT_EQUAL(state1.state.hdrlen, state2.state.hdrlen);
258 CU_ASSERT_EQUAL(state1.state.oflags, state2.state.oflags);
259 CU_ASSERT_EQUAL(state1.state.exfile.fsize, state2.state.exfile.fsize);
260 CU_ASSERT_EQUAL(state1.state.exfile.fsize, 2 * aunit);
261 rc = fsm.close(&fsm);
262 CU_ASSERT_FALSE_FATAL(rc);
263 }
264
265 void test_fsm_uniform_alloc_impl(int mmap_all);
266
test_fsm_uniform_alloc(void)267 void test_fsm_uniform_alloc(void) {
268 test_fsm_uniform_alloc_impl(0);
269 }
270
test_fsm_uniform_alloc_mmap_all(void)271 void test_fsm_uniform_alloc_mmap_all(void) {
272 test_fsm_uniform_alloc_impl(1);
273 }
274
test_fsm_uniform_alloc_impl(int mmap_all)275 void test_fsm_uniform_alloc_impl(int mmap_all) {
276 iwrc rc;
277 IWFS_FSMDBG_STATE state1, state2;
278 IWFS_FSM_OPTS opts = {
279 .exfile = {
280 .file = {
281 .path = "test_fsm_uniform_alloc.fsm",
282 .lock_mode = IWP_WLOCK,
283 .omode = IWFS_OTRUNC
284 },
285 .rspolicy = iw_exfile_szpolicy_fibo
286 },
287 .bpow = 6,
288 .hdrlen = 64,
289 .oflags = IWFSM_STRICT,
290 .mmap_all = mmap_all
291 };
292
293 typedef struct {
294 off_t addr;
295 off_t len;
296 } ASLOT;
297
298 const int bsize = 512;
299 #define bcnt 4096
300 ASLOT aslots[bcnt];
301
302 IWFS_FSM fsm;
303 rc = iwfs_fsmfile_open(&fsm, &opts);
304 CU_ASSERT_FALSE_FATAL(rc);
305
306 rc = iwfs_fsmdbg_state(&fsm, &state1);
307 CU_ASSERT_FALSE_FATAL(rc);
308 CU_ASSERT_EQUAL_FATAL(state1.state.exfile.file.ostatus, IWFS_OPEN_NEW);
309
310 for (int i = 0; i < bcnt; ++i) {
311 aslots[i].addr = 0;
312 rc = fsm.allocate(&fsm, bsize, &aslots[i].addr, &aslots[i].len, 0);
313 CU_ASSERT_FALSE_FATAL(rc);
314 }
315 rc = iwfs_fsmdbg_state(&fsm, &state1);
316 CU_ASSERT_FALSE_FATAL(rc);
317
318 if (iwp_alloc_unit() == 4096) { // todo check for system with different alloc units
319 CU_ASSERT_EQUAL(state1.bmlen, 8192);
320 CU_ASSERT_EQUAL(state1.bmoff, 2097152);
321 CU_ASSERT_EQUAL(state1.lfbklen, 32632);
322 CU_ASSERT_EQUAL(state1.lfbkoff, 32904);
323 CU_ASSERT_EQUAL(state1.state.blocks_num, 65536);
324 CU_ASSERT_EQUAL(state1.state.free_segments_num, 2);
325 CU_ASSERT_EQUAL(state1.state.avg_alloc_size, 8);
326 CU_ASSERT_EQUAL(state1.state.alloc_dispersion, 0);
327 }
328
329
330 rc = fsm.close(&fsm);
331 CU_ASSERT_FALSE_FATAL(rc);
332
333 return;
334
335 opts.exfile.file.omode = IWFS_OREAD;
336 rc = iwfs_fsmfile_open(&fsm, &opts);
337 CU_ASSERT_FALSE_FATAL(rc);
338
339 rc = iwfs_fsmdbg_state(&fsm, &state2);
340 CU_ASSERT_FALSE_FATAL(rc);
341 CU_ASSERT_EQUAL_FATAL(state2.state.exfile.file.ostatus, IWFS_OPEN_EXISTING);
342 CU_ASSERT_FALSE(state2.state.exfile.file.opts.omode & IWFS_OWRITE);
343
344 CU_ASSERT_EQUAL(state1.bmlen, state2.bmlen);
345 CU_ASSERT_EQUAL(state1.bmoff, state2.bmoff);
346 CU_ASSERT_EQUAL(state1.lfbklen, state2.lfbklen);
347 CU_ASSERT_EQUAL(state1.lfbkoff, state2.lfbkoff);
348 CU_ASSERT_EQUAL(state1.state.blocks_num, state2.state.blocks_num);
349 CU_ASSERT_EQUAL(state1.state.free_segments_num, state2.state.free_segments_num);
350 CU_ASSERT_EQUAL(state1.state.avg_alloc_size, state2.state.avg_alloc_size);
351 CU_ASSERT_EQUAL(state1.state.alloc_dispersion, state2.state.alloc_dispersion);
352
353 uint32_t ibuf;
354 off_t ilen;
355 rc = fsm.allocate(&fsm, sizeof(ibuf), (void*) &ibuf, &ilen, 0);
356 CU_ASSERT_EQUAL(rc, IW_ERROR_READONLY);
357
358 rc = fsm.close(&fsm);
359 CU_ASSERT_FALSE_FATAL(rc);
360
361 opts.exfile.file.omode = IWFS_OWRITE;
362 rc = iwfs_fsmfile_open(&fsm, &opts);
363 CU_ASSERT_FALSE_FATAL(rc);
364
365 rc = iwfs_fsmdbg_state(&fsm, &state1);
366 CU_ASSERT_FALSE_FATAL(rc);
367
368 if (iwp_alloc_unit() == 4096) { // todo check for system with different alloc units
369 CU_ASSERT_EQUAL(state1.bmlen, 8192);
370 CU_ASSERT_EQUAL(state1.bmoff, 2097152);
371 CU_ASSERT_EQUAL(state1.lfbklen, 32632);
372 CU_ASSERT_EQUAL(state1.lfbkoff, 32904);
373 CU_ASSERT_EQUAL(state1.state.blocks_num, 65536);
374 CU_ASSERT_EQUAL(state1.state.free_segments_num, 2);
375 CU_ASSERT_EQUAL(state1.state.avg_alloc_size, 8);
376 CU_ASSERT_EQUAL(state1.state.alloc_dispersion, 0);
377 }
378
379 int i = 0;
380 for ( ; i < bcnt; ++i) {
381 rc = fsm.deallocate(&fsm, aslots[i].addr, aslots[i].len);
382 if (rc) {
383 iwlog_ecode_error3(rc);
384 }
385 CU_ASSERT_FALSE_FATAL(rc);
386 }
387
388 rc = fsm.close(&fsm);
389 CU_ASSERT_FALSE_FATAL(rc);
390
391 if (iwp_alloc_unit() == 4096) {
392 IWP_FILE_STAT st;
393 rc = iwp_fstat("test_fsm_uniform_alloc.fsm", &st);
394 CU_ASSERT_EQUAL_FATAL(rc, 0);
395 CU_ASSERT_EQUAL(st.size, iwp_alloc_unit() * 3);
396 }
397 }
398
399 typedef struct FSMREC {
400 int64_t offset;
401 int64_t length;
402 int locked;
403 struct FSMREC *prev;
404 struct FSMREC *next;
405 } FSMREC;
406
407 typedef struct {
408 int maxrecs;
409 int avgrecsz;
410 IWFS_FSM *fsm;
411 volatile int numrecs;
412 FSMREC *reclist;
413 FSMREC *head;
414 int blkpow;
415 } FSMRECTASK;
416
417 //!!!! TODO this test is not good for multithreaded env, refactoring needed
418
recordsthr(void * op)419 static void* recordsthr(void *op) {
420 FSMRECTASK *task = op;
421 iwrc rc;
422 FSMREC *rec, *tmp;
423 IWFS_FSM *fsm = task->fsm;
424 size_t sp;
425
426 const int maxrsize = IW_ROUNDUP(task->avgrecsz * 3, 1 << task->blkpow);
427 char *rdata = malloc(maxrsize);
428 char *rdata2 = malloc(maxrsize);
429 int numrec;
430 int a, i = 0;
431
432 pthread_mutex_lock(&records_mtx);
433 numrec = task->numrecs;
434 pthread_mutex_unlock(&records_mtx);
435
436 while (numrec < task->maxrecs) {
437 ++i;
438 rec = malloc(sizeof(*rec));
439 memset(rec, 0, sizeof(*rec));
440 rec->locked = 1;
441 do {
442 rec->length = iwu_rand_dnorm((double) task->avgrecsz, task->avgrecsz / 3.0);
443 } while (rec->length <= 0 || rec->length > maxrsize);
444
445 /* Allocate record */
446 rc = fsm->allocate(fsm, rec->length, &rec->offset, &rec->length, 0);
447 if (rc) {
448 iwlog_ecode_error3(rc);
449 }
450 CU_ASSERT_FALSE_FATAL(rc);
451 memset(rdata, (rec->offset >> task->blkpow), maxrsize);
452 CU_ASSERT_TRUE_FATAL(maxrsize >= rec->length);
453 rc = fsm->write(fsm, rec->offset, rdata, rec->length, &sp);
454 if (rc) {
455 iwlog_ecode_error3(rc);
456 }
457 CU_ASSERT_FALSE_FATAL(rc);
458 CU_ASSERT_EQUAL_FATAL(rec->length, sp);
459
460 pthread_mutex_lock(&records_mtx);
461 if (task->reclist != rec) {
462 tmp = task->reclist;
463 task->reclist = rec;
464 task->reclist->prev = tmp;
465 tmp->next = task->reclist;
466 rec->locked = 0;
467 }
468 ++(task->numrecs);
469 numrec = task->numrecs;
470 pthread_mutex_unlock(&records_mtx);
471 }
472
473 rec = task->reclist;
474 i = 0;
475 while (rec && rec->prev) {
476 ++i;
477 a = rand() % 3;
478 if ((a == 0) || (a == 1)) { /* realloc */
479 pthread_mutex_lock(&records_mtx);
480 if (rec->locked) {
481 rec = rec->next;
482 pthread_mutex_unlock(&records_mtx);
483 continue;
484 }
485 rec->locked = 1;
486 pthread_mutex_unlock(&records_mtx);
487
488 rc = fsm->deallocate(fsm, rec->offset, rec->length);
489 if (rc) {
490 iwlog_ecode_error3(rc);
491 }
492 CU_ASSERT_FALSE_FATAL(rc);
493
494 /* allocate */
495 do {
496 rec->length = iwu_rand_dnorm((double) task->avgrecsz, task->avgrecsz / 3.0);
497 } while (rec->length <= 0 || rec->length > maxrsize);
498
499 rc = fsm->allocate(fsm, rec->length, &rec->offset, &rec->length, 0);
500 if (rc) {
501 iwlog_ecode_error3(rc);
502 CU_ASSERT_FALSE(rc);
503 break;
504 }
505
506 if (rec->length <= maxrsize) {
507 /* Write a record */
508 memset(rdata, (rec->offset >> task->blkpow), maxrsize);
509 rc = fsm->write(fsm, rec->offset, rdata, rec->length, &sp);
510 if (rc) {
511 iwlog_ecode_error3(rc);
512 }
513 CU_ASSERT_FALSE_FATAL(rc);
514 } else {
515 /* printf("Ops %lld %lld\n\n", rl >> task->blkpow, rec->length >>
516 * task->blkpow); */
517 CU_ASSERT_TRUE_FATAL(0);
518 assert(0);
519 }
520
521 pthread_mutex_lock(&records_mtx);
522 rec->locked = 0;
523 pthread_mutex_unlock(&records_mtx);
524 } else {
525 // TODO
526
527 // rc = fsm->lread(fsm, rec->offset, rdata, rec->length, &sp);
528 // CU_ASSERT_FALSE_FATAL(rc);
529 // CU_ASSERT_EQUAL_FATAL(sp, rec->length);
530 // memset(rdata2, (rec->offset >> task->blkpow), maxrsize);
531 // int cmp = memcmp(rdata, rdata2, rec->length);
532 // CU_ASSERT_FALSE_FATAL(cmp);
533 }
534 rec = rec->prev;
535 }
536 free(rdata);
537 free(rdata2);
538 return 0;
539 }
540
test_block_allocation_impl(int mmap_all,int nthreads,int numrec,int avgrecsz,int blkpow,const char * path)541 void test_block_allocation_impl(int mmap_all, int nthreads, int numrec, int avgrecsz, int blkpow, const char *path) {
542 iwrc rc;
543 pthread_t *tlist = malloc(nthreads * sizeof(pthread_t));
544
545 IWFS_FSM_OPTS opts = {
546 .exfile = {
547 .file = { .path = path, .omode = IWFS_OTRUNC },
548 .rspolicy = iw_exfile_szpolicy_fibo
549 },
550 .bpow = blkpow,
551 .oflags = IWFSM_STRICT,
552 .mmap_all = mmap_all
553 };
554
555 FSMRECTASK task;
556 FSMREC *rec, *prev;
557 IWFS_FSM fsm;
558 rc = iwfs_fsmfile_open(&fsm, &opts);
559 CU_ASSERT_FALSE_FATAL(rc);
560
561 memset(&task, 0, sizeof(task));
562 task.numrecs = 0;
563 task.maxrecs = numrec;
564 task.avgrecsz = avgrecsz;
565 task.fsm = &fsm;
566 task.reclist = malloc(sizeof(*task.reclist));
567 memset(task.reclist, 0, sizeof(*task.reclist));
568 task.head = task.reclist;
569 task.blkpow = opts.bpow;
570
571 for (int i = 0; i < nthreads; ++i) {
572 CU_ASSERT_EQUAL_FATAL(pthread_create(&tlist[i], 0, recordsthr, &task), 0);
573 }
574 for (int i = 0; i < nthreads; ++i) {
575 pthread_join(tlist[i], 0);
576 }
577
578 /* Cleanup */
579 rec = task.reclist;
580 while (rec) {
581 prev = rec->prev;
582 free(rec);
583 rec = prev;
584 }
585 rc = fsm.close(&fsm);
586 CU_ASSERT_FALSE_FATAL(rc);
587 free(tlist);
588 }
589
590 void test_block_allocation1_impl(int mmap_all);
591
test_block_allocation1(void)592 void test_block_allocation1(void) {
593 test_block_allocation1_impl(0);
594 }
595
test_block_allocation1_mmap_all(void)596 void test_block_allocation1_mmap_all(void) {
597 test_block_allocation1_impl(1);
598 }
599
test_block_allocation1_impl(int mmap_all)600 void test_block_allocation1_impl(int mmap_all) {
601 iwrc rc;
602 IWFS_FSM fsm;
603 int psize = iwp_alloc_unit();
604 IWFS_FSM_OPTS opts = {
605 .exfile = {
606 .file = {
607 .path = "test_block_allocation1.fsm",
608 .omode = IWFS_OTRUNC
609 }
610 },
611 .hdrlen = psize - 2 * 64,
612 .bpow = 6,
613 .oflags = IWFSM_STRICT,
614 .mmap_all = mmap_all
615 };
616
617 off_t oaddr = 0;
618 off_t olen;
619 // off_t sp, sp2;
620 int bsize = (1 << opts.bpow); /* byte block */
621 const int hoff = (2 * psize);
622
623 rc = iwfs_fsmfile_open(&fsm, &opts);
624 CU_ASSERT_FALSE_FATAL(rc);
625
626 /* Next alloc status:
627 xxxxxxx */
628 rc = fsm.allocate(&fsm, 3 * bsize, &oaddr, &olen, 0);
629 CU_ASSERT_FALSE_FATAL(rc);
630 CU_ASSERT_EQUAL(oaddr, hoff + 0);
631 CU_ASSERT_EQUAL(olen, 3 * bsize);
632
633 rc = fsm.allocate(&fsm, 4 * bsize, &oaddr, &olen, 0);
634 CU_ASSERT_FALSE_FATAL(rc);
635 CU_ASSERT_EQUAL(oaddr, hoff + 3 * bsize);
636 CU_ASSERT_EQUAL(olen, 4 * bsize);
637
638 rc = fsm.deallocate(&fsm, 1 * bsize, 1 * bsize);
639 CU_ASSERT_EQUAL(rc, IWFS_ERROR_FSM_SEGMENTATION);
640
641
642 /* Next alloc status:
643 x*xxxxx */
644 rc = fsm.deallocate(&fsm, hoff + 1 * bsize, 1 * bsize);
645 CU_ASSERT_FALSE_FATAL(rc);
646
647 /* Next alloc status:
648 xxxxxxx */
649 rc = fsm.allocate(&fsm, 1 * bsize, &oaddr, &olen, 0);
650 CU_ASSERT_FALSE_FATAL(rc);
651 CU_ASSERT_EQUAL(oaddr, hoff + 1 * bsize);
652 CU_ASSERT_EQUAL(olen, 1 * bsize);
653
654 /* Next alloc status:
655 x**xxxx */
656 rc = fsm.deallocate(&fsm, oaddr, 2 * bsize);
657 CU_ASSERT_FALSE_FATAL(rc);
658
659 /* Next alloc status:
660 x**x**x */
661 rc = fsm.deallocate(&fsm, hoff + 4 * bsize, 2 * bsize);
662 CU_ASSERT_FALSE_FATAL(rc);
663
664 oaddr = hoff + 5 * bsize; /* Test a free block location suggestion */
665 rc = fsm.allocate(&fsm, 2 * bsize, &oaddr, &olen, 0);
666 CU_ASSERT_FALSE_FATAL(rc);
667 CU_ASSERT_EQUAL(oaddr, hoff + 4 * bsize);
668 CU_ASSERT_EQUAL(olen, 2 * bsize);
669
670 /* Next alloc status:
671 x**x**x */
672 rc = fsm.deallocate(&fsm, hoff + 4 * bsize, 2 * bsize);
673 CU_ASSERT_FALSE_FATAL(rc);
674
675 /* Next alloc status:
676 x*****x */
677 CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 3);
678 rc = fsm.deallocate(&fsm, hoff + 3 * bsize, 1 * bsize);
679 CU_ASSERT_FALSE_FATAL(rc);
680 CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 2);
681
682 /* Next alloc status:
683 xxxxxxx */
684 oaddr = hoff;
685 rc = fsm.allocate(&fsm, 5 * bsize, &oaddr, &olen, 0);
686 CU_ASSERT_FALSE_FATAL(rc);
687 CU_ASSERT_EQUAL(oaddr, hoff + 1 * bsize);
688 CU_ASSERT_EQUAL(olen, 5 * bsize);
689 CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 1);
690
691 // Test reallocate
692 /* Next alloc status:
693 * xxx*** */
694 rc = fsm.deallocate(&fsm, hoff + 4 * bsize, 3 * bsize);
695 CU_ASSERT_FALSE_FATAL(rc);
696 rc = fsm.deallocate(&fsm, hoff, 1 * bsize);
697 CU_ASSERT_FALSE_FATAL(rc);
698 CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 2);
699
700 /* Next alloc status:
701 * xx**** */
702 oaddr = hoff + 1 * bsize;
703 olen = 3 * bsize;
704 rc = fsm.reallocate(&fsm, 2 * bsize, &oaddr, &olen, 0);
705 CU_ASSERT_FALSE_FATAL(rc);
706 CU_ASSERT_EQUAL(oaddr, hoff + 1 * bsize);
707 CU_ASSERT_EQUAL(olen, 2 * bsize);
708 CU_ASSERT_EQUAL(iwfs_fsmdbg_number_of_free_areas(&fsm), 2);
709
710 /* Next alloc status:
711 * xxxxxx */
712 // rc = fsm.reallocate(&fsm, 6 * bsize, &oaddr, &olen, 0);
713 // CU_ASSERT_FALSE_FATAL(rc);
714 // CU_ASSERT_EQUAL(oaddr, hoff + 1 * bsize);
715 // CU_ASSERT_EQUAL(olen, 6 * bsize);
716 //
717 // /* Next alloc status:
718 // *xx***x */
719 // rc = fsm.deallocate(&fsm, hoff + 3 * bsize, 3 * bsize);
720 // CU_ASSERT_FALSE_FATAL(rc);
721
722 // todo
723 // oaddr = hoff + 1 * bsize;
724 // olen = 1 * bsize;
725 // rc = fsm.reallocate(&fsm, 2 * bsize, &oaddr, &olen, 0);
726 // CU_ASSERT_EQUAL(oaddr, hoff);
727 // CU_ASSERT_EQUAL(olen, 2 * bsize);
728
729 rc = fsm.close(&fsm);
730 CU_ASSERT_FALSE_FATAL(rc);
731 }
732
733 void test_block_allocation2_impl(int mmap_all);
734
test_block_allocation2()735 void test_block_allocation2() {
736 test_block_allocation2_impl(0);
737 }
738
test_block_allocation2_mmap_all()739 void test_block_allocation2_mmap_all() {
740 test_block_allocation2_impl(1);
741 }
742
test_block_allocation2_impl(int mmap_all)743 void test_block_allocation2_impl(int mmap_all) {
744 test_block_allocation_impl(mmap_all, 4, 50000, 493, 6, "test_block_allocation2.fsm");
745 test_block_allocation_impl(mmap_all, 4, 50000, 5, 6, "test_block_allocation2.fsm");
746 }
747
main()748 int main() {
749 CU_pSuite pSuite = NULL;
750
751 /* Initialize the CUnit test registry */
752 if (CUE_SUCCESS != CU_initialize_registry()) {
753 return CU_get_error();
754 }
755
756 /* Add a suite to the registry */
757 pSuite = CU_add_suite("iwfs_test2", init_suite, clean_suite);
758
759 if (NULL == pSuite) {
760 CU_cleanup_registry();
761 return CU_get_error();
762 }
763
764 /* Add the tests to the suite */
765 if ( (NULL == CU_add_test(pSuite, "test_fsm_bitmap", test_fsm_bitmap))
766 || (NULL == CU_add_test(pSuite, "test_fsm_open_close", test_fsm_open_close))
767 || (NULL == CU_add_test(pSuite, "test_fsm_uniform_alloc", test_fsm_uniform_alloc))
768 || (NULL == CU_add_test(pSuite, "test_fsm_uniform_alloc_mmap_all", test_fsm_uniform_alloc_mmap_all))
769 || (NULL == CU_add_test(pSuite, "test_block_allocation1", test_block_allocation1))
770 || (NULL == CU_add_test(pSuite, "test_block_allocation1_mmap_all", test_block_allocation1_mmap_all))
771 || (NULL == CU_add_test(pSuite, "test_block_allocation2", test_block_allocation2))
772 || (NULL == CU_add_test(pSuite, "test_block_allocation2_mmap_all", test_block_allocation2_mmap_all))) {
773 CU_cleanup_registry();
774 return CU_get_error();
775 }
776
777 /* Run all tests using the CUnit Basic interface */
778 CU_basic_set_mode(CU_BRM_VERBOSE);
779 CU_basic_run_tests();
780 int ret = CU_get_error() || CU_get_number_of_failures();
781 CU_cleanup_registry();
782 return ret;
783 }
784