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