random-test.c 8.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "kerncompat.h"
#include "radix-tree.h"
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"

int keep_running = 1;
C
Chris Mason 已提交
11
struct btrfs_super_block super;
12

C
Chris Mason 已提交
13 14
static int setup_key(struct radix_tree_root *root, struct btrfs_key *key,
		     int exists)
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
{
	int num = rand();
	unsigned long res[2];
	int ret;

	key->flags = 0;
	key->offset = 0;
again:
	ret = radix_tree_gang_lookup(root, (void **)res, num, 2);
	if (exists) {
		if (ret == 0)
			return -1;
		num = res[0];
	} else if (ret != 0 && num == res[0]) {
		num++;
		if (ret > 1 && num == res[1]) {
			num++;
			goto again;
		}
	}
	key->objectid = num;
	return 0;
}

C
Chris Mason 已提交
39
static int ins_one(struct btrfs_root *root, struct radix_tree_root *radix)
40
{
C
Chris Mason 已提交
41
	struct btrfs_path path;
C
Chris Mason 已提交
42
	struct btrfs_key key;
43 44
	int ret;
	char buf[128];
C
Chris Mason 已提交
45
	unsigned long oid;
C
Chris Mason 已提交
46
	btrfs_init_path(&path);
47
	ret = setup_key(radix, &key, 0);
C
Chris Mason 已提交
48
	sprintf(buf, "str-%Lu\n", key.objectid);
C
Chris Mason 已提交
49
	ret = btrfs_insert_item(root, &key, buf, strlen(buf));
50 51
	if (ret)
		goto error;
C
Chris Mason 已提交
52
	oid = (unsigned long)key.objectid;
53
	radix_tree_preload(GFP_KERNEL);
C
Chris Mason 已提交
54
	ret = radix_tree_insert(radix, oid, (void *)oid);
55 56 57 58 59
	radix_tree_preload_end();
	if (ret)
		goto error;
	return ret;
error:
C
Chris Mason 已提交
60
	printf("failed to insert %Lu\n", key.objectid);
61 62 63
	return -1;
}

C
Chris Mason 已提交
64
static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
65
{
C
Chris Mason 已提交
66
	struct btrfs_path path;
C
Chris Mason 已提交
67
	struct btrfs_key key;
68 69
	int ret;
	char buf[128];
C
Chris Mason 已提交
70
	btrfs_init_path(&path);
71 72 73
	ret = setup_key(radix, &key, 1);
	if (ret < 0)
		return 0;
C
Chris Mason 已提交
74
	sprintf(buf, "str-%Lu\n", key.objectid);
C
Chris Mason 已提交
75
	ret = btrfs_insert_item(root, &key, buf, strlen(buf));
76
	if (ret != -EEXIST) {
C
Chris Mason 已提交
77
		printf("insert on %Lu gave us %d\n", key.objectid, ret);
78 79 80 81 82
		return 1;
	}
	return 0;
}

C
Chris Mason 已提交
83
static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
84
{
C
Chris Mason 已提交
85
	struct btrfs_path path;
C
Chris Mason 已提交
86
	struct btrfs_key key;
87 88
	int ret;
	unsigned long *ptr;
C
Chris Mason 已提交
89
	btrfs_init_path(&path);
90 91 92
	ret = setup_key(radix, &key, 1);
	if (ret < 0)
		return 0;
C
Chris Mason 已提交
93
	ret = btrfs_search_slot(root, &key, &path, -1, 1);
94 95
	if (ret)
		goto error;
C
Chris Mason 已提交
96 97
	ret = btrfs_del_item(root, &path);
	btrfs_release_path(root, &path);
98 99 100 101 102 103 104
	if (ret != 0)
		goto error;
	ptr = radix_tree_delete(radix, key.objectid);
	if (!ptr)
		goto error;
	return 0;
error:
C
Chris Mason 已提交
105
	printf("failed to delete %Lu\n", key.objectid);
106 107 108
	return -1;
}

C
Chris Mason 已提交
109
static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
110
{
C
Chris Mason 已提交
111
	struct btrfs_path path;
C
Chris Mason 已提交
112
	struct btrfs_key key;
113
	int ret;
C
Chris Mason 已提交
114
	btrfs_init_path(&path);
115 116 117
	ret = setup_key(radix, &key, 1);
	if (ret < 0)
		return 0;
C
Chris Mason 已提交
118 119
	ret = btrfs_search_slot(root, &key, &path, 0, 1);
	btrfs_release_path(root, &path);
120 121 122 123
	if (ret)
		goto error;
	return 0;
error:
C
Chris Mason 已提交
124
	printf("unable to find key %Lu\n", key.objectid);
125 126 127
	return -1;
}

C
Chris Mason 已提交
128
static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
129
{
C
Chris Mason 已提交
130
	struct btrfs_path path;
C
Chris Mason 已提交
131
	struct btrfs_key key;
132
	int ret;
C
Chris Mason 已提交
133
	btrfs_init_path(&path);
134 135 136
	ret = setup_key(radix, &key, 0);
	if (ret < 0)
		return ret;
C
Chris Mason 已提交
137 138
	ret = btrfs_search_slot(root, &key, &path, 0, 0);
	btrfs_release_path(root, &path);
C
Chris Mason 已提交
139
	if (ret <= 0)
140 141 142
		goto error;
	return 0;
error:
C
Chris Mason 已提交
143
	printf("able to find key that should not exist %Lu\n", key.objectid);
144 145 146
	return -1;
}

C
Chris Mason 已提交
147
static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
148 149
		      int nr)
{
C
Chris Mason 已提交
150
	struct btrfs_path path;
C
Chris Mason 已提交
151
	struct btrfs_key key;
152 153 154 155 156 157 158 159 160 161
	unsigned long found = 0;
	int ret;
	int slot;
	int *ptr;
	int count = 0;

	key.offset = 0;
	key.flags = 0;
	key.objectid = (unsigned long)-1;
	while(nr-- >= 0) {
C
Chris Mason 已提交
162 163
		btrfs_init_path(&path);
		ret = btrfs_search_slot(root, &key, &path, -1, 1);
164
		if (ret < 0) {
C
Chris Mason 已提交
165
			btrfs_release_path(root, &path);
166 167 168 169
			return ret;
		}
		if (ret != 0) {
			if (path.slots[0] == 0) {
C
Chris Mason 已提交
170
				btrfs_release_path(root, &path);
171 172 173 174 175
				break;
			}
			path.slots[0] -= 1;
		}
		slot = path.slots[0];
C
Chris Mason 已提交
176
		found=btrfs_key_objectid(&path.nodes[0]->leaf.items[slot].key);
C
Chris Mason 已提交
177
		ret = btrfs_del_item(root, &path);
178 179 180 181 182 183 184
		count++;
		if (ret) {
			fprintf(stderr,
				"failed to remove %lu from tree\n",
				found);
			return -1;
		}
C
Chris Mason 已提交
185
		btrfs_release_path(root, &path);
186 187 188 189 190 191 192 193 194 195 196 197
		ptr = radix_tree_delete(radix, found);
		if (!ptr)
			goto error;
		if (!keep_running)
			break;
	}
	return 0;
error:
	fprintf(stderr, "failed to delete from the radix %lu\n", found);
	return -1;
}

C
Chris Mason 已提交
198
static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
199 200 201 202 203 204 205
		     int count)
{
	int i;
	int ret = 0;
	for (i = 0; i < count; i++) {
		ret = ins_one(root, radix);
		if (ret) {
206
			fprintf(stderr, "fill failed\n");
207 208
			goto out;
		}
209
		if (i % 1000 == 0) {
C
Chris Mason 已提交
210
			ret = btrfs_commit_transaction(root, &super);
211 212 213 214 215
			if (ret) {
				fprintf(stderr, "fill commit failed\n");
				return ret;
			}
		}
C
Chris Mason 已提交
216
		if (i && i % 10000 == 0) {
217 218
			printf("bigfill %d\n", i);
		}
219 220 221 222 223 224 225
		if (!keep_running)
			break;
	}
out:
	return ret;
}

C
Chris Mason 已提交
226
static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
227 228
{
	int ret;
229
	int nr = rand() % 5000;
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
	static int run_nr = 0;

	/* do the bulk op much less frequently */
	if (run_nr++ % 100)
		return 0;
	ret = empty_tree(root, radix, nr);
	if (ret)
		return ret;
	ret = fill_tree(root, radix, nr);
	if (ret)
		return ret;
	return 0;
}


C
Chris Mason 已提交
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 };
248

C
Chris Mason 已提交
249
static int fill_radix(struct btrfs_root *root, struct radix_tree_root *radix)
250
{
C
Chris Mason 已提交
251
	struct btrfs_path path;
C
Chris Mason 已提交
252
	struct btrfs_key key;
C
Chris Mason 已提交
253
	unsigned long found;
254 255 256
	int ret;
	int slot;
	int i;
C
Chris Mason 已提交
257

258 259 260 261
	key.offset = 0;
	key.flags = 0;
	key.objectid = (unsigned long)-1;
	while(1) {
C
Chris Mason 已提交
262 263
		btrfs_init_path(&path);
		ret = btrfs_search_slot(root, &key, &path, 0, 0);
C
Chris Mason 已提交
264
		if (ret < 0) {
C
Chris Mason 已提交
265
			btrfs_release_path(root, &path);
C
Chris Mason 已提交
266 267
			return ret;
		}
268 269 270
		slot = path.slots[0];
		if (ret != 0) {
			if (slot == 0) {
C
Chris Mason 已提交
271
				btrfs_release_path(root, &path);
272 273 274 275 276
				break;
			}
			slot -= 1;
		}
		for (i = slot; i >= 0; i--) {
C
Chris Mason 已提交
277 278
			found = btrfs_key_objectid(&path.nodes[0]->
						   leaf.items[i].key);
279 280 281 282 283 284 285 286 287 288 289
			radix_tree_preload(GFP_KERNEL);
			ret = radix_tree_insert(radix, found, (void *)found);
			if (ret) {
				fprintf(stderr,
					"failed to insert %lu into radix\n",
					found);
				exit(1);
			}

			radix_tree_preload_end();
		}
C
Chris Mason 已提交
290
		btrfs_release_path(root, &path);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
		key.objectid = found - 1;
		if (key.objectid > found)
			break;
	}
	return 0;
}
void sigstopper(int ignored)
{
	keep_running = 0;
	fprintf(stderr, "caught exit signal, stopping\n");
}

int print_usage(void)
{
	printf("usage: tester [-ih] [-c count] [-f count]\n");
	printf("\t -c count -- iteration count after filling\n");
	printf("\t -f count -- run this many random inserts before starting\n");
	printf("\t -i       -- only do initial fill\n");
	printf("\t -h       -- this help text\n");
	exit(1);
}
int main(int ac, char **av)
{
	RADIX_TREE(radix, GFP_KERNEL);
C
Chris Mason 已提交
315
	struct btrfs_root *root;
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
	int i;
	int ret;
	int count;
	int op;
	int iterations = 20000;
	int init_fill_count = 800000;
	int err = 0;
	int initial_only = 0;
	radix_tree_init();
	root = open_ctree("dbfile", &super);
	fill_radix(root, &radix);

	signal(SIGTERM, sigstopper);
	signal(SIGINT, sigstopper);

	for (i = 1 ; i < ac ; i++) {
		if (strcmp(av[i], "-i") == 0) {
			initial_only = 1;
		} else if (strcmp(av[i], "-c") == 0) {
			iterations = atoi(av[i+1]);
			i++;
		} else if (strcmp(av[i], "-f") == 0) {
			init_fill_count = atoi(av[i+1]);
			i++;
		} else {
			print_usage();
		}
	}
344 345 346 347 348 349
	printf("initial fill\n");
	ret = fill_tree(root, &radix, init_fill_count);
	printf("starting run\n");
	if (ret) {
		err = ret;
		goto out;
350 351 352 353 354 355 356 357 358 359 360 361 362
	}
	if (initial_only == 1) {
		goto out;
	}
	for (i = 0; i < iterations; i++) {
		op = rand() % ARRAY_SIZE(ops);
		count = rand() % 128;
		if (i % 2000 == 0) {
			printf("%d\n", i);
			fflush(stdout);
		}
		if (i && i % 5000 == 0) {
			printf("open & close, root level %d nritems %d\n",
363 364
				btrfs_header_level(&root->node->node.header),
				btrfs_header_nritems(&root->node->node.header));
365
			close_ctree(root, &super);
366 367 368 369 370 371 372
			root = open_ctree("dbfile", &super);
		}
		while(count--) {
			ret = ops[op](root, &radix);
			if (ret) {
				fprintf(stderr, "op %d failed %d:%d\n",
					op, i, iterations);
C
Chris Mason 已提交
373
				btrfs_print_tree(root, root->node);
374 375 376 377 378
				fprintf(stderr, "op %d failed %d:%d\n",
					op, i, iterations);
				err = ret;
				goto out;
			}
379
			if (ops[op] == bulk_op)
380
				break;
381 382 383 384 385 386 387
			if (keep_running == 0) {
				err = 0;
				goto out;
			}
		}
	}
out:
388
	close_ctree(root, &super);
389 390 391
	return err;
}