1716fd348SMartin Matuska /* 2716fd348SMartin Matuska * This file and its contents are supplied under the terms of the 3716fd348SMartin Matuska * Common Development and Distribution License ("CDDL"), version 1.0. 4716fd348SMartin Matuska * You may only use this file in accordance with the terms of version 5716fd348SMartin Matuska * 1.0 of the CDDL. 6716fd348SMartin Matuska * 7716fd348SMartin Matuska * A full copy of the text of the CDDL should have accompanied this 8716fd348SMartin Matuska * source. A copy of the CDDL is also available via the Internet at 9716fd348SMartin Matuska * http://www.illumos.org/license/CDDL. 10716fd348SMartin Matuska */ 11716fd348SMartin Matuska 12716fd348SMartin Matuska /* 13716fd348SMartin Matuska * Copyright (c) 2019 by Delphix. All rights reserved. 14716fd348SMartin Matuska */ 15716fd348SMartin Matuska 16716fd348SMartin Matuska #include <stdio.h> 17716fd348SMartin Matuska #include <stdlib.h> 18be181ee2SMartin Matuska #include <string.h> 19716fd348SMartin Matuska #include <sys/avl.h> 20716fd348SMartin Matuska #include <sys/btree.h> 21716fd348SMartin Matuska #include <sys/time.h> 22716fd348SMartin Matuska #include <sys/resource.h> 23716fd348SMartin Matuska 24716fd348SMartin Matuska #define BUFSIZE 256 25716fd348SMartin Matuska 26*dbd5678dSMartin Matuska static int seed = 0; 27*dbd5678dSMartin Matuska static int stress_timeout = 180; 28*dbd5678dSMartin Matuska static int contents_frequency = 100; 29*dbd5678dSMartin Matuska static int tree_limit = 64 * 1024; 30*dbd5678dSMartin Matuska static boolean_t stress_only = B_FALSE; 31716fd348SMartin Matuska 32716fd348SMartin Matuska static void 33716fd348SMartin Matuska usage(int exit_value) 34716fd348SMartin Matuska { 35716fd348SMartin Matuska (void) fprintf(stderr, "Usage:\tbtree_test -n <test_name>\n"); 36716fd348SMartin Matuska (void) fprintf(stderr, "\tbtree_test -s [-r <seed>] [-l <limit>] " 37716fd348SMartin Matuska "[-t timeout>] [-c check_contents]\n"); 38716fd348SMartin Matuska (void) fprintf(stderr, "\tbtree_test [-r <seed>] [-l <limit>] " 39716fd348SMartin Matuska "[-t timeout>] [-c check_contents]\n"); 40716fd348SMartin Matuska (void) fprintf(stderr, "\n With the -n option, run the named " 41716fd348SMartin Matuska "negative test. With the -s option,\n"); 42716fd348SMartin Matuska (void) fprintf(stderr, " run the stress test according to the " 43716fd348SMartin Matuska "other options passed. With\n"); 44716fd348SMartin Matuska (void) fprintf(stderr, " neither, run all the positive tests, " 45716fd348SMartin Matuska "including the stress test with\n"); 46716fd348SMartin Matuska (void) fprintf(stderr, " the default options.\n"); 47716fd348SMartin Matuska (void) fprintf(stderr, "\n Options that control the stress test\n"); 48716fd348SMartin Matuska (void) fprintf(stderr, "\t-c stress iterations after which to compare " 49716fd348SMartin Matuska "tree contents [default: 100]\n"); 50716fd348SMartin Matuska (void) fprintf(stderr, "\t-l the largest value to allow in the tree " 51716fd348SMartin Matuska "[default: 1M]\n"); 52716fd348SMartin Matuska (void) fprintf(stderr, "\t-r random seed [default: from " 53716fd348SMartin Matuska "gettimeofday()]\n"); 54716fd348SMartin Matuska (void) fprintf(stderr, "\t-t seconds to let the stress test run " 55716fd348SMartin Matuska "[default: 180]\n"); 56716fd348SMartin Matuska exit(exit_value); 57716fd348SMartin Matuska } 58716fd348SMartin Matuska 59716fd348SMartin Matuska typedef struct int_node { 60716fd348SMartin Matuska avl_node_t node; 61716fd348SMartin Matuska uint64_t data; 62716fd348SMartin Matuska } int_node_t; 63716fd348SMartin Matuska 64716fd348SMartin Matuska /* 65716fd348SMartin Matuska * Utility functions 66716fd348SMartin Matuska */ 67716fd348SMartin Matuska 68716fd348SMartin Matuska static int 69716fd348SMartin Matuska avl_compare(const void *v1, const void *v2) 70716fd348SMartin Matuska { 71716fd348SMartin Matuska const int_node_t *n1 = v1; 72716fd348SMartin Matuska const int_node_t *n2 = v2; 73716fd348SMartin Matuska uint64_t a = n1->data; 74716fd348SMartin Matuska uint64_t b = n2->data; 75716fd348SMartin Matuska 76716fd348SMartin Matuska return (TREE_CMP(a, b)); 77716fd348SMartin Matuska } 78716fd348SMartin Matuska 79716fd348SMartin Matuska static int 80716fd348SMartin Matuska zfs_btree_compare(const void *v1, const void *v2) 81716fd348SMartin Matuska { 82716fd348SMartin Matuska const uint64_t *a = v1; 83716fd348SMartin Matuska const uint64_t *b = v2; 84716fd348SMartin Matuska 85716fd348SMartin Matuska return (TREE_CMP(*a, *b)); 86716fd348SMartin Matuska } 87716fd348SMartin Matuska 88716fd348SMartin Matuska static void 89716fd348SMartin Matuska verify_contents(avl_tree_t *avl, zfs_btree_t *bt) 90716fd348SMartin Matuska { 91716fd348SMartin Matuska static int count = 0; 92716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 93716fd348SMartin Matuska int_node_t *node; 94716fd348SMartin Matuska uint64_t *data; 95716fd348SMartin Matuska 96716fd348SMartin Matuska boolean_t forward = count % 2 == 0 ? B_TRUE : B_FALSE; 97716fd348SMartin Matuska count++; 98716fd348SMartin Matuska 99716fd348SMartin Matuska ASSERT3U(avl_numnodes(avl), ==, zfs_btree_numnodes(bt)); 100716fd348SMartin Matuska if (forward == B_TRUE) { 101716fd348SMartin Matuska node = avl_first(avl); 102716fd348SMartin Matuska data = zfs_btree_first(bt, &bt_idx); 103716fd348SMartin Matuska } else { 104716fd348SMartin Matuska node = avl_last(avl); 105716fd348SMartin Matuska data = zfs_btree_last(bt, &bt_idx); 106716fd348SMartin Matuska } 107716fd348SMartin Matuska 108716fd348SMartin Matuska while (node != NULL) { 109716fd348SMartin Matuska ASSERT3U(*data, ==, node->data); 110716fd348SMartin Matuska if (forward == B_TRUE) { 111716fd348SMartin Matuska data = zfs_btree_next(bt, &bt_idx, &bt_idx); 112716fd348SMartin Matuska node = AVL_NEXT(avl, node); 113716fd348SMartin Matuska } else { 114716fd348SMartin Matuska data = zfs_btree_prev(bt, &bt_idx, &bt_idx); 115716fd348SMartin Matuska node = AVL_PREV(avl, node); 116716fd348SMartin Matuska } 117716fd348SMartin Matuska } 118716fd348SMartin Matuska } 119716fd348SMartin Matuska 120716fd348SMartin Matuska static void 121716fd348SMartin Matuska verify_node(avl_tree_t *avl, zfs_btree_t *bt, int_node_t *node) 122716fd348SMartin Matuska { 123716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 124716fd348SMartin Matuska zfs_btree_index_t bt_idx2 = {0}; 125716fd348SMartin Matuska int_node_t *inp; 126716fd348SMartin Matuska uint64_t data = node->data; 127716fd348SMartin Matuska uint64_t *rv = NULL; 128716fd348SMartin Matuska 129716fd348SMartin Matuska ASSERT3U(avl_numnodes(avl), ==, zfs_btree_numnodes(bt)); 130716fd348SMartin Matuska ASSERT3P((rv = (uint64_t *)zfs_btree_find(bt, &data, &bt_idx)), !=, 131716fd348SMartin Matuska NULL); 132716fd348SMartin Matuska ASSERT3S(*rv, ==, data); 133716fd348SMartin Matuska ASSERT3P(zfs_btree_get(bt, &bt_idx), !=, NULL); 134716fd348SMartin Matuska ASSERT3S(data, ==, *(uint64_t *)zfs_btree_get(bt, &bt_idx)); 135716fd348SMartin Matuska 136716fd348SMartin Matuska if ((inp = AVL_NEXT(avl, node)) != NULL) { 137716fd348SMartin Matuska ASSERT3P((rv = zfs_btree_next(bt, &bt_idx, &bt_idx2)), !=, 138716fd348SMartin Matuska NULL); 139716fd348SMartin Matuska ASSERT3P(rv, ==, zfs_btree_get(bt, &bt_idx2)); 140716fd348SMartin Matuska ASSERT3S(inp->data, ==, *rv); 141716fd348SMartin Matuska } else { 142716fd348SMartin Matuska ASSERT3U(data, ==, *(uint64_t *)zfs_btree_last(bt, &bt_idx)); 143716fd348SMartin Matuska } 144716fd348SMartin Matuska 145716fd348SMartin Matuska if ((inp = AVL_PREV(avl, node)) != NULL) { 146716fd348SMartin Matuska ASSERT3P((rv = zfs_btree_prev(bt, &bt_idx, &bt_idx2)), !=, 147716fd348SMartin Matuska NULL); 148716fd348SMartin Matuska ASSERT3P(rv, ==, zfs_btree_get(bt, &bt_idx2)); 149716fd348SMartin Matuska ASSERT3S(inp->data, ==, *rv); 150716fd348SMartin Matuska } else { 151716fd348SMartin Matuska ASSERT3U(data, ==, *(uint64_t *)zfs_btree_first(bt, &bt_idx)); 152716fd348SMartin Matuska } 153716fd348SMartin Matuska } 154716fd348SMartin Matuska 155716fd348SMartin Matuska /* 156716fd348SMartin Matuska * Tests 157716fd348SMartin Matuska */ 158716fd348SMartin Matuska 159716fd348SMartin Matuska /* Verify that zfs_btree_find works correctly with a NULL index. */ 160716fd348SMartin Matuska static int 161716fd348SMartin Matuska find_without_index(zfs_btree_t *bt, char *why) 162716fd348SMartin Matuska { 163716fd348SMartin Matuska u_longlong_t *p, i = 12345; 164716fd348SMartin Matuska 165716fd348SMartin Matuska zfs_btree_add(bt, &i); 166716fd348SMartin Matuska if ((p = (u_longlong_t *)zfs_btree_find(bt, &i, NULL)) == NULL || 167716fd348SMartin Matuska *p != i) { 168be181ee2SMartin Matuska (void) snprintf(why, BUFSIZE, "Unexpectedly found %llu\n", 169716fd348SMartin Matuska p == NULL ? 0 : *p); 170716fd348SMartin Matuska return (1); 171716fd348SMartin Matuska } 172716fd348SMartin Matuska 173716fd348SMartin Matuska i++; 174716fd348SMartin Matuska 175716fd348SMartin Matuska if ((p = (u_longlong_t *)zfs_btree_find(bt, &i, NULL)) != NULL) { 176be181ee2SMartin Matuska (void) snprintf(why, BUFSIZE, "Found bad value: %llu\n", *p); 177716fd348SMartin Matuska return (1); 178716fd348SMartin Matuska } 179716fd348SMartin Matuska 180716fd348SMartin Matuska return (0); 181716fd348SMartin Matuska } 182716fd348SMartin Matuska 183716fd348SMartin Matuska /* Verify simple insertion and removal from the tree. */ 184716fd348SMartin Matuska static int 185716fd348SMartin Matuska insert_find_remove(zfs_btree_t *bt, char *why) 186716fd348SMartin Matuska { 187716fd348SMartin Matuska u_longlong_t *p, i = 12345; 188716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 189716fd348SMartin Matuska 190716fd348SMartin Matuska /* Insert 'i' into the tree, and attempt to find it again. */ 191716fd348SMartin Matuska zfs_btree_add(bt, &i); 192716fd348SMartin Matuska if ((p = (u_longlong_t *)zfs_btree_find(bt, &i, &bt_idx)) == NULL) { 193be181ee2SMartin Matuska (void) snprintf(why, BUFSIZE, "Didn't find value in tree\n"); 194716fd348SMartin Matuska return (1); 195716fd348SMartin Matuska } else if (*p != i) { 196be181ee2SMartin Matuska (void) snprintf(why, BUFSIZE, "Found (%llu) in tree\n", *p); 197716fd348SMartin Matuska return (1); 198716fd348SMartin Matuska } 199716fd348SMartin Matuska ASSERT3S(zfs_btree_numnodes(bt), ==, 1); 200716fd348SMartin Matuska zfs_btree_verify(bt); 201716fd348SMartin Matuska 202716fd348SMartin Matuska /* Remove 'i' from the tree, and verify it is not found. */ 203716fd348SMartin Matuska zfs_btree_remove(bt, &i); 204716fd348SMartin Matuska if ((p = (u_longlong_t *)zfs_btree_find(bt, &i, &bt_idx)) != NULL) { 205be181ee2SMartin Matuska (void) snprintf(why, BUFSIZE, 206be181ee2SMartin Matuska "Found removed value (%llu)\n", *p); 207716fd348SMartin Matuska return (1); 208716fd348SMartin Matuska } 209716fd348SMartin Matuska ASSERT3S(zfs_btree_numnodes(bt), ==, 0); 210716fd348SMartin Matuska zfs_btree_verify(bt); 211716fd348SMartin Matuska 212716fd348SMartin Matuska return (0); 213716fd348SMartin Matuska } 214716fd348SMartin Matuska 215716fd348SMartin Matuska /* 216716fd348SMartin Matuska * Add a number of random entries into a btree and avl tree. Then walk them 217716fd348SMartin Matuska * backwards and forwards while emptying the tree, verifying the trees look 218716fd348SMartin Matuska * the same. 219716fd348SMartin Matuska */ 220716fd348SMartin Matuska static int 221716fd348SMartin Matuska drain_tree(zfs_btree_t *bt, char *why) 222716fd348SMartin Matuska { 223716fd348SMartin Matuska avl_tree_t avl; 224716fd348SMartin Matuska int i = 0; 225716fd348SMartin Matuska int_node_t *node; 226716fd348SMartin Matuska avl_index_t avl_idx = {0}; 227716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 228716fd348SMartin Matuska 229716fd348SMartin Matuska avl_create(&avl, avl_compare, sizeof (int_node_t), 230716fd348SMartin Matuska offsetof(int_node_t, node)); 231716fd348SMartin Matuska 232716fd348SMartin Matuska /* Fill both trees with the same data */ 233716fd348SMartin Matuska for (i = 0; i < 64 * 1024; i++) { 234716fd348SMartin Matuska u_longlong_t randval = random(); 235*dbd5678dSMartin Matuska if (zfs_btree_find(bt, &randval, &bt_idx) != NULL) { 236716fd348SMartin Matuska continue; 237716fd348SMartin Matuska } 238716fd348SMartin Matuska zfs_btree_add_idx(bt, &randval, &bt_idx); 239716fd348SMartin Matuska 240be181ee2SMartin Matuska node = malloc(sizeof (int_node_t)); 241*dbd5678dSMartin Matuska if (node == NULL) { 242*dbd5678dSMartin Matuska perror("malloc"); 243*dbd5678dSMartin Matuska exit(EXIT_FAILURE); 244*dbd5678dSMartin Matuska } 245be181ee2SMartin Matuska 246716fd348SMartin Matuska node->data = randval; 247*dbd5678dSMartin Matuska if (avl_find(&avl, node, &avl_idx) != NULL) { 248be181ee2SMartin Matuska (void) snprintf(why, BUFSIZE, 249be181ee2SMartin Matuska "Found in avl: %llu\n", randval); 250716fd348SMartin Matuska return (1); 251716fd348SMartin Matuska } 252716fd348SMartin Matuska avl_insert(&avl, node, avl_idx); 253716fd348SMartin Matuska } 254716fd348SMartin Matuska 255716fd348SMartin Matuska /* Remove data from either side of the trees, comparing the data */ 256716fd348SMartin Matuska while (avl_numnodes(&avl) != 0) { 257716fd348SMartin Matuska uint64_t *data; 258716fd348SMartin Matuska 259716fd348SMartin Matuska ASSERT3U(avl_numnodes(&avl), ==, zfs_btree_numnodes(bt)); 260716fd348SMartin Matuska if (avl_numnodes(&avl) % 2 == 0) { 261716fd348SMartin Matuska node = avl_first(&avl); 262716fd348SMartin Matuska data = zfs_btree_first(bt, &bt_idx); 263716fd348SMartin Matuska } else { 264716fd348SMartin Matuska node = avl_last(&avl); 265716fd348SMartin Matuska data = zfs_btree_last(bt, &bt_idx); 266716fd348SMartin Matuska } 267716fd348SMartin Matuska ASSERT3U(node->data, ==, *data); 268716fd348SMartin Matuska zfs_btree_remove_idx(bt, &bt_idx); 269716fd348SMartin Matuska avl_remove(&avl, node); 270716fd348SMartin Matuska 271716fd348SMartin Matuska if (avl_numnodes(&avl) == 0) { 272716fd348SMartin Matuska break; 273716fd348SMartin Matuska } 274716fd348SMartin Matuska 275716fd348SMartin Matuska node = avl_first(&avl); 276716fd348SMartin Matuska ASSERT3U(node->data, ==, 277716fd348SMartin Matuska *(uint64_t *)zfs_btree_first(bt, NULL)); 278716fd348SMartin Matuska node = avl_last(&avl); 279716fd348SMartin Matuska ASSERT3U(node->data, ==, *(uint64_t *)zfs_btree_last(bt, NULL)); 280716fd348SMartin Matuska } 281716fd348SMartin Matuska ASSERT3S(zfs_btree_numnodes(bt), ==, 0); 282716fd348SMartin Matuska 283716fd348SMartin Matuska void *avl_cookie = NULL; 284716fd348SMartin Matuska while ((node = avl_destroy_nodes(&avl, &avl_cookie)) != NULL) 285716fd348SMartin Matuska free(node); 286716fd348SMartin Matuska avl_destroy(&avl); 287716fd348SMartin Matuska 288716fd348SMartin Matuska return (0); 289716fd348SMartin Matuska } 290716fd348SMartin Matuska 291716fd348SMartin Matuska /* 292716fd348SMartin Matuska * This test uses an avl and btree, and continually processes new random 293716fd348SMartin Matuska * values. Each value is either removed or inserted, depending on whether 294716fd348SMartin Matuska * or not it is found in the tree. The test periodically checks that both 295716fd348SMartin Matuska * trees have the same data and does consistency checks. This stress 296716fd348SMartin Matuska * option can also be run on its own from the command line. 297716fd348SMartin Matuska */ 298716fd348SMartin Matuska static int 299716fd348SMartin Matuska stress_tree(zfs_btree_t *bt, char *why) 300716fd348SMartin Matuska { 301716fd348SMartin Matuska (void) why; 302716fd348SMartin Matuska avl_tree_t avl; 303716fd348SMartin Matuska int_node_t *node; 304716fd348SMartin Matuska struct timeval tp; 305716fd348SMartin Matuska time_t t0; 306716fd348SMartin Matuska int insertions = 0, removals = 0, iterations = 0; 307716fd348SMartin Matuska u_longlong_t max = 0, min = UINT64_MAX; 308716fd348SMartin Matuska 309716fd348SMartin Matuska (void) gettimeofday(&tp, NULL); 310716fd348SMartin Matuska t0 = tp.tv_sec; 311716fd348SMartin Matuska 312716fd348SMartin Matuska avl_create(&avl, avl_compare, sizeof (int_node_t), 313716fd348SMartin Matuska offsetof(int_node_t, node)); 314716fd348SMartin Matuska 315716fd348SMartin Matuska while (1) { 316716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 317716fd348SMartin Matuska avl_index_t avl_idx = {0}; 318716fd348SMartin Matuska 319716fd348SMartin Matuska uint64_t randval = random() % tree_limit; 320716fd348SMartin Matuska node = malloc(sizeof (*node)); 321*dbd5678dSMartin Matuska if (node == NULL) { 322*dbd5678dSMartin Matuska perror("malloc"); 323*dbd5678dSMartin Matuska exit(EXIT_FAILURE); 324*dbd5678dSMartin Matuska } 325716fd348SMartin Matuska node->data = randval; 326716fd348SMartin Matuska 327716fd348SMartin Matuska max = randval > max ? randval : max; 328716fd348SMartin Matuska min = randval < min ? randval : min; 329716fd348SMartin Matuska 330716fd348SMartin Matuska void *ret = avl_find(&avl, node, &avl_idx); 331716fd348SMartin Matuska if (ret == NULL) { 332716fd348SMartin Matuska insertions++; 333716fd348SMartin Matuska avl_insert(&avl, node, avl_idx); 334716fd348SMartin Matuska ASSERT3P(zfs_btree_find(bt, &randval, &bt_idx), ==, 335716fd348SMartin Matuska NULL); 336716fd348SMartin Matuska zfs_btree_add_idx(bt, &randval, &bt_idx); 337716fd348SMartin Matuska verify_node(&avl, bt, node); 338716fd348SMartin Matuska } else { 339716fd348SMartin Matuska removals++; 340716fd348SMartin Matuska verify_node(&avl, bt, ret); 341716fd348SMartin Matuska zfs_btree_remove(bt, &randval); 342716fd348SMartin Matuska avl_remove(&avl, ret); 343716fd348SMartin Matuska free(ret); 344716fd348SMartin Matuska free(node); 345716fd348SMartin Matuska } 346716fd348SMartin Matuska 347716fd348SMartin Matuska zfs_btree_verify(bt); 348716fd348SMartin Matuska 349716fd348SMartin Matuska iterations++; 350716fd348SMartin Matuska if (iterations % contents_frequency == 0) { 351716fd348SMartin Matuska verify_contents(&avl, bt); 352716fd348SMartin Matuska } 353716fd348SMartin Matuska 354716fd348SMartin Matuska zfs_btree_verify(bt); 355716fd348SMartin Matuska 356716fd348SMartin Matuska (void) gettimeofday(&tp, NULL); 357716fd348SMartin Matuska if (tp.tv_sec > t0 + stress_timeout) { 358716fd348SMartin Matuska fprintf(stderr, "insertions/removals: %u/%u\nmax/min: " 359716fd348SMartin Matuska "%llu/%llu\n", insertions, removals, max, min); 360716fd348SMartin Matuska break; 361716fd348SMartin Matuska } 362716fd348SMartin Matuska } 363716fd348SMartin Matuska 364716fd348SMartin Matuska void *avl_cookie = NULL; 365716fd348SMartin Matuska while ((node = avl_destroy_nodes(&avl, &avl_cookie)) != NULL) 366716fd348SMartin Matuska free(node); 367716fd348SMartin Matuska avl_destroy(&avl); 368716fd348SMartin Matuska 369716fd348SMartin Matuska if (stress_only) { 370716fd348SMartin Matuska zfs_btree_index_t *idx = NULL; 371*dbd5678dSMartin Matuska while (zfs_btree_destroy_nodes(bt, &idx) != NULL) 372716fd348SMartin Matuska ; 373716fd348SMartin Matuska zfs_btree_verify(bt); 374716fd348SMartin Matuska } 375716fd348SMartin Matuska 376716fd348SMartin Matuska return (0); 377716fd348SMartin Matuska } 378716fd348SMartin Matuska 379716fd348SMartin Matuska /* 380716fd348SMartin Matuska * Verify inserting a duplicate value will cause a crash. 381716fd348SMartin Matuska * Note: negative test; return of 0 is a failure. 382716fd348SMartin Matuska */ 383716fd348SMartin Matuska static int 384716fd348SMartin Matuska insert_duplicate(zfs_btree_t *bt) 385716fd348SMartin Matuska { 386*dbd5678dSMartin Matuska uint64_t i = 23456; 387716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 388716fd348SMartin Matuska 389*dbd5678dSMartin Matuska if (zfs_btree_find(bt, &i, &bt_idx) != NULL) { 390716fd348SMartin Matuska fprintf(stderr, "Found value in empty tree.\n"); 391716fd348SMartin Matuska return (0); 392716fd348SMartin Matuska } 393716fd348SMartin Matuska zfs_btree_add_idx(bt, &i, &bt_idx); 394*dbd5678dSMartin Matuska if (zfs_btree_find(bt, &i, &bt_idx) == NULL) { 395716fd348SMartin Matuska fprintf(stderr, "Did not find expected value.\n"); 396716fd348SMartin Matuska return (0); 397716fd348SMartin Matuska } 398716fd348SMartin Matuska 399716fd348SMartin Matuska /* Crash on inserting a duplicate */ 400716fd348SMartin Matuska zfs_btree_add_idx(bt, &i, NULL); 401716fd348SMartin Matuska 402716fd348SMartin Matuska return (0); 403716fd348SMartin Matuska } 404716fd348SMartin Matuska 405716fd348SMartin Matuska /* 406716fd348SMartin Matuska * Verify removing a non-existent value will cause a crash. 407716fd348SMartin Matuska * Note: negative test; return of 0 is a failure. 408716fd348SMartin Matuska */ 409716fd348SMartin Matuska static int 410716fd348SMartin Matuska remove_missing(zfs_btree_t *bt) 411716fd348SMartin Matuska { 412*dbd5678dSMartin Matuska uint64_t i = 23456; 413716fd348SMartin Matuska zfs_btree_index_t bt_idx = {0}; 414716fd348SMartin Matuska 415*dbd5678dSMartin Matuska if (zfs_btree_find(bt, &i, &bt_idx) != NULL) { 416716fd348SMartin Matuska fprintf(stderr, "Found value in empty tree.\n"); 417716fd348SMartin Matuska return (0); 418716fd348SMartin Matuska } 419716fd348SMartin Matuska 420716fd348SMartin Matuska /* Crash removing a nonexistent entry */ 421716fd348SMartin Matuska zfs_btree_remove(bt, &i); 422716fd348SMartin Matuska 423716fd348SMartin Matuska return (0); 424716fd348SMartin Matuska } 425716fd348SMartin Matuska 426716fd348SMartin Matuska static int 427716fd348SMartin Matuska do_negative_test(zfs_btree_t *bt, char *test_name) 428716fd348SMartin Matuska { 429716fd348SMartin Matuska int rval = 0; 430716fd348SMartin Matuska struct rlimit rlim = {0}; 431be181ee2SMartin Matuska 432be181ee2SMartin Matuska (void) setrlimit(RLIMIT_CORE, &rlim); 433716fd348SMartin Matuska 434716fd348SMartin Matuska if (strcmp(test_name, "insert_duplicate") == 0) { 435716fd348SMartin Matuska rval = insert_duplicate(bt); 436716fd348SMartin Matuska } else if (strcmp(test_name, "remove_missing") == 0) { 437716fd348SMartin Matuska rval = remove_missing(bt); 438716fd348SMartin Matuska } 439716fd348SMartin Matuska 440716fd348SMartin Matuska /* 441716fd348SMartin Matuska * Return 0, since callers will expect non-zero return values for 442716fd348SMartin Matuska * these tests, and we should have crashed before getting here anyway. 443716fd348SMartin Matuska */ 444716fd348SMartin Matuska (void) fprintf(stderr, "Test: %s returned %d.\n", test_name, rval); 445716fd348SMartin Matuska return (0); 446716fd348SMartin Matuska } 447716fd348SMartin Matuska 448716fd348SMartin Matuska typedef struct btree_test { 449716fd348SMartin Matuska const char *name; 450716fd348SMartin Matuska int (*func)(zfs_btree_t *, char *); 451716fd348SMartin Matuska } btree_test_t; 452716fd348SMartin Matuska 453716fd348SMartin Matuska static btree_test_t test_table[] = { 454716fd348SMartin Matuska { "insert_find_remove", insert_find_remove }, 455716fd348SMartin Matuska { "find_without_index", find_without_index }, 456716fd348SMartin Matuska { "drain_tree", drain_tree }, 457716fd348SMartin Matuska { "stress_tree", stress_tree }, 458716fd348SMartin Matuska { NULL, NULL } 459716fd348SMartin Matuska }; 460716fd348SMartin Matuska 461716fd348SMartin Matuska int 462716fd348SMartin Matuska main(int argc, char *argv[]) 463716fd348SMartin Matuska { 464716fd348SMartin Matuska char *negative_test = NULL; 465716fd348SMartin Matuska int failed_tests = 0; 466716fd348SMartin Matuska struct timeval tp; 467716fd348SMartin Matuska zfs_btree_t bt; 468716fd348SMartin Matuska int c; 469716fd348SMartin Matuska 470716fd348SMartin Matuska while ((c = getopt(argc, argv, "c:l:n:r:st:")) != -1) { 471716fd348SMartin Matuska switch (c) { 472716fd348SMartin Matuska case 'c': 473716fd348SMartin Matuska contents_frequency = atoi(optarg); 474716fd348SMartin Matuska break; 475716fd348SMartin Matuska case 'l': 476716fd348SMartin Matuska tree_limit = atoi(optarg); 477716fd348SMartin Matuska break; 478716fd348SMartin Matuska case 'n': 479716fd348SMartin Matuska negative_test = optarg; 480716fd348SMartin Matuska break; 481716fd348SMartin Matuska case 'r': 482716fd348SMartin Matuska seed = atoi(optarg); 483716fd348SMartin Matuska break; 484716fd348SMartin Matuska case 's': 485716fd348SMartin Matuska stress_only = B_TRUE; 486716fd348SMartin Matuska break; 487716fd348SMartin Matuska case 't': 488716fd348SMartin Matuska stress_timeout = atoi(optarg); 489716fd348SMartin Matuska break; 490716fd348SMartin Matuska case 'h': 491716fd348SMartin Matuska default: 492716fd348SMartin Matuska usage(1); 493716fd348SMartin Matuska break; 494716fd348SMartin Matuska } 495716fd348SMartin Matuska } 496716fd348SMartin Matuska 497716fd348SMartin Matuska if (seed == 0) { 498716fd348SMartin Matuska (void) gettimeofday(&tp, NULL); 499716fd348SMartin Matuska seed = tp.tv_sec; 500716fd348SMartin Matuska } 501716fd348SMartin Matuska srandom(seed); 502716fd348SMartin Matuska 503716fd348SMartin Matuska zfs_btree_init(); 504716fd348SMartin Matuska zfs_btree_create(&bt, zfs_btree_compare, sizeof (uint64_t)); 505716fd348SMartin Matuska 506716fd348SMartin Matuska /* 507716fd348SMartin Matuska * This runs the named negative test. None of them should 508716fd348SMartin Matuska * return, as they both cause crashes. 509716fd348SMartin Matuska */ 510716fd348SMartin Matuska if (negative_test) { 511716fd348SMartin Matuska return (do_negative_test(&bt, negative_test)); 512716fd348SMartin Matuska } 513716fd348SMartin Matuska 514716fd348SMartin Matuska fprintf(stderr, "Seed: %u\n", seed); 515716fd348SMartin Matuska 516716fd348SMartin Matuska /* 517716fd348SMartin Matuska * This is a stress test that does operations on a btree over the 518716fd348SMartin Matuska * requested timeout period, verifying them against identical 519716fd348SMartin Matuska * operations in an avl tree. 520716fd348SMartin Matuska */ 521716fd348SMartin Matuska if (stress_only != 0) { 522716fd348SMartin Matuska return (stress_tree(&bt, NULL)); 523716fd348SMartin Matuska } 524716fd348SMartin Matuska 525716fd348SMartin Matuska /* Do the positive tests */ 526716fd348SMartin Matuska btree_test_t *test = &test_table[0]; 527716fd348SMartin Matuska while (test->name) { 528716fd348SMartin Matuska int retval; 529716fd348SMartin Matuska char why[BUFSIZE] = {0}; 530716fd348SMartin Matuska zfs_btree_index_t *idx = NULL; 531716fd348SMartin Matuska 532716fd348SMartin Matuska (void) fprintf(stdout, "%-20s", test->name); 533716fd348SMartin Matuska retval = test->func(&bt, why); 534716fd348SMartin Matuska 535716fd348SMartin Matuska if (retval == 0) { 536716fd348SMartin Matuska (void) fprintf(stdout, "ok\n"); 537716fd348SMartin Matuska } else { 538716fd348SMartin Matuska (void) fprintf(stdout, "failed with %d\n", retval); 539716fd348SMartin Matuska if (strlen(why) != 0) 540716fd348SMartin Matuska (void) fprintf(stdout, "\t%s\n", why); 541716fd348SMartin Matuska why[0] = '\0'; 542716fd348SMartin Matuska failed_tests++; 543716fd348SMartin Matuska } 544716fd348SMartin Matuska 545716fd348SMartin Matuska /* Remove all the elements and re-verify the tree */ 546*dbd5678dSMartin Matuska while (zfs_btree_destroy_nodes(&bt, &idx) != NULL) 547716fd348SMartin Matuska ; 548716fd348SMartin Matuska zfs_btree_verify(&bt); 549716fd348SMartin Matuska 550716fd348SMartin Matuska test++; 551716fd348SMartin Matuska } 552716fd348SMartin Matuska 553716fd348SMartin Matuska zfs_btree_verify(&bt); 554716fd348SMartin Matuska zfs_btree_fini(); 555716fd348SMartin Matuska 556716fd348SMartin Matuska return (failed_tests); 557716fd348SMartin Matuska } 558