Btrfs: transaction handles everywhere
[linux-2.6-block.git] / fs / btrfs / random-test.c
CommitLineData
fec577fb
CM
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"
e089f05c 9#include "transaction.h"
fec577fb
CM
10
11int keep_running = 1;
234b63a0 12struct btrfs_super_block super;
fec577fb 13
e2fa7227
CM
14static int setup_key(struct radix_tree_root *root, struct btrfs_key *key,
15 int exists)
fec577fb
CM
16{
17 int num = rand();
18 unsigned long res[2];
19 int ret;
20
21 key->flags = 0;
62e2749e 22 btrfs_set_key_type(key, BTRFS_STRING_ITEM_KEY);
fec577fb
CM
23 key->offset = 0;
24again:
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 key->objectid = num;
38 return 0;
39}
40
e089f05c
CM
41static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
42 struct radix_tree_root *radix)
fec577fb 43{
234b63a0 44 struct btrfs_path path;
e2fa7227 45 struct btrfs_key key;
fec577fb
CM
46 int ret;
47 char buf[128];
41903fe6 48 unsigned long oid;
234b63a0 49 btrfs_init_path(&path);
fec577fb 50 ret = setup_key(radix, &key, 0);
7cf75962 51 sprintf(buf, "str-%Lu\n", key.objectid);
e089f05c 52 ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
fec577fb
CM
53 if (ret)
54 goto error;
41903fe6 55 oid = (unsigned long)key.objectid;
fec577fb 56 radix_tree_preload(GFP_KERNEL);
41903fe6 57 ret = radix_tree_insert(radix, oid, (void *)oid);
fec577fb
CM
58 radix_tree_preload_end();
59 if (ret)
60 goto error;
61 return ret;
62error:
7cf75962 63 printf("failed to insert %Lu\n", key.objectid);
fec577fb
CM
64 return -1;
65}
66
e089f05c
CM
67static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root
68 *root, struct radix_tree_root *radix)
fec577fb 69{
234b63a0 70 struct btrfs_path path;
e2fa7227 71 struct btrfs_key key;
fec577fb
CM
72 int ret;
73 char buf[128];
234b63a0 74 btrfs_init_path(&path);
fec577fb
CM
75 ret = setup_key(radix, &key, 1);
76 if (ret < 0)
77 return 0;
7cf75962 78 sprintf(buf, "str-%Lu\n", key.objectid);
e089f05c 79 ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
fec577fb 80 if (ret != -EEXIST) {
7cf75962 81 printf("insert on %Lu gave us %d\n", key.objectid, ret);
fec577fb
CM
82 return 1;
83 }
84 return 0;
85}
86
e089f05c
CM
87static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
88 struct radix_tree_root *radix)
fec577fb 89{
234b63a0 90 struct btrfs_path path;
e2fa7227 91 struct btrfs_key key;
fec577fb
CM
92 int ret;
93 unsigned long *ptr;
234b63a0 94 btrfs_init_path(&path);
fec577fb
CM
95 ret = setup_key(radix, &key, 1);
96 if (ret < 0)
97 return 0;
e089f05c 98 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
fec577fb
CM
99 if (ret)
100 goto error;
e089f05c 101 ret = btrfs_del_item(trans, root, &path);
234b63a0 102 btrfs_release_path(root, &path);
fec577fb
CM
103 if (ret != 0)
104 goto error;
105 ptr = radix_tree_delete(radix, key.objectid);
106 if (!ptr)
107 goto error;
108 return 0;
109error:
7cf75962 110 printf("failed to delete %Lu\n", key.objectid);
fec577fb
CM
111 return -1;
112}
113
e089f05c
CM
114static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root
115 *root, struct radix_tree_root *radix)
fec577fb 116{
234b63a0 117 struct btrfs_path path;
e2fa7227 118 struct btrfs_key key;
fec577fb 119 int ret;
234b63a0 120 btrfs_init_path(&path);
fec577fb
CM
121 ret = setup_key(radix, &key, 1);
122 if (ret < 0)
123 return 0;
e089f05c 124 ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
234b63a0 125 btrfs_release_path(root, &path);
fec577fb
CM
126 if (ret)
127 goto error;
128 return 0;
129error:
7cf75962 130 printf("unable to find key %Lu\n", key.objectid);
fec577fb
CM
131 return -1;
132}
133
e089f05c
CM
134static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root
135 *root, struct radix_tree_root *radix)
fec577fb 136{
234b63a0 137 struct btrfs_path path;
e2fa7227 138 struct btrfs_key key;
fec577fb 139 int ret;
234b63a0 140 btrfs_init_path(&path);
fec577fb
CM
141 ret = setup_key(radix, &key, 0);
142 if (ret < 0)
143 return ret;
e089f05c 144 ret = btrfs_search_slot(trans, root, &key, &path, 0, 0);
234b63a0 145 btrfs_release_path(root, &path);
aa5d6bed 146 if (ret <= 0)
fec577fb
CM
147 goto error;
148 return 0;
149error:
7cf75962 150 printf("able to find key that should not exist %Lu\n", key.objectid);
fec577fb
CM
151 return -1;
152}
153
e089f05c
CM
154static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root
155 *root, struct radix_tree_root *radix, int nr)
79f95c82 156{
234b63a0 157 struct btrfs_path path;
e2fa7227 158 struct btrfs_key key;
79f95c82
CM
159 unsigned long found = 0;
160 int ret;
161 int slot;
162 int *ptr;
163 int count = 0;
164
165 key.offset = 0;
166 key.flags = 0;
62e2749e 167 btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY);
79f95c82
CM
168 key.objectid = (unsigned long)-1;
169 while(nr-- >= 0) {
234b63a0 170 btrfs_init_path(&path);
e089f05c 171 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
79f95c82 172 if (ret < 0) {
234b63a0 173 btrfs_release_path(root, &path);
79f95c82
CM
174 return ret;
175 }
176 if (ret != 0) {
177 if (path.slots[0] == 0) {
234b63a0 178 btrfs_release_path(root, &path);
79f95c82
CM
179 break;
180 }
181 path.slots[0] -= 1;
182 }
183 slot = path.slots[0];
62e2749e
CM
184 found = btrfs_disk_key_objectid(
185 &path.nodes[0]->leaf.items[slot].key);
e089f05c 186 ret = btrfs_del_item(trans, root, &path);
79f95c82
CM
187 count++;
188 if (ret) {
189 fprintf(stderr,
190 "failed to remove %lu from tree\n",
191 found);
192 return -1;
193 }
234b63a0 194 btrfs_release_path(root, &path);
79f95c82
CM
195 ptr = radix_tree_delete(radix, found);
196 if (!ptr)
197 goto error;
198 if (!keep_running)
199 break;
200 }
201 return 0;
202error:
203 fprintf(stderr, "failed to delete from the radix %lu\n", found);
204 return -1;
205}
206
e089f05c
CM
207static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root,
208 struct radix_tree_root *radix, int count)
79f95c82
CM
209{
210 int i;
79f95c82
CM
211 int ret = 0;
212 for (i = 0; i < count; i++) {
e089f05c 213 ret = ins_one(trans, root, radix);
79f95c82 214 if (ret) {
77ce6846 215 fprintf(stderr, "fill failed\n");
79f95c82
CM
216 goto out;
217 }
77ce6846 218 if (i % 1000 == 0) {
e089f05c 219 ret = btrfs_commit_transaction(trans, root, &super);
77ce6846
CM
220 if (ret) {
221 fprintf(stderr, "fill commit failed\n");
222 return ret;
223 }
224 }
02217ed2 225 if (i && i % 10000 == 0) {
77ce6846
CM
226 printf("bigfill %d\n", i);
227 }
79f95c82
CM
228 if (!keep_running)
229 break;
230 }
231out:
232 return ret;
233}
234
e089f05c
CM
235static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root,
236 struct radix_tree_root *radix)
79f95c82
CM
237{
238 int ret;
a28ec197 239 int nr = rand() % 5000;
79f95c82
CM
240 static int run_nr = 0;
241
242 /* do the bulk op much less frequently */
243 if (run_nr++ % 100)
244 return 0;
e089f05c 245 ret = empty_tree(trans, root, radix, nr);
79f95c82
CM
246 if (ret)
247 return ret;
e089f05c 248 ret = fill_tree(trans, root, radix, nr);
79f95c82
CM
249 if (ret)
250 return ret;
251 return 0;
252}
253
254
e089f05c
CM
255int (*ops[])(struct btrfs_trans_handle *,
256 struct btrfs_root *root, struct radix_tree_root *radix) =
f0930a37 257 { ins_one, insert_dup, del_one, lookup_item,
a28ec197 258 lookup_enoent, bulk_op };
fec577fb 259
234b63a0 260static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix)
fec577fb 261{
234b63a0 262 struct btrfs_path path;
e2fa7227 263 struct btrfs_key key;
7cf75962 264 unsigned long found;
fec577fb
CM
265 int ret;
266 int slot;
267 int i;
aa5d6bed 268
fec577fb
CM
269 key.offset = 0;
270 key.flags = 0;
62e2749e 271 btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY);
fec577fb
CM
272 key.objectid = (unsigned long)-1;
273 while(1) {
234b63a0 274 btrfs_init_path(&path);
e089f05c 275 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
aa5d6bed 276 if (ret < 0) {
234b63a0 277 btrfs_release_path(root, &path);
aa5d6bed
CM
278 return ret;
279 }
fec577fb
CM
280 slot = path.slots[0];
281 if (ret != 0) {
282 if (slot == 0) {
234b63a0 283 btrfs_release_path(root, &path);
fec577fb
CM
284 break;
285 }
286 slot -= 1;
287 }
288 for (i = slot; i >= 0; i--) {
62e2749e
CM
289 found = btrfs_disk_key_objectid(&path.nodes[0]->
290 leaf.items[i].key);
fec577fb
CM
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);
298 }
299
300 radix_tree_preload_end();
301 }
234b63a0 302 btrfs_release_path(root, &path);
fec577fb
CM
303 key.objectid = found - 1;
304 if (key.objectid > found)
305 break;
306 }
307 return 0;
308}
fec577fb
CM
309void sigstopper(int ignored)
310{
311 keep_running = 0;
312 fprintf(stderr, "caught exit signal, stopping\n");
313}
314
315int print_usage(void)
316{
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);
323}
324int main(int ac, char **av)
325{
326 RADIX_TREE(radix, GFP_KERNEL);
234b63a0 327 struct btrfs_root *root;
fec577fb
CM
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;
e089f05c 336 struct btrfs_trans_handle *trans;
fec577fb
CM
337 radix_tree_init();
338 root = open_ctree("dbfile", &super);
339 fill_radix(root, &radix);
340
341 signal(SIGTERM, sigstopper);
342 signal(SIGINT, sigstopper);
343
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();
355 }
356 }
79f95c82 357 printf("initial fill\n");
e089f05c
CM
358 trans = btrfs_start_transaction(root, 1);
359 ret = fill_tree(trans, root, &radix, init_fill_count);
79f95c82
CM
360 printf("starting run\n");
361 if (ret) {
362 err = ret;
363 goto out;
fec577fb
CM
364 }
365 if (initial_only == 1) {
366 goto out;
367 }
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);
374 }
375 if (i && i % 5000 == 0) {
376 printf("open & close, root level %d nritems %d\n",
7518a238
CM
377 btrfs_header_level(&root->node->node.header),
378 btrfs_header_nritems(&root->node->node.header));
a28ec197 379 close_ctree(root, &super);
fec577fb
CM
380 root = open_ctree("dbfile", &super);
381 }
382 while(count--) {
e089f05c 383 ret = ops[op](trans, root, &radix);
fec577fb
CM
384 if (ret) {
385 fprintf(stderr, "op %d failed %d:%d\n",
386 op, i, iterations);
234b63a0 387 btrfs_print_tree(root, root->node);
fec577fb
CM
388 fprintf(stderr, "op %d failed %d:%d\n",
389 op, i, iterations);
390 err = ret;
391 goto out;
392 }
a28ec197 393 if (ops[op] == bulk_op)
79f95c82 394 break;
fec577fb
CM
395 if (keep_running == 0) {
396 err = 0;
397 goto out;
398 }
399 }
400 }
401out:
a28ec197 402 close_ctree(root, &super);
fec577fb
CM
403 return err;
404}
405