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