blob: 3a38ae7a886d6db89cd6f2b7e4a3f808386f9148 [file] [log] [blame]
Chris Masonfec577f2007-02-26 10:40:21 -05001#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"
Chris Masone089f052007-03-16 16:20:31 -04009#include "transaction.h"
Chris Masonfec577f2007-02-26 10:40:21 -050010
11int keep_running = 1;
Chris Mason234b63a2007-03-13 10:46:10 -040012struct btrfs_super_block super;
Chris Masonfec577f2007-02-26 10:40:21 -050013
Chris Masone2fa7222007-03-12 16:22:34 -040014static int setup_key(struct radix_tree_root *root, struct btrfs_key *key,
15 int exists)
Chris Masonfec577f2007-02-26 10:40:21 -050016{
17 int num = rand();
18 unsigned long res[2];
19 int ret;
20
21 key->flags = 0;
Chris Mason62e27492007-03-15 12:56:47 -040022 btrfs_set_key_type(key, BTRFS_STRING_ITEM_KEY);
Chris Masonfec577f2007-02-26 10:40:21 -050023 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
Chris Masone089f052007-03-16 16:20:31 -040041static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
42 struct radix_tree_root *radix)
Chris Masonfec577f2007-02-26 10:40:21 -050043{
Chris Mason234b63a2007-03-13 10:46:10 -040044 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -040045 struct btrfs_key key;
Chris Masonfec577f2007-02-26 10:40:21 -050046 int ret;
47 char buf[128];
Chris Mason41903fe2007-02-26 10:55:42 -050048 unsigned long oid;
Chris Mason234b63a2007-03-13 10:46:10 -040049 btrfs_init_path(&path);
Chris Masonfec577f2007-02-26 10:40:21 -050050 ret = setup_key(radix, &key, 0);
Chris Mason7cf75962007-02-26 10:55:01 -050051 sprintf(buf, "str-%Lu\n", key.objectid);
Chris Masone089f052007-03-16 16:20:31 -040052 ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
Chris Masonfec577f2007-02-26 10:40:21 -050053 if (ret)
54 goto error;
Chris Mason41903fe2007-02-26 10:55:42 -050055 oid = (unsigned long)key.objectid;
Chris Masonfec577f2007-02-26 10:40:21 -050056 radix_tree_preload(GFP_KERNEL);
Chris Mason41903fe2007-02-26 10:55:42 -050057 ret = radix_tree_insert(radix, oid, (void *)oid);
Chris Masonfec577f2007-02-26 10:40:21 -050058 radix_tree_preload_end();
59 if (ret)
60 goto error;
61 return ret;
62error:
Chris Mason7cf75962007-02-26 10:55:01 -050063 printf("failed to insert %Lu\n", key.objectid);
Chris Masonfec577f2007-02-26 10:40:21 -050064 return -1;
65}
66
Chris Masone089f052007-03-16 16:20:31 -040067static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root
68 *root, struct radix_tree_root *radix)
Chris Masonfec577f2007-02-26 10:40:21 -050069{
Chris Mason234b63a2007-03-13 10:46:10 -040070 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -040071 struct btrfs_key key;
Chris Masonfec577f2007-02-26 10:40:21 -050072 int ret;
73 char buf[128];
Chris Mason234b63a2007-03-13 10:46:10 -040074 btrfs_init_path(&path);
Chris Masonfec577f2007-02-26 10:40:21 -050075 ret = setup_key(radix, &key, 1);
76 if (ret < 0)
77 return 0;
Chris Mason7cf75962007-02-26 10:55:01 -050078 sprintf(buf, "str-%Lu\n", key.objectid);
Chris Masone089f052007-03-16 16:20:31 -040079 ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
Chris Masonfec577f2007-02-26 10:40:21 -050080 if (ret != -EEXIST) {
Chris Mason7cf75962007-02-26 10:55:01 -050081 printf("insert on %Lu gave us %d\n", key.objectid, ret);
Chris Masonfec577f2007-02-26 10:40:21 -050082 return 1;
83 }
84 return 0;
85}
86
Chris Masone089f052007-03-16 16:20:31 -040087static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
88 struct radix_tree_root *radix)
Chris Masonfec577f2007-02-26 10:40:21 -050089{
Chris Mason234b63a2007-03-13 10:46:10 -040090 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -040091 struct btrfs_key key;
Chris Masonfec577f2007-02-26 10:40:21 -050092 int ret;
93 unsigned long *ptr;
Chris Mason234b63a2007-03-13 10:46:10 -040094 btrfs_init_path(&path);
Chris Masonfec577f2007-02-26 10:40:21 -050095 ret = setup_key(radix, &key, 1);
96 if (ret < 0)
97 return 0;
Chris Masone089f052007-03-16 16:20:31 -040098 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
Chris Masonfec577f2007-02-26 10:40:21 -050099 if (ret)
100 goto error;
Chris Masone089f052007-03-16 16:20:31 -0400101 ret = btrfs_del_item(trans, root, &path);
Chris Mason234b63a2007-03-13 10:46:10 -0400102 btrfs_release_path(root, &path);
Chris Masonfec577f2007-02-26 10:40:21 -0500103 if (ret != 0)
104 goto error;
105 ptr = radix_tree_delete(radix, key.objectid);
106 if (!ptr)
107 goto error;
108 return 0;
109error:
Chris Mason7cf75962007-02-26 10:55:01 -0500110 printf("failed to delete %Lu\n", key.objectid);
Chris Masonfec577f2007-02-26 10:40:21 -0500111 return -1;
112}
113
Chris Masone089f052007-03-16 16:20:31 -0400114static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root
115 *root, struct radix_tree_root *radix)
Chris Masonfec577f2007-02-26 10:40:21 -0500116{
Chris Mason234b63a2007-03-13 10:46:10 -0400117 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -0400118 struct btrfs_key key;
Chris Masonfec577f2007-02-26 10:40:21 -0500119 int ret;
Chris Mason234b63a2007-03-13 10:46:10 -0400120 btrfs_init_path(&path);
Chris Masonfec577f2007-02-26 10:40:21 -0500121 ret = setup_key(radix, &key, 1);
122 if (ret < 0)
123 return 0;
Chris Masone089f052007-03-16 16:20:31 -0400124 ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
Chris Mason234b63a2007-03-13 10:46:10 -0400125 btrfs_release_path(root, &path);
Chris Masonfec577f2007-02-26 10:40:21 -0500126 if (ret)
127 goto error;
128 return 0;
129error:
Chris Mason7cf75962007-02-26 10:55:01 -0500130 printf("unable to find key %Lu\n", key.objectid);
Chris Masonfec577f2007-02-26 10:40:21 -0500131 return -1;
132}
133
Chris Masone089f052007-03-16 16:20:31 -0400134static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root
135 *root, struct radix_tree_root *radix)
Chris Masonfec577f2007-02-26 10:40:21 -0500136{
Chris Mason234b63a2007-03-13 10:46:10 -0400137 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -0400138 struct btrfs_key key;
Chris Masonfec577f2007-02-26 10:40:21 -0500139 int ret;
Chris Mason234b63a2007-03-13 10:46:10 -0400140 btrfs_init_path(&path);
Chris Masonfec577f2007-02-26 10:40:21 -0500141 ret = setup_key(radix, &key, 0);
142 if (ret < 0)
143 return ret;
Chris Masone089f052007-03-16 16:20:31 -0400144 ret = btrfs_search_slot(trans, root, &key, &path, 0, 0);
Chris Mason234b63a2007-03-13 10:46:10 -0400145 btrfs_release_path(root, &path);
Chris Masonaa5d6be2007-02-28 16:35:06 -0500146 if (ret <= 0)
Chris Masonfec577f2007-02-26 10:40:21 -0500147 goto error;
148 return 0;
149error:
Chris Mason7cf75962007-02-26 10:55:01 -0500150 printf("able to find key that should not exist %Lu\n", key.objectid);
Chris Masonfec577f2007-02-26 10:40:21 -0500151 return -1;
152}
153
Chris Masone089f052007-03-16 16:20:31 -0400154static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root
155 *root, struct radix_tree_root *radix, int nr)
Chris Mason79f95c82007-03-01 15:16:26 -0500156{
Chris Mason234b63a2007-03-13 10:46:10 -0400157 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -0400158 struct btrfs_key key;
Chris Mason79f95c82007-03-01 15:16:26 -0500159 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;
Chris Mason62e27492007-03-15 12:56:47 -0400167 btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY);
Chris Mason79f95c82007-03-01 15:16:26 -0500168 key.objectid = (unsigned long)-1;
169 while(nr-- >= 0) {
Chris Mason234b63a2007-03-13 10:46:10 -0400170 btrfs_init_path(&path);
Chris Masone089f052007-03-16 16:20:31 -0400171 ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
Chris Mason79f95c82007-03-01 15:16:26 -0500172 if (ret < 0) {
Chris Mason234b63a2007-03-13 10:46:10 -0400173 btrfs_release_path(root, &path);
Chris Mason79f95c82007-03-01 15:16:26 -0500174 return ret;
175 }
176 if (ret != 0) {
177 if (path.slots[0] == 0) {
Chris Mason234b63a2007-03-13 10:46:10 -0400178 btrfs_release_path(root, &path);
Chris Mason79f95c82007-03-01 15:16:26 -0500179 break;
180 }
181 path.slots[0] -= 1;
182 }
183 slot = path.slots[0];
Chris Mason62e27492007-03-15 12:56:47 -0400184 found = btrfs_disk_key_objectid(
185 &path.nodes[0]->leaf.items[slot].key);
Chris Masone089f052007-03-16 16:20:31 -0400186 ret = btrfs_del_item(trans, root, &path);
Chris Mason79f95c82007-03-01 15:16:26 -0500187 count++;
188 if (ret) {
189 fprintf(stderr,
190 "failed to remove %lu from tree\n",
191 found);
192 return -1;
193 }
Chris Mason234b63a2007-03-13 10:46:10 -0400194 btrfs_release_path(root, &path);
Chris Mason79f95c82007-03-01 15:16:26 -0500195 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
Chris Masone089f052007-03-16 16:20:31 -0400207static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root,
208 struct radix_tree_root *radix, int count)
Chris Mason79f95c82007-03-01 15:16:26 -0500209{
210 int i;
Chris Mason79f95c82007-03-01 15:16:26 -0500211 int ret = 0;
212 for (i = 0; i < count; i++) {
Chris Masone089f052007-03-16 16:20:31 -0400213 ret = ins_one(trans, root, radix);
Chris Mason79f95c82007-03-01 15:16:26 -0500214 if (ret) {
Chris Mason77ce6842007-03-02 10:06:43 -0500215 fprintf(stderr, "fill failed\n");
Chris Mason79f95c82007-03-01 15:16:26 -0500216 goto out;
217 }
Chris Mason77ce6842007-03-02 10:06:43 -0500218 if (i % 1000 == 0) {
Chris Masone089f052007-03-16 16:20:31 -0400219 ret = btrfs_commit_transaction(trans, root, &super);
Chris Mason77ce6842007-03-02 10:06:43 -0500220 if (ret) {
221 fprintf(stderr, "fill commit failed\n");
222 return ret;
223 }
224 }
Chris Mason02217ed2007-03-02 16:08:05 -0500225 if (i && i % 10000 == 0) {
Chris Mason77ce6842007-03-02 10:06:43 -0500226 printf("bigfill %d\n", i);
227 }
Chris Mason79f95c82007-03-01 15:16:26 -0500228 if (!keep_running)
229 break;
230 }
231out:
232 return ret;
233}
234
Chris Masone089f052007-03-16 16:20:31 -0400235static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root,
236 struct radix_tree_root *radix)
Chris Mason79f95c82007-03-01 15:16:26 -0500237{
238 int ret;
Chris Masona28ec192007-03-06 20:08:01 -0500239 int nr = rand() % 5000;
Chris Mason79f95c82007-03-01 15:16:26 -0500240 static int run_nr = 0;
241
242 /* do the bulk op much less frequently */
243 if (run_nr++ % 100)
244 return 0;
Chris Masone089f052007-03-16 16:20:31 -0400245 ret = empty_tree(trans, root, radix, nr);
Chris Mason79f95c82007-03-01 15:16:26 -0500246 if (ret)
247 return ret;
Chris Masone089f052007-03-16 16:20:31 -0400248 ret = fill_tree(trans, root, radix, nr);
Chris Mason79f95c82007-03-01 15:16:26 -0500249 if (ret)
250 return ret;
251 return 0;
252}
253
254
Chris Masone089f052007-03-16 16:20:31 -0400255int (*ops[])(struct btrfs_trans_handle *,
256 struct btrfs_root *root, struct radix_tree_root *radix) =
Chris Masonf0930a32007-03-02 09:47:58 -0500257 { ins_one, insert_dup, del_one, lookup_item,
Chris Masona28ec192007-03-06 20:08:01 -0500258 lookup_enoent, bulk_op };
Chris Masonfec577f2007-02-26 10:40:21 -0500259
Chris Mason234b63a2007-03-13 10:46:10 -0400260static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix)
Chris Masonfec577f2007-02-26 10:40:21 -0500261{
Chris Mason234b63a2007-03-13 10:46:10 -0400262 struct btrfs_path path;
Chris Masone2fa7222007-03-12 16:22:34 -0400263 struct btrfs_key key;
Chris Mason7cf75962007-02-26 10:55:01 -0500264 unsigned long found;
Chris Masonfec577f2007-02-26 10:40:21 -0500265 int ret;
266 int slot;
267 int i;
Chris Masonaa5d6be2007-02-28 16:35:06 -0500268
Chris Masonfec577f2007-02-26 10:40:21 -0500269 key.offset = 0;
270 key.flags = 0;
Chris Mason62e27492007-03-15 12:56:47 -0400271 btrfs_set_key_type(&key, BTRFS_STRING_ITEM_KEY);
Chris Masonfec577f2007-02-26 10:40:21 -0500272 key.objectid = (unsigned long)-1;
273 while(1) {
Chris Mason234b63a2007-03-13 10:46:10 -0400274 btrfs_init_path(&path);
Chris Masone089f052007-03-16 16:20:31 -0400275 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
Chris Masonaa5d6be2007-02-28 16:35:06 -0500276 if (ret < 0) {
Chris Mason234b63a2007-03-13 10:46:10 -0400277 btrfs_release_path(root, &path);
Chris Masonaa5d6be2007-02-28 16:35:06 -0500278 return ret;
279 }
Chris Masonfec577f2007-02-26 10:40:21 -0500280 slot = path.slots[0];
281 if (ret != 0) {
282 if (slot == 0) {
Chris Mason234b63a2007-03-13 10:46:10 -0400283 btrfs_release_path(root, &path);
Chris Masonfec577f2007-02-26 10:40:21 -0500284 break;
285 }
286 slot -= 1;
287 }
288 for (i = slot; i >= 0; i--) {
Chris Mason62e27492007-03-15 12:56:47 -0400289 found = btrfs_disk_key_objectid(&path.nodes[0]->
290 leaf.items[i].key);
Chris Masonfec577f2007-02-26 10:40:21 -0500291 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 }
Chris Mason234b63a2007-03-13 10:46:10 -0400302 btrfs_release_path(root, &path);
Chris Masonfec577f2007-02-26 10:40:21 -0500303 key.objectid = found - 1;
304 if (key.objectid > found)
305 break;
306 }
307 return 0;
308}
Chris Masonfec577f2007-02-26 10:40:21 -0500309void 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);
Chris Mason234b63a2007-03-13 10:46:10 -0400327 struct btrfs_root *root;
Chris Masonfec577f2007-02-26 10:40:21 -0500328 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;
Chris Masone089f052007-03-16 16:20:31 -0400336 struct btrfs_trans_handle *trans;
Chris Masonfec577f2007-02-26 10:40:21 -0500337 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 }
Chris Mason79f95c82007-03-01 15:16:26 -0500357 printf("initial fill\n");
Chris Masone089f052007-03-16 16:20:31 -0400358 trans = btrfs_start_transaction(root, 1);
359 ret = fill_tree(trans, root, &radix, init_fill_count);
Chris Mason79f95c82007-03-01 15:16:26 -0500360 printf("starting run\n");
361 if (ret) {
362 err = ret;
363 goto out;
Chris Masonfec577f2007-02-26 10:40:21 -0500364 }
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",
Chris Mason7518a232007-03-12 12:01:18 -0400377 btrfs_header_level(&root->node->node.header),
378 btrfs_header_nritems(&root->node->node.header));
Chris Masona28ec192007-03-06 20:08:01 -0500379 close_ctree(root, &super);
Chris Masonfec577f2007-02-26 10:40:21 -0500380 root = open_ctree("dbfile", &super);
381 }
382 while(count--) {
Chris Masone089f052007-03-16 16:20:31 -0400383 ret = ops[op](trans, root, &radix);
Chris Masonfec577f2007-02-26 10:40:21 -0500384 if (ret) {
385 fprintf(stderr, "op %d failed %d:%d\n",
386 op, i, iterations);
Chris Mason234b63a2007-03-13 10:46:10 -0400387 btrfs_print_tree(root, root->node);
Chris Masonfec577f2007-02-26 10:40:21 -0500388 fprintf(stderr, "op %d failed %d:%d\n",
389 op, i, iterations);
390 err = ret;
391 goto out;
392 }
Chris Masona28ec192007-03-06 20:08:01 -0500393 if (ops[op] == bulk_op)
Chris Mason79f95c82007-03-01 15:16:26 -0500394 break;
Chris Masonfec577f2007-02-26 10:40:21 -0500395 if (keep_running == 0) {
396 err = 0;
397 goto out;
398 }
399 }
400 }
401out:
Chris Masona28ec192007-03-06 20:08:01 -0500402 close_ctree(root, &super);
Chris Masonfec577f2007-02-26 10:40:21 -0500403 return err;
404}
405