2 * Copyright (C) 2007 Oracle. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
22 #include "kerncompat.h"
23 #include "radix-tree.h"
26 #include "print-tree.h"
27 #include "transaction.h"
30 struct btrfs_super_block super
;
32 static int setup_key(struct radix_tree_root
*root
, struct btrfs_key
*key
,
40 key
->type
= BTRFS_STRING_ITEM_KEY
;
43 ret
= radix_tree_gang_lookup(root
, (void **)res
, num
, 2);
48 } else if (ret
!= 0 && num
== res
[0]) {
50 if (ret
> 1 && num
== res
[1]) {
59 static int ins_one(struct btrfs_trans_handle
*trans
, struct btrfs_root
*root
,
60 struct radix_tree_root
*radix
)
62 struct btrfs_path path
;
67 btrfs_init_path(&path
);
68 ret
= setup_key(radix
, &key
, 0);
69 sprintf(buf
, "str-%llu\n", (unsigned long long)key
.objectid
);
70 ret
= btrfs_insert_item(trans
, root
, &key
, buf
, strlen(buf
));
73 oid
= (unsigned long)key
.objectid
;
74 radix_tree_preload(GFP_KERNEL
);
75 ret
= radix_tree_insert(radix
, oid
, (void *)oid
);
76 radix_tree_preload_end();
81 printf("failed to insert %llu\n", (unsigned long long)key
.objectid
);
85 static int insert_dup(struct btrfs_trans_handle
*trans
, struct btrfs_root
86 *root
, struct radix_tree_root
*radix
)
88 struct btrfs_path path
;
92 btrfs_init_path(&path
);
93 ret
= setup_key(radix
, &key
, 1);
96 sprintf(buf
, "str-%llu\n", (unsigned long long)key
.objectid
);
97 ret
= btrfs_insert_item(trans
, root
, &key
, buf
, strlen(buf
));
99 printf("insert on %llu gave us %d\n",
100 (unsigned long long)key
.objectid
, ret
);
106 static int del_one(struct btrfs_trans_handle
*trans
, struct btrfs_root
*root
,
107 struct radix_tree_root
*radix
)
109 struct btrfs_path path
;
110 struct btrfs_key key
;
113 btrfs_init_path(&path
);
114 ret
= setup_key(radix
, &key
, 1);
117 ret
= btrfs_search_slot(trans
, root
, &key
, &path
, -1, 1);
120 ret
= btrfs_del_item(trans
, root
, &path
);
121 btrfs_release_path(&path
);
124 ptr
= radix_tree_delete(radix
, key
.objectid
);
129 printf("failed to delete %llu\n", (unsigned long long)key
.objectid
);
133 static int lookup_item(struct btrfs_trans_handle
*trans
, struct btrfs_root
134 *root
, struct radix_tree_root
*radix
)
136 struct btrfs_path path
;
137 struct btrfs_key key
;
139 btrfs_init_path(&path
);
140 ret
= setup_key(radix
, &key
, 1);
143 ret
= btrfs_search_slot(trans
, root
, &key
, &path
, 0, 1);
144 btrfs_release_path(&path
);
149 printf("unable to find key %llu\n", (unsigned long long)key
.objectid
);
153 static int lookup_enoent(struct btrfs_trans_handle
*trans
, struct btrfs_root
154 *root
, struct radix_tree_root
*radix
)
156 struct btrfs_path path
;
157 struct btrfs_key key
;
159 btrfs_init_path(&path
);
160 ret
= setup_key(radix
, &key
, 0);
163 ret
= btrfs_search_slot(trans
, root
, &key
, &path
, 0, 0);
164 btrfs_release_path(&path
);
169 printf("able to find key that should not exist %llu\n",
170 (unsigned long long)key
.objectid
);
174 static int empty_tree(struct btrfs_trans_handle
*trans
, struct btrfs_root
175 *root
, struct radix_tree_root
*radix
, int nr
)
177 struct btrfs_path path
;
178 struct btrfs_key key
;
179 unsigned long found
= 0;
187 key
.type
= BTRFS_STRING_ITEM_KEY
;
188 key
.objectid
= (unsigned long)-1;
190 btrfs_init_path(&path
);
191 ret
= btrfs_search_slot(trans
, root
, &key
, &path
, -1, 1);
193 btrfs_release_path(&path
);
197 if (path
.slots
[0] == 0) {
198 btrfs_release_path(&path
);
203 slot
= path
.slots
[0];
204 found
= btrfs_disk_key_objectid(
205 &path
.nodes
[0]->leaf
.items
[slot
].key
);
206 ret
= btrfs_del_item(trans
, root
, &path
);
210 "failed to remove %lu from tree\n",
214 btrfs_release_path(&path
);
215 ptr
= radix_tree_delete(radix
, found
);
223 fprintf(stderr
, "failed to delete from the radix %lu\n", found
);
227 static int fill_tree(struct btrfs_trans_handle
*trans
, struct btrfs_root
*root
,
228 struct radix_tree_root
*radix
, int count
)
232 for (i
= 0; i
< count
; i
++) {
233 ret
= ins_one(trans
, root
, radix
);
235 fprintf(stderr
, "fill failed\n");
239 ret
= btrfs_commit_transaction(trans
, root
, &super
);
241 fprintf(stderr
, "fill commit failed\n");
245 if (i
&& i
% 10000 == 0) {
246 printf("bigfill %d\n", i
);
255 static int bulk_op(struct btrfs_trans_handle
*trans
, struct btrfs_root
*root
,
256 struct radix_tree_root
*radix
)
259 int nr
= rand() % 5000;
260 static int run_nr
= 0;
262 /* do the bulk op much less frequently */
265 ret
= empty_tree(trans
, root
, radix
, nr
);
268 ret
= fill_tree(trans
, root
, radix
, nr
);
275 int (*ops
[])(struct btrfs_trans_handle
*,
276 struct btrfs_root
*root
, struct radix_tree_root
*radix
) =
277 { ins_one
, insert_dup
, del_one
, lookup_item
,
278 lookup_enoent
, bulk_op
};
280 static int fill_radix(struct btrfs_root
*root
, struct radix_tree_root
*radix
)
282 struct btrfs_path path
;
283 struct btrfs_key key
;
284 unsigned long found
= 0;
291 key
.type
= BTRFS_STRING_ITEM_KEY
;
292 key
.objectid
= (unsigned long)-1;
294 btrfs_init_path(&path
);
295 ret
= btrfs_search_slot(NULL
, root
, &key
, &path
, 0, 0);
297 btrfs_release_path(&path
);
300 slot
= path
.slots
[0];
303 btrfs_release_path(&path
);
308 for (i
= slot
; i
>= 0; i
--) {
309 found
= btrfs_disk_key_objectid(&path
.nodes
[0]->
311 radix_tree_preload(GFP_KERNEL
);
312 ret
= radix_tree_insert(radix
, found
, (void *)found
);
315 "failed to insert %lu into radix\n",
320 radix_tree_preload_end();
322 btrfs_release_path(&path
);
323 key
.objectid
= found
- 1;
324 if (key
.objectid
> found
)
329 void sigstopper(int ignored
)
332 fprintf(stderr
, "caught exit signal, stopping\n");
335 int print_usage(void)
337 printf("usage: tester [-ih] [-c count] [-f count]\n");
338 printf("\t -c count -- iteration count after filling\n");
339 printf("\t -f count -- run this many random inserts before starting\n");
340 printf("\t -i -- only do initial fill\n");
341 printf("\t -h -- this help text\n");
344 int main(int ac
, char **av
)
346 RADIX_TREE(radix
, GFP_KERNEL
);
347 struct btrfs_root
*root
;
352 int iterations
= 20000;
353 int init_fill_count
= 800000;
355 int initial_only
= 0;
356 struct btrfs_trans_handle
*trans
;
358 root
= open_ctree("dbfile", &super
);
360 fprintf(stderr
, "Open ctree failed\n");
363 fill_radix(root
, &radix
);
365 signal(SIGTERM
, sigstopper
);
366 signal(SIGINT
, sigstopper
);
368 for (i
= 1 ; i
< ac
; i
++) {
369 if (strcmp(av
[i
], "-i") == 0) {
371 } else if (strcmp(av
[i
], "-c") == 0) {
372 iterations
= atoi(av
[i
+1]);
374 } else if (strcmp(av
[i
], "-f") == 0) {
375 init_fill_count
= atoi(av
[i
+1]);
381 printf("initial fill\n");
382 trans
= btrfs_start_transaction(root
, 1);
383 BUG_ON(IS_ERR(trans
));
384 ret
= fill_tree(trans
, root
, &radix
, init_fill_count
);
385 printf("starting run\n");
390 if (initial_only
== 1) {
393 for (i
= 0; i
< iterations
; i
++) {
394 op
= rand() % ARRAY_SIZE(ops
);
395 count
= rand() % 128;
400 if (i
&& i
% 5000 == 0) {
401 printf("open & close, root level %d nritems %d\n",
402 btrfs_header_level(&root
->node
->node
.header
),
403 btrfs_header_nritems(&root
->node
->node
.header
));
404 close_ctree(root
, &super
);
405 root
= open_ctree("dbfile", &super
);
407 fprintf(stderr
, "Open ctree failed\n");
412 ret
= ops
[op
](trans
, root
, &radix
);
414 fprintf(stderr
, "op %d failed %d:%d\n",
416 btrfs_print_tree(root
, root
->node
, 1);
417 fprintf(stderr
, "op %d failed %d:%d\n",
422 if (ops
[op
] == bulk_op
)
424 if (keep_running
== 0) {
431 close_ctree(root
, &super
);