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