add a name_len to dir items, reorder key
[platform/upstream/btrfs-progs.git] / dir-test.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <unistd.h>
5 #include "kerncompat.h"
6 #include "radix-tree.h"
7 #include "ctree.h"
8 #include "disk-io.h"
9 #include "print-tree.h"
10 #include "hash.h"
11
12 int keep_running = 1;
13 struct btrfs_super_block super;
14 static u64 dir_oid = 44556;
15 static u64 file_oid = 33778;
16
17 static int find_num(struct radix_tree_root *root, unsigned long *num_ret,
18                      int exists)
19 {
20         unsigned long num = rand();
21         unsigned long res[2];
22         int ret;
23
24 again:
25         ret = radix_tree_gang_lookup(root, (void **)res, num, 2);
26         if (exists) {
27                 if (ret == 0)
28                         return -1;
29                 num = res[0];
30         } else if (ret != 0 && num == res[0]) {
31                 num++;
32                 if (ret > 1 && num == res[1]) {
33                         num++;
34                         goto again;
35                 }
36         }
37         *num_ret = num;
38         return 0;
39 }
40
41 static int ins_one(struct btrfs_root *root, struct radix_tree_root *radix)
42 {
43         int ret;
44         char buf[128];
45         unsigned long oid;
46         struct btrfs_path path;
47
48         find_num(radix, &oid, 0);
49         sprintf(buf, "str-%lu", oid);
50
51         ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
52                                     1);
53         if (ret)
54                 goto error;
55
56         radix_tree_preload(GFP_KERNEL);
57         ret = radix_tree_insert(radix, oid, (void *)oid);
58         radix_tree_preload_end();
59         if (ret)
60                 goto error;
61         return ret;
62 error:
63         if (ret != -EEXIST)
64                 goto fatal;
65
66         /*
67          * if we got an EEXIST, it may be due to hash collision, double
68          * check
69          */
70         btrfs_init_path(&path);
71         ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
72         if (ret)
73                 goto fatal_release;
74         if (!btrfs_match_dir_item_name(root, &path, buf, strlen(buf))) {
75                 struct btrfs_dir_item *di;
76                 char *found;
77                 u32 found_len;
78                 u64 myhash;
79                 u64 foundhash;
80
81                 di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0],
82                                     struct btrfs_dir_item);
83                 found = (char *)(di + 1);
84                 found_len = btrfs_dir_name_len(di);
85                 btrfs_name_hash(buf, strlen(buf), &myhash);
86                 btrfs_name_hash(found, found_len, &foundhash);
87                 if (myhash != foundhash)
88                         goto fatal_release;
89                 btrfs_release_path(root, &path);
90                 return 0;
91         }
92 fatal_release:
93         btrfs_release_path(root, &path);
94 fatal:
95         printf("failed to insert %lu ret %d\n", oid, ret);
96         return -1;
97 }
98
99 static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
100 {
101         int ret;
102         char buf[128];
103         unsigned long oid;
104
105         ret = find_num(radix, &oid, 1);
106         if (ret < 0)
107                 return 0;
108         sprintf(buf, "str-%lu", oid);
109
110         ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
111                                     1);
112         if (ret != -EEXIST) {
113                 printf("insert on %s gave us %d\n", buf, ret);
114                 return 1;
115         }
116         return 0;
117 }
118
119 static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
120 {
121         int ret;
122         char buf[128];
123         unsigned long oid;
124         struct btrfs_path path;
125         unsigned long *ptr;
126
127         ret = find_num(radix, &oid, 1);
128         if (ret < 0)
129                 return 0;
130         sprintf(buf, "str-%lu", oid);
131         btrfs_init_path(&path);
132         ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), -1);
133         if (ret)
134                 goto out_release;
135         ret = btrfs_del_item(root, &path);
136         if (ret)
137                 goto out_release;
138         btrfs_release_path(root, &path);
139         ptr = radix_tree_delete(radix, oid);
140         if (!ptr) {
141                 ret = -5555;
142                 goto out;
143         }
144         return 0;
145 out_release:
146         btrfs_release_path(root, &path);
147 out:
148         printf("failed to delete %lu %d\n", oid, ret);
149         return -1;
150 }
151
152 static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
153 {
154         struct btrfs_path path;
155         char buf[128];
156         int ret;
157         unsigned long oid;
158
159         ret = find_num(radix, &oid, 1);
160         if (ret < 0)
161                 return 0;
162         sprintf(buf, "str-%lu", oid);
163         btrfs_init_path(&path);
164         ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
165         btrfs_release_path(root, &path);
166         if (ret) {
167                 printf("unable to find key %lu\n", oid);
168                 return -1;
169         }
170         return 0;
171 }
172
173 static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
174 {
175         struct btrfs_path path;
176         char buf[128];
177         int ret;
178         unsigned long oid;
179
180         ret = find_num(radix, &oid, 0);
181         if (ret < 0)
182                 return 0;
183         sprintf(buf, "str-%lu", oid);
184         btrfs_init_path(&path);
185         ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
186         btrfs_release_path(root, &path);
187         if (!ret) {
188                 printf("able to find key that should not exist %lu\n", oid);
189                 return -1;
190         }
191         return 0;
192 }
193
194 static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
195                       int nr)
196 {
197         struct btrfs_path path;
198         struct btrfs_key key;
199         unsigned long found = 0;
200         u32 found_len;
201         int ret;
202         int slot;
203         int *ptr;
204         int count = 0;
205         char buf[128];
206         struct btrfs_dir_item *di;
207
208         key.offset = (u64)-1;
209         key.flags = 0;
210         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
211         key.objectid = dir_oid;
212         while(nr-- >= 0) {
213                 btrfs_init_path(&path);
214                 ret = btrfs_search_slot(root, &key, &path, -1, 1);
215                 if (ret < 0) {
216                         btrfs_release_path(root, &path);
217                         return ret;
218                 }
219                 if (ret != 0) {
220                         if (path.slots[0] == 0) {
221                                 btrfs_release_path(root, &path);
222                                 break;
223                         }
224                         path.slots[0] -= 1;
225                 }
226                 slot = path.slots[0];
227                 di = btrfs_item_ptr(&path.nodes[0]->leaf, slot,
228                                     struct btrfs_dir_item);
229                 found_len = btrfs_dir_name_len(di);
230                 memcpy(buf, (char *)(di + 1), found_len);
231                 BUG_ON(found_len > 128);
232                 buf[found_len] = '\0';
233                 found = atoi(buf + 4);
234                 ret = btrfs_del_item(root, &path);
235                 count++;
236                 if (ret) {
237                         fprintf(stderr,
238                                 "failed to remove %lu from tree\n",
239                                 found);
240                         return -1;
241                 }
242                 btrfs_release_path(root, &path);
243                 ptr = radix_tree_delete(radix, found);
244                 if (!ptr)
245                         goto error;
246                 if (!keep_running)
247                         break;
248         }
249         return 0;
250 error:
251         fprintf(stderr, "failed to delete from the radix %lu\n", found);
252         return -1;
253 }
254
255 static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
256                      int count)
257 {
258         int i;
259         int ret = 0;
260         for (i = 0; i < count; i++) {
261                 ret = ins_one(root, radix);
262                 if (ret) {
263                         fprintf(stderr, "fill failed\n");
264                         goto out;
265                 }
266                 if (i % 1000 == 0) {
267                         ret = btrfs_commit_transaction(root, &super);
268                         if (ret) {
269                                 fprintf(stderr, "fill commit failed\n");
270                                 return ret;
271                         }
272                 }
273                 if (i && i % 10000 == 0) {
274                         printf("bigfill %d\n", i);
275                 }
276                 if (!keep_running)
277                         break;
278         }
279 out:
280         return ret;
281 }
282
283 static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
284 {
285         int ret;
286         int nr = rand() % 5000;
287         static int run_nr = 0;
288
289         /* do the bulk op much less frequently */
290         if (run_nr++ % 100)
291                 return 0;
292         ret = empty_tree(root, radix, nr);
293         if (ret)
294                 return ret;
295         ret = fill_tree(root, radix, nr);
296         if (ret)
297                 return ret;
298         return 0;
299 }
300
301
302 int (*ops[])(struct btrfs_root *root, struct radix_tree_root *radix) =
303         { ins_one, insert_dup, del_one, lookup_item,
304           lookup_enoent, bulk_op };
305
306 void sigstopper(int ignored)
307 {
308         keep_running = 0;
309         fprintf(stderr, "caught exit signal, stopping\n");
310 }
311
312 int print_usage(void)
313 {
314         printf("usage: tester [-ih] [-c count] [-f count]\n");
315         printf("\t -c count -- iteration count after filling\n");
316         printf("\t -f count -- run this many random inserts before starting\n");
317         printf("\t -i       -- only do initial fill\n");
318         printf("\t -h       -- this help text\n");
319         exit(1);
320 }
321 int main(int ac, char **av)
322 {
323         RADIX_TREE(radix, GFP_KERNEL);
324         struct btrfs_root *root;
325         int i;
326         int ret;
327         int count;
328         int op;
329         int iterations = 20000;
330         int init_fill_count = 800000;
331         int err = 0;
332         int initial_only = 0;
333         radix_tree_init();
334
335         printf("removing old tree\n");
336         unlink("dbfile");
337         root = open_ctree("dbfile", &super);
338
339         signal(SIGTERM, sigstopper);
340         signal(SIGINT, sigstopper);
341
342         for (i = 1 ; i < ac ; i++) {
343                 if (strcmp(av[i], "-i") == 0) {
344                         initial_only = 1;
345                 } else if (strcmp(av[i], "-c") == 0) {
346                         iterations = atoi(av[i+1]);
347                         i++;
348                 } else if (strcmp(av[i], "-f") == 0) {
349                         init_fill_count = atoi(av[i+1]);
350                         i++;
351                 } else {
352                         print_usage();
353                 }
354         }
355         printf("initial fill\n");
356         ret = fill_tree(root, &radix, init_fill_count);
357         printf("starting run\n");
358         if (ret) {
359                 err = ret;
360                 goto out;
361         }
362         if (initial_only == 1) {
363                 goto out;
364         }
365         for (i = 0; i < iterations; i++) {
366                 op = rand() % ARRAY_SIZE(ops);
367                 count = rand() % 128;
368                 if (i % 2000 == 0) {
369                         printf("%d\n", i);
370                         fflush(stdout);
371                 }
372                 if (i && i % 5000 == 0) {
373                         printf("open & close, root level %d nritems %d\n",
374                                 btrfs_header_level(&root->node->node.header),
375                                 btrfs_header_nritems(&root->node->node.header));
376                         close_ctree(root, &super);
377                         root = open_ctree("dbfile", &super);
378                 }
379                 while(count--) {
380                         ret = ops[op](root, &radix);
381                         if (ret) {
382                                 fprintf(stderr, "op %d failed %d:%d\n",
383                                         op, i, iterations);
384                                 btrfs_print_tree(root, root->node);
385                                 fprintf(stderr, "op %d failed %d:%d\n",
386                                         op, i, iterations);
387                                 err = ret;
388                                 goto out;
389                         }
390                         if (ops[op] == bulk_op)
391                                 break;
392                         if (keep_running == 0) {
393                                 err = 0;
394                                 goto out;
395                         }
396                 }
397         }
398 out:
399         close_ctree(root, &super);
400         return err;
401 }
402