1 #include "iowow.h"
2 #include "log/iwlog.h"
3 #include "fs/iwfsmfile.h"
4 #include "utils/iwutils.h"
5
6 #include "iwcfg.h"
7 #include <CUnit/Basic.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11
12 #include "utils/kbtree.h"
13
14 #define NRECS 10000
15 #define RECSZ (10*1024)
16
17 #define UNLINK() \
18 unlink("test_fsm_stress.data"); \
19 unlink("test_fsm_stress1.fsm"); \
20 unlink("test_fsm_stress2.fsm")
21
22 typedef struct SREC {
23 int id;
24 off_t addr;
25 off_t rsz;
26 off_t alc_addr;
27 off_t alc_len;
28 bool freed;
29 bool reallocated;
30 } SREC;
31
32 #define _srec_cmp(r1, r2) ((r1).id - (r2).id)
33
KBTREE_INIT(rt,SREC,_srec_cmp)34 KBTREE_INIT(rt, SREC, _srec_cmp)
35
36 FILE *fstress1;
37 kbtree_t(rt) *rt;
38
39 int init_suite(void) {
40 UNLINK();
41 int rc = iw_init();
42 RCRET(rc);
43
44 rt = kb_init(rt, KB_DEFAULT_SIZE);
45
46 off_t addr = 0;
47 uint64_t ts;
48 rc = iwp_current_time_ms(&ts, false);
49 RCRET(rc);
50 ts = IW_SWAB64(ts);
51 ts >>= 32;
52 iwu_rand_seed(ts);
53
54 printf("Generating stress data file: test_fsm_stress1.data, random seed: %" PRIu64, ts);
55 fstress1 = fopen("test_fsm_stress.data", "w+");
56 char *buf = malloc(RECSZ + 1);
57 for (int i = 0, j; i < NRECS; ++i) {
58 int rsz = iwu_rand_range(RECSZ + 1);
59 if (rsz < 1) {
60 rsz = 1;
61 }
62 for (j = 0; j < rsz; ++j) {
63 buf[j] = ' ' + iwu_rand_range(95);
64 }
65 buf[j] = '\0';
66 fprintf(fstress1, "%08d:%s\n", i, buf);
67 SREC rec = {
68 .id = i,
69 .addr = addr,
70 .rsz = rsz,
71 .freed = false
72 };
73 addr += (8 + 1 + rsz + 1);
74 kb_putp(rt, rt, &rec);
75 }
76 free(buf);
77 return rc;
78 }
79
clean_suite(void)80 int clean_suite(void) {
81 if (fstress1) {
82 fclose(fstress1);
83 fstress1 = 0;
84 }
85 kb_destroy(rt, rt);
86 UNLINK();
87 return 0;
88 }
89
test_stress(char * path,int bpow,bool mmap_all)90 void test_stress(char *path, int bpow, bool mmap_all) {
91 IWFS_FSM fsm;
92 IWFS_FSM_OPTS opts = {
93 .exfile = {
94 .file = {
95 .path = path,
96 .omode = IWFS_OTRUNC
97 }
98 },
99 .hdrlen = 62,
100 .bpow = bpow,
101 .oflags = IWFSM_STRICT,
102 .mmap_all = mmap_all
103 };
104 iwrc rc = iwfs_fsmfile_open(&fsm, &opts);
105 CU_ASSERT_FALSE_FATAL(rc);
106
107 fprintf(stderr, "\nRunning allocations...\n");
108
109 char *buf = malloc(2 * RECSZ + 1);
110 for (int i = 0; i < NRECS; ++i) {
111 size_t sp;
112 SREC k = {.id = i};
113 iwfs_fsm_aflags aflags = IWFSM_SOLID_ALLOCATED_SPACE | IWFSM_ALLOC_NO_OVERALLOCATE;
114 uint32_t rop = iwu_rand_u32();
115 if (i > 0 && (!(rop % 3) || !(rop % 5))) {
116 k.id = iwu_rand_range(i);
117 SREC *pr = kb_getp(rt, rt, &k);
118 CU_ASSERT_PTR_NOT_NULL_FATAL(pr);
119 if (!pr->freed) {
120 if ((rop % 3)) { // deallocate previous
121 //fprintf(stderr, "%05d D %ld:%ld\n", pr->id, pr->alc_addr, pr->alc_len);
122 pr->freed = true;
123 rc = fsm.deallocate(&fsm, pr->alc_addr, pr->alc_len);
124 CU_ASSERT_FALSE_FATAL(rc);
125 } else if (!pr->reallocated && !(rop % 5)) { // reallocate previous
126 //fprintf(stderr, "%05d R %ld:%ld\n", pr->id, pr->alc_addr, pr->alc_len);
127 pr->reallocated = true;
128 uint32_t nlen = iwu_rand_range(2 * pr->rsz + 1);
129 if (nlen < 1) {
130 nlen = 1;
131 }
132 rc = fsm.reallocate(&fsm, nlen, &pr->alc_addr, &pr->alc_len, IWFSM_SOLID_ALLOCATED_SPACE);
133 CU_ASSERT_FALSE_FATAL(rc);
134 if (pr->alc_len > pr->rsz) {
135 rc = fsm.read(&fsm, pr->alc_addr, buf, pr->rsz, &sp);
136 CU_ASSERT_FALSE_FATAL(rc);
137 CU_ASSERT_EQUAL_FATAL(pr->rsz, sp);
138 off_t wsz = pr->alc_len - pr->rsz;
139 while (wsz > 0) {
140 int wc = MIN(wsz, pr->rsz);
141 rc = fsm.write(&fsm, pr->alc_addr + pr->alc_len - wsz, buf, wc, &sp);
142 CU_ASSERT_FALSE_FATAL(rc);
143 CU_ASSERT_EQUAL_FATAL(wc, sp);
144 wsz -= wc;
145 }
146 }
147 }
148 }
149 }
150
151 k.id = i;
152 SREC *r = kb_getp(rt, rt, &k);
153 CU_ASSERT_PTR_NOT_NULL_FATAL(r);
154 fseek(fstress1, r->addr + 8 + 1, SEEK_SET);
155 fread(buf, r->rsz, 1, fstress1);
156 buf[r->rsz + 1] = '\0';
157
158 rc = fsm.allocate(&fsm, r->rsz, &r->alc_addr, &r->alc_len, aflags);
159 //fprintf(stderr, "%05d A %ld:%ld\n", i, r->alc_addr, r->alc_len);
160 CU_ASSERT_FALSE_FATAL(rc);
161 CU_ASSERT_TRUE_FATAL(r->alc_len >= r->rsz);
162 rc = fsm.write(&fsm, r->alc_addr, buf, r->rsz, &sp);
163 CU_ASSERT_FALSE_FATAL(rc);
164 CU_ASSERT_EQUAL_FATAL(sp, r->rsz);
165
166 if (r->alc_len > r->rsz) {
167 off_t wsz = r->alc_len - r->rsz;
168 while (wsz > 0) {
169 int wc = MIN(wsz, r->rsz);
170 rc = fsm.write(&fsm, r->alc_addr + r->alc_len - wsz, buf, wc, &sp);
171 CU_ASSERT_FALSE_FATAL(rc);
172 CU_ASSERT_EQUAL_FATAL(wc, sp);
173 wsz -= wc;
174 }
175 }
176 }
177 CU_ASSERT_FALSE_FATAL(fsm.close(&fsm));
178
179 fprintf(stderr, "Checking data\n");
180 opts.exfile.file.omode = 0;
181 rc = iwfs_fsmfile_open(&fsm, &opts);
182 CU_ASSERT_FALSE_FATAL(rc);
183
184 char *buf2 = malloc(2 * RECSZ + 1);
185 for (int i = 0; i < NRECS; ++i) {
186 size_t sp;
187 SREC k = {.id = i};
188 SREC *r = kb_getp(rt, rt, &k);
189 CU_ASSERT_PTR_NOT_NULL_FATAL(r);
190 if (r->freed) {
191 continue;
192 }
193 CU_ASSERT_TRUE(r->alc_len <= 2 * RECSZ + 1);
194 fseek(fstress1, r->addr + 8 + 1, SEEK_SET);
195 fread(buf, r->rsz, 1, fstress1);
196 buf[r->rsz + 1] = '\0';
197
198 off_t rn = MIN(r->rsz, r->alc_len);
199 if (r->alc_len < r->rsz) {
200 CU_ASSERT_TRUE_FATAL(r->reallocated);
201 }
202 memset(buf2, 0, rn); // 20736
203 rc = fsm.read(&fsm, r->alc_addr, buf2, rn, &sp);
204 CU_ASSERT_FALSE_FATAL(rc);
205 CU_ASSERT_EQUAL_FATAL(rn, sp);
206 int ri = memcmp(buf, buf2, rn);
207 CU_ASSERT_EQUAL_FATAL(ri, 0);
208
209 if (rn < r->alc_len) {
210 while (rn < r->alc_len) {
211 off_t rz = MIN(r->alc_len - rn, r->rsz);
212 rc = fsm.read(&fsm, r->alc_addr + rn, buf2, rz, &sp);
213 CU_ASSERT_FALSE_FATAL(rc);
214 ri = memcmp(buf, buf2, rz);
215 CU_ASSERT_EQUAL_FATAL(ri, 0);
216 rn += rz;
217 }
218 }
219 }
220 free(buf2);
221 free(buf);
222 CU_ASSERT_FALSE_FATAL(fsm.close(&fsm));
223 }
224
test_stress1()225 static void test_stress1() {
226 test_stress("test_fsm_stress1.fsm", 6, true);
227 }
228
test_stress2()229 static void test_stress2() {
230 test_stress("test_fsm_stress2.fsm", 6, false);
231 }
232
main()233 int main() {
234 CU_pSuite pSuite = NULL;
235
236 /* Initialize the CUnit test registry */
237 if (CUE_SUCCESS != CU_initialize_registry())
238 return CU_get_error();
239
240 /* Add a suite to the registry */
241 pSuite = CU_add_suite("iwfs_test3", init_suite, clean_suite);
242
243 if (NULL == pSuite) {
244 CU_cleanup_registry();
245 return CU_get_error();
246 }
247
248 /* Add the tests to the suite */
249 if (
250 (NULL == CU_add_test(pSuite, "test_stress1", test_stress1)) ||
251 (NULL == CU_add_test(pSuite, "test_stress2", test_stress2))
252 ) {
253 CU_cleanup_registry();
254 return CU_get_error();
255 }
256
257 /* Run all tests using the CUnit Basic interface */
258 CU_basic_set_mode(CU_BRM_VERBOSE);
259 CU_basic_run_tests();
260 int ret = CU_get_error() || CU_get_number_of_failures();
261 CU_cleanup_registry();
262 return ret;
263 }
264