add leaf data casting helper
[btrfs-progs-unstable.git] / random-test.c
bloba8ef0478991b3f3d11cfc82b8ecaf36555c75d72
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include "kerncompat.h"
5 #include "radix-tree.h"
6 #include "ctree.h"
7 #include "disk-io.h"
8 #include "print-tree.h"
10 int keep_running = 1;
11 struct btrfs_super_block super;
13 static int setup_key(struct radix_tree_root *root, struct btrfs_key *key,
14 int exists)
16 int num = rand();
17 unsigned long res[2];
18 int ret;
20 key->flags = 0;
21 key->offset = 0;
22 again:
23 ret = radix_tree_gang_lookup(root, (void **)res, num, 2);
24 if (exists) {
25 if (ret == 0)
26 return -1;
27 num = res[0];
28 } else if (ret != 0 && num == res[0]) {
29 num++;
30 if (ret > 1 && num == res[1]) {
31 num++;
32 goto again;
35 key->objectid = num;
36 return 0;
39 static int ins_one(struct btrfs_root *root, struct radix_tree_root *radix)
41 struct btrfs_path path;
42 struct btrfs_key key;
43 int ret;
44 char buf[128];
45 unsigned long oid;
46 btrfs_init_path(&path);
47 ret = setup_key(radix, &key, 0);
48 sprintf(buf, "str-%Lu\n", key.objectid);
49 ret = btrfs_insert_item(root, &key, buf, strlen(buf));
50 if (ret)
51 goto error;
52 oid = (unsigned long)key.objectid;
53 radix_tree_preload(GFP_KERNEL);
54 ret = radix_tree_insert(radix, oid, (void *)oid);
55 radix_tree_preload_end();
56 if (ret)
57 goto error;
58 return ret;
59 error:
60 printf("failed to insert %Lu\n", key.objectid);
61 return -1;
64 static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
66 struct btrfs_path path;
67 struct btrfs_key key;
68 int ret;
69 char buf[128];
70 btrfs_init_path(&path);
71 ret = setup_key(radix, &key, 1);
72 if (ret < 0)
73 return 0;
74 sprintf(buf, "str-%Lu\n", key.objectid);
75 ret = btrfs_insert_item(root, &key, buf, strlen(buf));
76 if (ret != -EEXIST) {
77 printf("insert on %Lu gave us %d\n", key.objectid, ret);
78 return 1;
80 return 0;
83 static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
85 struct btrfs_path path;
86 struct btrfs_key key;
87 int ret;
88 unsigned long *ptr;
89 btrfs_init_path(&path);
90 ret = setup_key(radix, &key, 1);
91 if (ret < 0)
92 return 0;
93 ret = btrfs_search_slot(root, &key, &path, -1, 1);
94 if (ret)
95 goto error;
96 ret = btrfs_del_item(root, &path);
97 btrfs_release_path(root, &path);
98 if (ret != 0)
99 goto error;
100 ptr = radix_tree_delete(radix, key.objectid);
101 if (!ptr)
102 goto error;
103 return 0;
104 error:
105 printf("failed to delete %Lu\n", key.objectid);
106 return -1;
109 static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
111 struct btrfs_path path;
112 struct btrfs_key key;
113 int ret;
114 btrfs_init_path(&path);
115 ret = setup_key(radix, &key, 1);
116 if (ret < 0)
117 return 0;
118 ret = btrfs_search_slot(root, &key, &path, 0, 1);
119 btrfs_release_path(root, &path);
120 if (ret)
121 goto error;
122 return 0;
123 error:
124 printf("unable to find key %Lu\n", key.objectid);
125 return -1;
128 static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
130 struct btrfs_path path;
131 struct btrfs_key key;
132 int ret;
133 btrfs_init_path(&path);
134 ret = setup_key(radix, &key, 0);
135 if (ret < 0)
136 return ret;
137 ret = btrfs_search_slot(root, &key, &path, 0, 0);
138 btrfs_release_path(root, &path);
139 if (ret <= 0)
140 goto error;
141 return 0;
142 error:
143 printf("able to find key that should not exist %Lu\n", key.objectid);
144 return -1;
147 static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
148 int nr)
150 struct btrfs_path path;
151 struct btrfs_key key;
152 unsigned long found = 0;
153 int ret;
154 int slot;
155 int *ptr;
156 int count = 0;
158 key.offset = 0;
159 key.flags = 0;
160 key.objectid = (unsigned long)-1;
161 while(nr-- >= 0) {
162 btrfs_init_path(&path);
163 ret = btrfs_search_slot(root, &key, &path, -1, 1);
164 if (ret < 0) {
165 btrfs_release_path(root, &path);
166 return ret;
168 if (ret != 0) {
169 if (path.slots[0] == 0) {
170 btrfs_release_path(root, &path);
171 break;
173 path.slots[0] -= 1;
175 slot = path.slots[0];
176 found=btrfs_key_objectid(&path.nodes[0]->leaf.items[slot].key);
177 ret = btrfs_del_item(root, &path);
178 count++;
179 if (ret) {
180 fprintf(stderr,
181 "failed to remove %lu from tree\n",
182 found);
183 return -1;
185 btrfs_release_path(root, &path);
186 ptr = radix_tree_delete(radix, found);
187 if (!ptr)
188 goto error;
189 if (!keep_running)
190 break;
192 return 0;
193 error:
194 fprintf(stderr, "failed to delete from the radix %lu\n", found);
195 return -1;
198 static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
199 int count)
201 int i;
202 int ret = 0;
203 for (i = 0; i < count; i++) {
204 ret = ins_one(root, radix);
205 if (ret) {
206 fprintf(stderr, "fill failed\n");
207 goto out;
209 if (i % 1000 == 0) {
210 ret = btrfs_commit_transaction(root, &super);
211 if (ret) {
212 fprintf(stderr, "fill commit failed\n");
213 return ret;
216 if (i && i % 10000 == 0) {
217 printf("bigfill %d\n", i);
219 if (!keep_running)
220 break;
222 out:
223 return ret;
226 static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
228 int ret;
229 int nr = rand() % 5000;
230 static int run_nr = 0;
232 /* do the bulk op much less frequently */
233 if (run_nr++ % 100)
234 return 0;
235 ret = empty_tree(root, radix, nr);
236 if (ret)
237 return ret;
238 ret = fill_tree(root, radix, nr);
239 if (ret)
240 return ret;
241 return 0;
245 int (*ops[])(struct btrfs_root *root, struct radix_tree_root *radix) =
246 { ins_one, insert_dup, del_one, lookup_item,
247 lookup_enoent, bulk_op };
249 static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix)
251 struct btrfs_path path;
252 struct btrfs_key key;
253 unsigned long found;
254 int ret;
255 int slot;
256 int i;
258 key.offset = 0;
259 key.flags = 0;
260 key.objectid = (unsigned long)-1;
261 while(1) {
262 btrfs_init_path(&path);
263 ret = btrfs_search_slot(root, &key, &path, 0, 0);
264 if (ret < 0) {
265 btrfs_release_path(root, &path);
266 return ret;
268 slot = path.slots[0];
269 if (ret != 0) {
270 if (slot == 0) {
271 btrfs_release_path(root, &path);
272 break;
274 slot -= 1;
276 for (i = slot; i >= 0; i--) {
277 found = btrfs_key_objectid(&path.nodes[0]->
278 leaf.items[i].key);
279 radix_tree_preload(GFP_KERNEL);
280 ret = radix_tree_insert(radix, found, (void *)found);
281 if (ret) {
282 fprintf(stderr,
283 "failed to insert %lu into radix\n",
284 found);
285 exit(1);
288 radix_tree_preload_end();
290 btrfs_release_path(root, &path);
291 key.objectid = found - 1;
292 if (key.objectid > found)
293 break;
295 return 0;
297 void sigstopper(int ignored)
299 keep_running = 0;
300 fprintf(stderr, "caught exit signal, stopping\n");
303 int print_usage(void)
305 printf("usage: tester [-ih] [-c count] [-f count]\n");
306 printf("\t -c count -- iteration count after filling\n");
307 printf("\t -f count -- run this many random inserts before starting\n");
308 printf("\t -i -- only do initial fill\n");
309 printf("\t -h -- this help text\n");
310 exit(1);
312 int main(int ac, char **av)
314 RADIX_TREE(radix, GFP_KERNEL);
315 struct btrfs_root *root;
316 int i;
317 int ret;
318 int count;
319 int op;
320 int iterations = 20000;
321 int init_fill_count = 800000;
322 int err = 0;
323 int initial_only = 0;
324 radix_tree_init();
325 root = open_ctree("dbfile", &super);
326 fill_radix(root, &radix);
328 signal(SIGTERM, sigstopper);
329 signal(SIGINT, sigstopper);
331 for (i = 1 ; i < ac ; i++) {
332 if (strcmp(av[i], "-i") == 0) {
333 initial_only = 1;
334 } else if (strcmp(av[i], "-c") == 0) {
335 iterations = atoi(av[i+1]);
336 i++;
337 } else if (strcmp(av[i], "-f") == 0) {
338 init_fill_count = atoi(av[i+1]);
339 i++;
340 } else {
341 print_usage();
344 printf("initial fill\n");
345 ret = fill_tree(root, &radix, init_fill_count);
346 printf("starting run\n");
347 if (ret) {
348 err = ret;
349 goto out;
351 if (initial_only == 1) {
352 goto out;
354 for (i = 0; i < iterations; i++) {
355 op = rand() % ARRAY_SIZE(ops);
356 count = rand() % 128;
357 if (i % 2000 == 0) {
358 printf("%d\n", i);
359 fflush(stdout);
361 if (i && i % 5000 == 0) {
362 printf("open & close, root level %d nritems %d\n",
363 btrfs_header_level(&root->node->node.header),
364 btrfs_header_nritems(&root->node->node.header));
365 close_ctree(root, &super);
366 root = open_ctree("dbfile", &super);
368 while(count--) {
369 ret = ops[op](root, &radix);
370 if (ret) {
371 fprintf(stderr, "op %d failed %d:%d\n",
372 op, i, iterations);
373 btrfs_print_tree(root, root->node);
374 fprintf(stderr, "op %d failed %d:%d\n",
375 op, i, iterations);
376 err = ret;
377 goto out;
379 if (ops[op] == bulk_op)
380 break;
381 if (keep_running == 0) {
382 err = 0;
383 goto out;
387 out:
388 close_ctree(root, &super);
389 return err;