transaction handles everywhere
[btrfs-progs-unstable.git] / random-test.c
blob3a38ae7a886d6db89cd6f2b7e4a3f808386f9148
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"
9 #include "transaction.h"
11 int keep_running = 1;
12 struct btrfs_super_block super;
14 static int setup_key(struct radix_tree_root *root, struct btrfs_key *key,
15 int exists)
17 int num = rand();
18 unsigned long res[2];
19 int ret;
21 key->flags = 0;
22 btrfs_set_key_type(key, BTRFS_STRING_ITEM_KEY);
23 key->offset = 0;
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;
37 key->objectid = num;
38 return 0;
41 static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
42 struct radix_tree_root *radix)
44 struct btrfs_path path;
45 struct btrfs_key key;
46 int ret;
47 char buf[128];
48 unsigned long oid;
49 btrfs_init_path(&path);
50 ret = setup_key(radix, &key, 0);
51 sprintf(buf, "str-%Lu\n", key.objectid);
52 ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
53 if (ret)
54 goto error;
55 oid = (unsigned long)key.objectid;
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 printf("failed to insert %Lu\n", key.objectid);
64 return -1;
67 static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root
68 *root, struct radix_tree_root *radix)
70 struct btrfs_path path;
71 struct btrfs_key key;
72 int ret;
73 char buf[128];
74 btrfs_init_path(&path);
75 ret = setup_key(radix, &key, 1);
76 if (ret < 0)
77 return 0;
78 sprintf(buf, "str-%Lu\n", key.objectid);
79 ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
80 if (ret != -EEXIST) {
81 printf("insert on %Lu gave us %d\n", key.objectid, ret);
82 return 1;
84 return 0;
87 static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
88 struct radix_tree_root *radix)
90 struct btrfs_path path;
91 struct btrfs_key key;
92 int ret;
93 unsigned long *ptr;
94 btrfs_init_path(&path);
95 ret = setup_key(radix, &key, 1);
96 if (ret < 0)
97 return 0;
98 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
99 if (ret)
100 goto error;
101 ret = btrfs_del_item(trans, root, &path);
102 btrfs_release_path(root, &path);
103 if (ret != 0)
104 goto error;
105 ptr = radix_tree_delete(radix, key.objectid);
106 if (!ptr)
107 goto error;
108 return 0;
109 error:
110 printf("failed to delete %Lu\n", key.objectid);
111 return -1;
114 static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root
115 *root, struct radix_tree_root *radix)
117 struct btrfs_path path;
118 struct btrfs_key key;
119 int ret;
120 btrfs_init_path(&path);
121 ret = setup_key(radix, &key, 1);
122 if (ret < 0)
123 return 0;
124 ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
125 btrfs_release_path(root, &path);
126 if (ret)
127 goto error;
128 return 0;
129 error:
130 printf("unable to find key %Lu\n", key.objectid);
131 return -1;
134 static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root
135 *root, struct radix_tree_root *radix)
137 struct btrfs_path path;
138 struct btrfs_key key;
139 int ret;
140 btrfs_init_path(&path);
141 ret = setup_key(radix, &key, 0);
142 if (ret < 0)
143 return ret;
144 ret = btrfs_search_slot(trans, root, &key, &path, 0, 0);
145 btrfs_release_path(root, &path);
146 if (ret <= 0)
147 goto error;
148 return 0;
149 error:
150 printf("able to find key that should not exist %Lu\n", key.objectid);
151 return -1;
154 static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root
155 *root, struct radix_tree_root *radix, int nr)
157 struct btrfs_path path;
158 struct btrfs_key key;
159 unsigned long found = 0;
160 int ret;
161 int slot;
162 int *ptr;
163 int count = 0;
165 key.offset = 0;
166 key.flags = 0;
167 btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY);
168 key.objectid = (unsigned long)-1;
169 while(nr-- >= 0) {
170 btrfs_init_path(&path);
171 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
172 if (ret < 0) {
173 btrfs_release_path(root, &path);
174 return ret;
176 if (ret != 0) {
177 if (path.slots[0] == 0) {
178 btrfs_release_path(root, &path);
179 break;
181 path.slots[0] -= 1;
183 slot = path.slots[0];
184 found = btrfs_disk_key_objectid(
185 &path.nodes[0]->leaf.items[slot].key);
186 ret = btrfs_del_item(trans, root, &path);
187 count++;
188 if (ret) {
189 fprintf(stderr,
190 "failed to remove %lu from tree\n",
191 found);
192 return -1;
194 btrfs_release_path(root, &path);
195 ptr = radix_tree_delete(radix, found);
196 if (!ptr)
197 goto error;
198 if (!keep_running)
199 break;
201 return 0;
202 error:
203 fprintf(stderr, "failed to delete from the radix %lu\n", found);
204 return -1;
207 static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root,
208 struct radix_tree_root *radix, int count)
210 int i;
211 int ret = 0;
212 for (i = 0; i < count; i++) {
213 ret = ins_one(trans, root, radix);
214 if (ret) {
215 fprintf(stderr, "fill failed\n");
216 goto out;
218 if (i % 1000 == 0) {
219 ret = btrfs_commit_transaction(trans, root, &super);
220 if (ret) {
221 fprintf(stderr, "fill commit failed\n");
222 return ret;
225 if (i && i % 10000 == 0) {
226 printf("bigfill %d\n", i);
228 if (!keep_running)
229 break;
231 out:
232 return ret;
235 static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root,
236 struct radix_tree_root *radix)
238 int ret;
239 int nr = rand() % 5000;
240 static int run_nr = 0;
242 /* do the bulk op much less frequently */
243 if (run_nr++ % 100)
244 return 0;
245 ret = empty_tree(trans, root, radix, nr);
246 if (ret)
247 return ret;
248 ret = fill_tree(trans, root, radix, nr);
249 if (ret)
250 return ret;
251 return 0;
255 int (*ops[])(struct btrfs_trans_handle *,
256 struct btrfs_root *root, struct radix_tree_root *radix) =
257 { ins_one, insert_dup, del_one, lookup_item,
258 lookup_enoent, bulk_op };
260 static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix)
262 struct btrfs_path path;
263 struct btrfs_key key;
264 unsigned long found;
265 int ret;
266 int slot;
267 int i;
269 key.offset = 0;
270 key.flags = 0;
271 btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY);
272 key.objectid = (unsigned long)-1;
273 while(1) {
274 btrfs_init_path(&path);
275 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
276 if (ret < 0) {
277 btrfs_release_path(root, &path);
278 return ret;
280 slot = path.slots[0];
281 if (ret != 0) {
282 if (slot == 0) {
283 btrfs_release_path(root, &path);
284 break;
286 slot -= 1;
288 for (i = slot; i >= 0; i--) {
289 found = btrfs_disk_key_objectid(&path.nodes[0]->
290 leaf.items[i].key);
291 radix_tree_preload(GFP_KERNEL);
292 ret = radix_tree_insert(radix, found, (void *)found);
293 if (ret) {
294 fprintf(stderr,
295 "failed to insert %lu into radix\n",
296 found);
297 exit(1);
300 radix_tree_preload_end();
302 btrfs_release_path(root, &path);
303 key.objectid = found - 1;
304 if (key.objectid > found)
305 break;
307 return 0;
309 void sigstopper(int ignored)
311 keep_running = 0;
312 fprintf(stderr, "caught exit signal, stopping\n");
315 int print_usage(void)
317 printf("usage: tester [-ih] [-c count] [-f count]\n");
318 printf("\t -c count -- iteration count after filling\n");
319 printf("\t -f count -- run this many random inserts before starting\n");
320 printf("\t -i -- only do initial fill\n");
321 printf("\t -h -- this help text\n");
322 exit(1);
324 int main(int ac, char **av)
326 RADIX_TREE(radix, GFP_KERNEL);
327 struct btrfs_root *root;
328 int i;
329 int ret;
330 int count;
331 int op;
332 int iterations = 20000;
333 int init_fill_count = 800000;
334 int err = 0;
335 int initial_only = 0;
336 struct btrfs_trans_handle *trans;
337 radix_tree_init();
338 root = open_ctree("dbfile", &super);
339 fill_radix(root, &radix);
341 signal(SIGTERM, sigstopper);
342 signal(SIGINT, sigstopper);
344 for (i = 1 ; i < ac ; i++) {
345 if (strcmp(av[i], "-i") == 0) {
346 initial_only = 1;
347 } else if (strcmp(av[i], "-c") == 0) {
348 iterations = atoi(av[i+1]);
349 i++;
350 } else if (strcmp(av[i], "-f") == 0) {
351 init_fill_count = atoi(av[i+1]);
352 i++;
353 } else {
354 print_usage();
357 printf("initial fill\n");
358 trans = btrfs_start_transaction(root, 1);
359 ret = fill_tree(trans, root, &radix, init_fill_count);
360 printf("starting run\n");
361 if (ret) {
362 err = ret;
363 goto out;
365 if (initial_only == 1) {
366 goto out;
368 for (i = 0; i < iterations; i++) {
369 op = rand() % ARRAY_SIZE(ops);
370 count = rand() % 128;
371 if (i % 2000 == 0) {
372 printf("%d\n", i);
373 fflush(stdout);
375 if (i && i % 5000 == 0) {
376 printf("open & close, root level %d nritems %d\n",
377 btrfs_header_level(&root->node->node.header),
378 btrfs_header_nritems(&root->node->node.header));
379 close_ctree(root, &super);
380 root = open_ctree("dbfile", &super);
382 while(count--) {
383 ret = ops[op](trans, root, &radix);
384 if (ret) {
385 fprintf(stderr, "op %d failed %d:%d\n",
386 op, i, iterations);
387 btrfs_print_tree(root, root->node);
388 fprintf(stderr, "op %d failed %d:%d\n",
389 op, i, iterations);
390 err = ret;
391 goto out;
393 if (ops[op] == bulk_op)
394 break;
395 if (keep_running == 0) {
396 err = 0;
397 goto out;
401 out:
402 close_ctree(root, &super);
403 return err;