1 # $NetBSD: t_db.sh,v 1.9 2020/03/12 14:10:59 martin Exp $ 2 # 3 # Copyright (c) 2008 The NetBSD Foundation, Inc. 4 # All rights reserved. 5 # 6 # Redistribution and use in source and binary forms, with or without 7 # modification, are permitted provided that the following conditions 8 # are met: 9 # 1. Redistributions of source code must retain the above copyright 10 # notice, this list of conditions and the following disclaimer. 11 # 2. Redistributions in binary form must reproduce the above copyright 12 # notice, this list of conditions and the following disclaimer in the 13 # documentation and/or other materials provided with the distribution. 14 # 15 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 # POSSIBILITY OF SUCH DAMAGE. 26 # 27 28 prog_db() 29 { 30 echo $(atf_get_srcdir)/h_db 31 } 32 33 prog_lfsr() 34 { 35 echo $(atf_get_srcdir)/h_lfsr 36 } 37 38 dict() 39 { 40 if [ -f /usr/share/dict/words ]; then 41 echo /usr/share/dict/words 42 elif [ -f /usr/dict/words ]; then 43 echo /usr/dict/words 44 else 45 atf_fail "no dictionary found" 46 fi 47 } 48 49 SEVEN_SEVEN="abcdefg|abcdefg|abcdefg|abcdefg|abcdefg|abcdefg|abcdefg" 50 51 atf_test_case small_btree 52 small_btree_head() 53 { 54 atf_set "descr" \ 55 "Checks btree database using small keys and small data" \ 56 "pairs: takes the first hundred entries in the dictionary," \ 57 "and makes them be key/data pairs." 58 } 59 small_btree_body() 60 { 61 TMPDIR="$(pwd)/db_dir"; export TMPDIR 62 mkdir ${TMPDIR} 63 64 sed 200q $(dict) >exp 65 66 for i in `sed 200q $(dict)`; do 67 echo p 68 echo k$i 69 echo d$i 70 echo g 71 echo k$i 72 done >in 73 74 atf_check -o file:exp "$(prog_db)" btree in 75 } 76 77 atf_test_case small_hash 78 small_hash_head() 79 { 80 atf_set "descr" \ 81 "Checks hash database using small keys and small data" \ 82 "pairs: takes the first hundred entries in the dictionary," \ 83 "and makes them be key/data pairs." 84 } 85 small_hash_body() 86 { 87 TMPDIR="$(pwd)/db_dir"; export TMPDIR 88 mkdir ${TMPDIR} 89 90 sed 200q $(dict) >exp 91 92 for i in `sed 200q $(dict)`; do 93 echo p 94 echo k$i 95 echo d$i 96 echo g 97 echo k$i 98 done >in 99 100 atf_check -o file:exp "$(prog_db)" hash in 101 } 102 103 atf_test_case small_recno 104 small_recno_head() 105 { 106 atf_set "descr" \ 107 "Checks recno database using small keys and small data" \ 108 "pairs: takes the first hundred entries in the dictionary," \ 109 "and makes them be key/data pairs." 110 } 111 small_recno_body() 112 { 113 TMPDIR="$(pwd)/db_dir"; export TMPDIR 114 mkdir ${TMPDIR} 115 116 sed 200q $(dict) >exp 117 118 sed 200q $(dict) | 119 awk '{ 120 ++i; 121 printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i); 122 }' >in 123 124 atf_check -o file:exp "$(prog_db)" recno in 125 } 126 127 atf_test_case medium_btree 128 medium_btree_head() 129 { 130 atf_set "descr" \ 131 "Checks btree database using small keys and medium" \ 132 "data pairs: takes the first 200 entries in the" \ 133 "dictionary, and gives them each a medium size data entry." 134 } 135 medium_btree_body() 136 { 137 TMPDIR="$(pwd)/db_dir"; export TMPDIR 138 mkdir ${TMPDIR} 139 140 mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz 141 echo $mdata | 142 awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp 143 144 for i in $(sed 200q $(dict)); do 145 echo p 146 echo k$i 147 echo d$mdata 148 echo g 149 echo k$i 150 done >in 151 152 atf_check -o file:exp "$(prog_db)" btree in 153 } 154 155 atf_test_case medium_hash 156 medium_hash_head() 157 { 158 atf_set "descr" \ 159 "Checks hash database using small keys and medium" \ 160 "data pairs: takes the first 200 entries in the" \ 161 "dictionary, and gives them each a medium size data entry." 162 } 163 medium_hash_body() 164 { 165 TMPDIR="$(pwd)/db_dir"; export TMPDIR 166 mkdir ${TMPDIR} 167 168 mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz 169 echo $mdata | 170 awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp 171 172 for i in $(sed 200q $(dict)); do 173 echo p 174 echo k$i 175 echo d$mdata 176 echo g 177 echo k$i 178 done >in 179 180 atf_check -o file:exp "$(prog_db)" hash in 181 } 182 183 atf_test_case medium_recno 184 medium_recno_head() 185 { 186 atf_set "descr" \ 187 "Checks recno database using small keys and medium" \ 188 "data pairs: takes the first 200 entries in the" \ 189 "dictionary, and gives them each a medium size data entry." 190 } 191 medium_recno_body() 192 { 193 TMPDIR="$(pwd)/db_dir"; export TMPDIR 194 mkdir ${TMPDIR} 195 196 mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz 197 echo $mdata | 198 awk '{ for (i = 1; i < 201; ++i) print $0 }' >exp 199 200 echo $mdata | 201 awk '{ for (i = 1; i < 201; ++i) 202 printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i); 203 }' >in 204 205 atf_check -o file:exp "$(prog_db)" recno in 206 } 207 208 atf_test_case big_btree 209 big_btree_head() 210 { 211 atf_set "descr" \ 212 "Checks btree database using small keys and big data" \ 213 "pairs: inserts the programs in /bin with their paths" \ 214 "as their keys." 215 } 216 big_btree_body() 217 { 218 TMPDIR="$(pwd)/db_dir"; export TMPDIR 219 mkdir ${TMPDIR} 220 221 (find /bin -type f -print | xargs cat) >exp 222 223 for psize in 512 16384 65536; do 224 echo "checking page size: $psize" 225 226 for i in `find /bin -type f -print`; do 227 echo p 228 echo k$i 229 echo D$i 230 echo g 231 echo k$i 232 done >in 233 234 atf_check "$(prog_db)" -o out btree in 235 cmp -s exp out || atf_fail "test failed for page size: $psize" 236 done 237 } 238 239 atf_test_case big_hash 240 big_hash_head() 241 { 242 atf_set "descr" \ 243 "Checks hash database using small keys and big data" \ 244 "pairs: inserts the programs in /bin with their paths" \ 245 "as their keys." 246 } 247 big_hash_body() 248 { 249 TMPDIR="$(pwd)/db_dir"; export TMPDIR 250 mkdir ${TMPDIR} 251 252 (find /bin -type f -print | xargs cat) >exp 253 254 for i in `find /bin -type f -print`; do 255 echo p 256 echo k$i 257 echo D$i 258 echo g 259 echo k$i 260 done >in 261 262 atf_check "$(prog_db)" -o out hash in 263 cmp -s exp out || atf_fail "test failed" 264 } 265 266 atf_test_case big_recno 267 big_recno_head() 268 { 269 atf_set "descr" \ 270 "Checks recno database using small keys and big data" \ 271 "pairs: inserts the programs in /bin with their paths" \ 272 "as their keys." 273 } 274 big_recno_body() 275 { 276 TMPDIR="$(pwd)/db_dir"; export TMPDIR 277 mkdir ${TMPDIR} 278 279 (find /bin -type f -print | xargs cat) >exp 280 281 find /bin -type f -print | 282 awk '{ 283 ++i; 284 printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i); 285 }' >in 286 287 for psize in 512 16384 65536; do 288 echo "checking page size: $psize" 289 290 atf_check "$(prog_db)" -o out recno in 291 cmp -s exp out || atf_fail "test failed for page size: $psize" 292 done 293 } 294 295 atf_test_case random_recno 296 random_recno_head() 297 { 298 atf_set "descr" "Checks recno database using random entries" 299 } 300 random_recno_body() 301 { 302 TMPDIR="$(pwd)/db_dir"; export TMPDIR 303 mkdir ${TMPDIR} 304 305 echo $SEVEN_SEVEN | 306 awk '{ 307 for (i = 37; i <= 37 + 88 * 17; i += 17) { 308 if (i % 41) 309 s = substr($0, 1, i % 41); 310 else 311 s = substr($0, 1); 312 printf("input key %d: %s\n", i, s); 313 } 314 for (i = 1; i <= 15; ++i) { 315 if (i % 41) 316 s = substr($0, 1, i % 41); 317 else 318 s = substr($0, 1); 319 printf("input key %d: %s\n", i, s); 320 } 321 for (i = 19234; i <= 19234 + 61 * 27; i += 27) { 322 if (i % 41) 323 s = substr($0, 1, i % 41); 324 else 325 s = substr($0, 1); 326 printf("input key %d: %s\n", i, s); 327 } 328 exit 329 }' >exp 330 331 cat exp | 332 awk 'BEGIN { 333 i = 37; 334 incr = 17; 335 } 336 { 337 printf("p\nk%d\nd%s\n", i, $0); 338 if (i == 19234 + 61 * 27) 339 exit; 340 if (i == 37 + 88 * 17) { 341 i = 1; 342 incr = 1; 343 } else if (i == 15) { 344 i = 19234; 345 incr = 27; 346 } else 347 i += incr; 348 } 349 END { 350 for (i = 37; i <= 37 + 88 * 17; i += 17) 351 printf("g\nk%d\n", i); 352 for (i = 1; i <= 15; ++i) 353 printf("g\nk%d\n", i); 354 for (i = 19234; i <= 19234 + 61 * 27; i += 27) 355 printf("g\nk%d\n", i); 356 }' >in 357 358 atf_check -o file:exp "$(prog_db)" recno in 359 } 360 361 atf_test_case reverse_recno 362 reverse_recno_head() 363 { 364 atf_set "descr" "Checks recno database using reverse order entries" 365 } 366 reverse_recno_body() 367 { 368 TMPDIR="$(pwd)/db_dir"; export TMPDIR 369 mkdir ${TMPDIR} 370 371 echo $SEVEN_SEVEN | 372 awk ' { 373 for (i = 1500; i; --i) { 374 if (i % 34) 375 s = substr($0, 1, i % 34); 376 else 377 s = substr($0, 1); 378 printf("input key %d: %s\n", i, s); 379 } 380 exit; 381 }' >exp 382 383 cat exp | 384 awk 'BEGIN { 385 i = 1500; 386 } 387 { 388 printf("p\nk%d\nd%s\n", i, $0); 389 --i; 390 } 391 END { 392 for (i = 1500; i; --i) 393 printf("g\nk%d\n", i); 394 }' >in 395 396 atf_check -o file:exp "$(prog_db)" recno in 397 } 398 399 atf_test_case alternate_recno 400 alternate_recno_head() 401 { 402 atf_set "descr" "Checks recno database using alternating order entries" 403 } 404 alternate_recno_body() 405 { 406 TMPDIR="$(pwd)/db_dir"; export TMPDIR 407 mkdir ${TMPDIR} 408 409 echo $SEVEN_SEVEN | 410 awk ' { 411 for (i = 1; i < 1200; i += 2) { 412 if (i % 34) 413 s = substr($0, 1, i % 34); 414 else 415 s = substr($0, 1); 416 printf("input key %d: %s\n", i, s); 417 } 418 for (i = 2; i < 1200; i += 2) { 419 if (i % 34) 420 s = substr($0, 1, i % 34); 421 else 422 s = substr($0, 1); 423 printf("input key %d: %s\n", i, s); 424 } 425 exit; 426 }' >exp 427 428 cat exp | 429 awk 'BEGIN { 430 i = 1; 431 even = 0; 432 } 433 { 434 printf("p\nk%d\nd%s\n", i, $0); 435 i += 2; 436 if (i >= 1200) { 437 if (even == 1) 438 exit; 439 even = 1; 440 i = 2; 441 } 442 } 443 END { 444 for (i = 1; i < 1200; ++i) 445 printf("g\nk%d\n", i); 446 }' >in 447 448 atf_check "$(prog_db)" -o out recno in 449 450 sort -o exp exp 451 sort -o out out 452 453 cmp -s exp out || atf_fail "test failed" 454 } 455 456 h_delete() 457 { 458 TMPDIR="$(pwd)/db_dir"; export TMPDIR 459 mkdir ${TMPDIR} 460 461 type=$1 462 463 echo $SEVEN_SEVEN | 464 awk '{ 465 for (i = 1; i <= 120; ++i) 466 printf("%05d: input key %d: %s\n", i, i, $0); 467 }' >exp 468 469 cat exp | 470 awk '{ 471 printf("p\nk%d\nd%s\n", ++i, $0); 472 } 473 END { 474 printf("fR_NEXT\n"); 475 for (i = 1; i <= 120; ++i) 476 printf("s\n"); 477 printf("fR_CURSOR\ns\nkXX\n"); 478 printf("r\n"); 479 printf("fR_NEXT\ns\n"); 480 printf("fR_CURSOR\ns\nk1\n"); 481 printf("r\n"); 482 printf("fR_FIRST\ns\n"); 483 }' >in 484 485 # For btree, the records are ordered by the string representation 486 # of the key value. So sort the expected output file accordingly, 487 # and set the seek_last key to the last expected key value. 488 489 if [ "$type" = "btree" ] ; then 490 sed -e 's/kXX/k99/' < in > tmp 491 mv tmp in 492 sort -d -k4 < exp > tmp 493 mv tmp exp 494 echo $SEVEN_SEVEN | 495 awk '{ 496 printf("%05d: input key %d: %s\n", 99, 99, $0); 497 printf("seq failed, no such key\n"); 498 printf("%05d: input key %d: %s\n", 1, 1, $0); 499 printf("%05d: input key %d: %s\n", 10, 10, $0); 500 exit; 501 }' >> exp 502 else 503 # For recno, records are ordered by numerical key value. No sort 504 # is needed, but still need to set proper seek_last key value. 505 sed -e 's/kXX/k120/' < in > tmp 506 mv tmp in 507 echo $SEVEN_SEVEN | 508 awk '{ 509 printf("%05d: input key %d: %s\n", 120, 120, $0); 510 printf("seq failed, no such key\n"); 511 printf("%05d: input key %d: %s\n", 1, 1, $0); 512 printf("%05d: input key %d: %s\n", 2, 2, $0); 513 exit; 514 }' >> exp 515 fi 516 517 atf_check "$(prog_db)" -o out $type in 518 atf_check -o file:exp cat out 519 } 520 521 atf_test_case delete_btree 522 delete_btree_head() 523 { 524 atf_set "descr" "Checks removing records in btree database" 525 } 526 delete_btree_body() 527 { 528 h_delete btree 529 } 530 531 atf_test_case delete_recno 532 delete_recno_head() 533 { 534 atf_set "descr" "Checks removing records in recno database" 535 } 536 delete_recno_body() 537 { 538 h_delete recno 539 } 540 541 h_repeated() 542 { 543 local type="$1" 544 TMPDIR="$(pwd)/db_dir"; export TMPDIR 545 mkdir ${TMPDIR} 546 547 echo "" | 548 awk 'BEGIN { 549 for (i = 1; i <= 10; ++i) { 550 printf("p\nkkey1\nD/bin/sh\n"); 551 printf("p\nkkey2\nD/bin/csh\n"); 552 if (i % 8 == 0) { 553 printf("c\nkkey2\nD/bin/csh\n"); 554 printf("c\nkkey1\nD/bin/sh\n"); 555 printf("e\t%d of 10 (comparison)\n", i); 556 } else 557 printf("e\t%d of 10 \n", i); 558 printf("r\nkkey1\nr\nkkey2\n"); 559 } 560 }' >in 561 562 $(prog_db) $type in 563 } 564 565 atf_test_case repeated_btree 566 repeated_btree_head() 567 { 568 atf_set "descr" \ 569 "Checks btree database with repeated small keys and" \ 570 "big data pairs. Makes sure that overflow pages are reused" 571 } 572 repeated_btree_body() 573 { 574 h_repeated btree 575 } 576 577 atf_test_case repeated_hash 578 repeated_hash_head() 579 { 580 atf_set "descr" \ 581 "Checks hash database with repeated small keys and" \ 582 "big data pairs. Makes sure that overflow pages are reused" 583 } 584 repeated_hash_body() 585 { 586 h_repeated hash 587 } 588 589 atf_test_case duplicate_btree 590 duplicate_btree_head() 591 { 592 atf_set "descr" "Checks btree database with duplicate keys" 593 } 594 duplicate_btree_body() 595 { 596 TMPDIR="$(pwd)/db_dir"; export TMPDIR 597 mkdir ${TMPDIR} 598 599 echo $SEVEN_SEVEN | 600 awk '{ 601 for (i = 1; i <= 543; ++i) 602 printf("%05d: input key %d: %s\n", i, i, $0); 603 exit; 604 }' >exp 605 606 cat exp | 607 awk '{ 608 if (i++ % 2) 609 printf("p\nkduplicatekey\nd%s\n", $0); 610 else 611 printf("p\nkunique%dkey\nd%s\n", i, $0); 612 } 613 END { 614 printf("o\n"); 615 }' >in 616 617 atf_check -o file:exp -x "$(prog_db) -iflags=1 btree in | sort" 618 } 619 620 h_cursor_flags() 621 { 622 local type=$1 623 TMPDIR="$(pwd)/db_dir"; export TMPDIR 624 mkdir ${TMPDIR} 625 626 echo $SEVEN_SEVEN | 627 awk '{ 628 for (i = 1; i <= 20; ++i) 629 printf("%05d: input key %d: %s\n", i, i, $0); 630 exit; 631 }' >exp 632 633 # Test that R_CURSOR doesn't succeed before cursor initialized 634 cat exp | 635 awk '{ 636 if (i == 10) 637 exit; 638 printf("p\nk%d\nd%s\n", ++i, $0); 639 } 640 END { 641 printf("fR_CURSOR\nr\n"); 642 printf("eR_CURSOR SHOULD HAVE FAILED\n"); 643 }' >in 644 645 atf_check -o ignore -e ignore -s ne:0 "$(prog_db)" -o out $type in 646 atf_check -s ne:0 test -s out 647 648 cat exp | 649 awk '{ 650 if (i == 10) 651 exit; 652 printf("p\nk%d\nd%s\n", ++i, $0); 653 } 654 END { 655 printf("fR_CURSOR\np\nk1\ndsome data\n"); 656 printf("eR_CURSOR SHOULD HAVE FAILED\n"); 657 }' >in 658 659 atf_check -o ignore -e ignore -s ne:0 "$(prog_db)" -o out $type in 660 atf_check -s ne:0 test -s out 661 } 662 663 atf_test_case cursor_flags_btree 664 cursor_flags_btree_head() 665 { 666 atf_set "descr" \ 667 "Checks use of cursor flags without initialization in btree database" 668 } 669 cursor_flags_btree_body() 670 { 671 h_cursor_flags btree 672 } 673 674 atf_test_case cursor_flags_recno 675 cursor_flags_recno_head() 676 { 677 atf_set "descr" \ 678 "Checks use of cursor flags without initialization in recno database" 679 } 680 cursor_flags_recno_body() 681 { 682 h_cursor_flags recno 683 } 684 685 atf_test_case reverse_order_recno 686 reverse_order_recno_head() 687 { 688 atf_set "descr" "Checks reverse order inserts in recno database" 689 } 690 reverse_order_recno_body() 691 { 692 TMPDIR="$(pwd)/db_dir"; export TMPDIR 693 mkdir ${TMPDIR} 694 695 echo $SEVEN_SEVEN | 696 awk '{ 697 for (i = 1; i <= 779; ++i) 698 printf("%05d: input key %d: %s\n", i, i, $0); 699 exit; 700 }' >exp 701 702 cat exp | 703 awk '{ 704 if (i == 0) { 705 i = 1; 706 printf("p\nk1\nd%s\n", $0); 707 printf("%s\n", "fR_IBEFORE"); 708 } else 709 printf("p\nk1\nd%s\n", $0); 710 } 711 END { 712 printf("or\n"); 713 }' >in 714 715 atf_check -o file:exp "$(prog_db)" recno in 716 } 717 718 atf_test_case small_page_btree 719 small_page_btree_head() 720 { 721 atf_set "descr" \ 722 "Checks btree database with lots of keys and small page" \ 723 "size: takes the first 20000 entries in the dictionary," \ 724 "reverses them, and gives them each a small size data" \ 725 "entry. Uses a small page size to make sure the btree" \ 726 "split code gets hammered." 727 } 728 small_page_btree_body() 729 { 730 TMPDIR="$(pwd)/db_dir"; export TMPDIR 731 mkdir ${TMPDIR} 732 733 mdata=abcdefghijklmnopqrstuvwxy 734 echo $mdata | 735 awk '{ for (i = 1; i < 20001; ++i) print $0 }' >exp 736 737 for i in `sed 20000q $(dict) | rev`; do 738 echo p 739 echo k$i 740 echo d$mdata 741 echo g 742 echo k$i 743 done >in 744 745 atf_check -o file:exp "$(prog_db)" -i psize=512 btree in 746 } 747 748 h_byte_orders() 749 { 750 TMPDIR="$(pwd)/db_dir"; export TMPDIR 751 mkdir ${TMPDIR} 752 753 type=$1 754 755 sed 50q $(dict) >exp 756 for order in 1234 4321; do 757 for i in `sed 50q $(dict)`; do 758 echo p 759 echo k$i 760 echo d$i 761 echo S 762 echo g 763 echo k$i 764 done >in 765 766 atf_check -o file:exp "$(prog_db)" -ilorder=$order -f byte.file $type in 767 768 for i in `sed 50q $(dict)`; do 769 echo g 770 echo k$i 771 done >in 772 773 atf_check -o file:exp "$(prog_db)" -s -ilorder=$order -f byte.file $type in 774 done 775 } 776 777 atf_test_case byte_orders_btree 778 byte_orders_btree_head() 779 { 780 atf_set "descr" "Checks btree database using differing byte orders" 781 } 782 byte_orders_btree_body() 783 { 784 h_byte_orders btree 785 } 786 787 atf_test_case byte_orders_hash 788 byte_orders_hash_head() 789 { 790 atf_set "descr" "Checks hash database using differing byte orders" 791 } 792 byte_orders_hash_body() 793 { 794 h_byte_orders hash 795 } 796 797 h_bsize_ffactor() 798 { 799 bsize=$1 800 ffactor=$2 801 802 echo "bucketsize $bsize, fill factor $ffactor" 803 atf_check -o file:exp "$(prog_db)" "-ibsize=$bsize,\ 804 ffactor=$ffactor,nelem=25000,cachesize=65536" hash in 805 } 806 807 atf_test_case bsize_ffactor 808 bsize_ffactor_head() 809 { 810 atf_set "timeout" "1800" 811 atf_set "descr" "Checks hash database with various" \ 812 "bucketsizes and fill factors" 813 } 814 bsize_ffactor_body() 815 { 816 TMPDIR="$(pwd)/db_dir"; export TMPDIR 817 mkdir ${TMPDIR} 818 819 echo $SEVEN_SEVEN | 820 awk '{ 821 for (i = 1; i <= 10000; ++i) { 822 if (i % 34) 823 s = substr($0, 1, i % 34); 824 else 825 s = substr($0, 1); 826 printf("%s\n", s); 827 } 828 exit; 829 830 }' >exp 831 832 sed 10000q $(dict) | 833 awk 'BEGIN { 834 ds="'$SEVEN_SEVEN'" 835 } 836 { 837 if (++i % 34) 838 s = substr(ds, 1, i % 34); 839 else 840 s = substr(ds, 1); 841 printf("p\nk%s\nd%s\n", $0, s); 842 }' >in 843 844 sed 10000q $(dict) | 845 awk '{ 846 ++i; 847 printf("g\nk%s\n", $0); 848 }' >>in 849 850 h_bsize_ffactor 256 11 851 h_bsize_ffactor 256 14 852 h_bsize_ffactor 256 21 853 854 h_bsize_ffactor 512 21 855 h_bsize_ffactor 512 28 856 h_bsize_ffactor 512 43 857 858 h_bsize_ffactor 1024 43 859 h_bsize_ffactor 1024 57 860 h_bsize_ffactor 1024 85 861 862 h_bsize_ffactor 2048 85 863 h_bsize_ffactor 2048 114 864 h_bsize_ffactor 2048 171 865 866 h_bsize_ffactor 4096 171 867 h_bsize_ffactor 4096 228 868 h_bsize_ffactor 4096 341 869 870 h_bsize_ffactor 8192 341 871 h_bsize_ffactor 8192 455 872 h_bsize_ffactor 8192 683 873 874 h_bsize_ffactor 16384 341 875 h_bsize_ffactor 16384 455 876 h_bsize_ffactor 16384 683 877 878 h_bsize_ffactor 32768 341 879 h_bsize_ffactor 32768 455 880 h_bsize_ffactor 32768 683 881 882 h_bsize_ffactor 65536 341 883 h_bsize_ffactor 65536 455 884 h_bsize_ffactor 65536 683 885 } 886 887 # This tests 64K block size addition/removal 888 atf_test_case four_char_hash 889 four_char_hash_head() 890 { 891 atf_set "descr" \ 892 "Checks hash database with 4 char key and" \ 893 "value insert on a 65536 bucket size" 894 } 895 four_char_hash_body() 896 { 897 TMPDIR="$(pwd)/db_dir"; export TMPDIR 898 mkdir ${TMPDIR} 899 900 cat >in <<EOF 901 p 902 k1234 903 d1234 904 r 905 k1234 906 EOF 907 908 atf_check "$(prog_db)" -i bsize=65536 hash in 909 } 910 911 912 atf_test_case bsize_torture 913 bsize_torture_head() 914 { 915 atf_set "timeout" "36000" 916 atf_set "descr" "Checks hash database with various bucket sizes" 917 } 918 bsize_torture_body() 919 { 920 TMPDIR="$(pwd)/db_dir"; export TMPDIR 921 mkdir ${TMPDIR} 922 AVAIL=$( df -m ${TMPDIR} | awk '{if (int($4) > 0) print $4}' ) 923 LIST="2048 4096 8192 16384" 924 if [ $AVAIL -gt 30 ]; then 925 LIST="$LIST 32768" 926 fi 927 if [ $AVAIL -gt 60 ]; then 928 LIST="$LIST 65536" 929 fi 930 for i in $LIST 931 do 932 atf_check "$(prog_lfsr)" $i 933 done 934 } 935 936 atf_test_case btree_weird_page_split 937 btree_weird_page_split_head() 938 { 939 atf_set "descr" \ 940 "Test for a weird page split condition where an insertion " \ 941 "into index 0 of a page that would cause the new item to " \ 942 "be the only item on the left page results in index 0 of " \ 943 "the right page being erroneously skipped; this only " \ 944 "happens with one particular key+data length for each page size." 945 atf_set "timeout" "900" 946 } 947 btree_weird_page_split_body() 948 { 949 for psize in 512 1024 2048 4096 8192; do 950 echo " page size $psize" 951 kdsizes=`awk 'BEGIN { 952 psize = '$psize'; hsize = int(psize/2); 953 for (kdsize = hsize-40; kdsize <= hsize; kdsize++) { 954 print kdsize; 955 } 956 }' /dev/null` 957 958 # Use a series of keylen+datalen values in the right 959 # neighborhood to find the one that triggers the bug. 960 # We could compute the exact size that triggers the 961 # bug but this additional fuzz may be useful. 962 963 # Insert keys in reverse order to maximize the chances 964 # for a split on index 0. 965 966 for kdsize in $kdsizes; do 967 awk 'BEGIN { 968 kdsize = '$kdsize'; 969 for (i = 8; i-- > 0; ) { 970 s = sprintf("a%03d:%09d", i, kdsize); 971 for (j = 0; j < kdsize-20; j++) { 972 s = s "x"; 973 } 974 printf("p\nka%03d\nd%s\n", i, s); 975 } 976 print "o"; 977 }' /dev/null > in 978 sed -n 's/^d//p' in | sort > exp 979 atf_check -o file:exp \ 980 "$(prog_db)" -i psize=$psize btree in 981 done 982 done 983 } 984 985 # Extremely tricky test attempting to replicate some unusual database 986 # corruption seen in the field: pieces of the database becoming 987 # inaccessible to random access, sequential access, or both. The 988 # hypothesis is that at least some of these are triggered by the bug 989 # in page splits on index 0 with a particular exact keylen+datalen. 990 # (See Test 40.) For psize=4096, this size is exactly 2024. 991 992 # The order of operations here relies on very specific knowledge of 993 # the internals of the btree access method in order to place records 994 # at specific offsets in a page and to create certain keys on internal 995 # pages. The to-be-split page immediately prior to the bug-triggering 996 # split has the following properties: 997 # 998 # * is not the leftmost leaf page 999 # * key on the parent page is compares less than the key of the item 1000 # on index 0 1001 # * triggering record's key also compares greater than the key on the 1002 # parent page 1003 1004 # Additionally, we prime the mpool LRU chain so that the head page on 1005 # the chain has the following properties: 1006 # 1007 # * record at index 0 is located where it will not get overwritten by 1008 # items written to the right-hand page during the split 1009 # * key of the record at index 0 compares less than the key of the 1010 # bug-triggering record 1011 1012 # If the page-split bug exists, this test appears to create a database 1013 # where some records are inaccessible to a search, but still remain in 1014 # the file and are accessible by sequential traversal. At least one 1015 # record gets duplicated out of sequence. 1016 1017 atf_test_case btree_tricky_page_split 1018 btree_tricky_page_split_head() 1019 { 1020 atf_set "descr" \ 1021 "btree: no unsearchables due to page split on index 0" 1022 } 1023 btree_tricky_page_split_body() 1024 { 1025 list=`(for i in a b c d; do 1026 for j in 990 998 999; do 1027 echo g ${i}${j} 1024 1028 done 1029 done; 1030 echo g y997 2014 1031 for i in y z; do 1032 for j in 998 999; do 1033 echo g ${i}${j} 1024 1034 done 1035 done)` 1036 # Exact number for trigger condition accounts for newlines 1037 # retained by dbtest with -ofile but not without; we use 1038 # -ofile, so count newlines. keylen=5,datalen=5+2014 for 1039 # psize=4096 here. 1040 (cat - <<EOF 1041 p z999 1024 1042 p z998 1024 1043 p y999 1024 1044 p y990 1024 1045 p d999 1024 1046 p d990 1024 1047 p c999 1024 1048 p c990 1024 1049 p b999 1024 1050 p b990 1024 1051 p a999 1024 1052 p a990 1024 1053 p y998 1024 1054 r y990 1055 p d998 1024 1056 p d990 1024 1057 p c998 1024 1058 p c990 1024 1059 p b998 1024 1060 p b990 1024 1061 p a998 1024 1062 p a990 1024 1063 p y997 2014 1064 S 1065 o 1066 EOF 1067 echo "$list") | 1068 # awk script input: 1069 # {p|g|r} key [datasize] 1070 awk '/^[pgr]/{ 1071 printf("%s\nk%s\n", $1, $2); 1072 } 1073 /^p/{ 1074 s = $2; 1075 for (i = 0; i < $3; i++) { 1076 s = s "x"; 1077 } 1078 printf("d%s\n", s); 1079 } 1080 !/^[pgr]/{ 1081 print $0; 1082 }' > in 1083 (echo "$list"; echo "$list") | awk '{ 1084 s = $2; 1085 for (i = 0; i < $3; i++) { 1086 s = s "x"; 1087 } 1088 print s; 1089 }' > exp 1090 atf_check -o file:exp \ 1091 "$(prog_db)" -i psize=4096 btree in 1092 } 1093 1094 atf_test_case btree_recursive_traversal 1095 btree_recursive_traversal_head() 1096 { 1097 atf_set "descr" \ 1098 "btree: Test for recursive traversal successfully " \ 1099 "retrieving records that are inaccessible to normal " \ 1100 "sequential 'sibling-link' traversal. This works by " \ 1101 "unlinking a few leaf pages but leaving their parent " \ 1102 "links intact. To verify that the unlink actually makes " \ 1103 "records inaccessible, the test first uses 'o' to do a " \ 1104 "normal sequential traversal, followed by 'O' to do a " \ 1105 "recursive traversal." 1106 } 1107 btree_recursive_traversal_body() 1108 { 1109 fill="abcdefghijklmnopqrstuvwxyzy" 1110 script='{ 1111 for (i = 0; i < 20000; i++) { 1112 printf("p\nkAA%05d\nd%05d%s\n", i, i, $0); 1113 } 1114 print "u"; 1115 print "u"; 1116 print "u"; 1117 print "u"; 1118 }' 1119 (echo $fill | awk "$script"; echo o) > in1 1120 echo $fill | 1121 awk '{ 1122 for (i = 0; i < 20000; i++) { 1123 if (i >= 5 && i <= 40) 1124 continue; 1125 printf("%05d%s\n", i, $0); 1126 } 1127 }' > exp1 1128 atf_check -o file:exp1 \ 1129 "$(prog_db)" -i psize=512 btree in1 1130 echo $fill | 1131 awk '{ 1132 for (i = 0; i < 20000; i++) { 1133 printf("%05d%s\n", i, $0); 1134 } 1135 }' > exp2 1136 (echo $fill | awk "$script"; echo O) > in2 1137 atf_check -o file:exp2 \ 1138 "$(prog_db)" -i psize=512 btree in2 1139 } 1140 1141 atf_test_case btree_byteswap_unaligned_access_bksd 1142 btree_byteswap_unaligned_access_bksd_head() 1143 { 1144 atf_set "descr" \ 1145 "btree: big key, small data, byteswap unaligned access" 1146 } 1147 btree_byteswap_unaligned_access_bksd_body() 1148 { 1149 (echo foo; echo bar) | 1150 awk '{ 1151 s = $0 1152 for (i = 0; i < 488; i++) { 1153 s = s "x"; 1154 } 1155 printf("p\nk%s\ndx\n", s); 1156 }' > in 1157 for order in 1234 4321; do 1158 atf_check \ 1159 "$(prog_db)" -o out -i psize=512,lorder=$order btree in 1160 done 1161 } 1162 1163 atf_test_case btree_byteswap_unaligned_access_skbd 1164 btree_byteswap_unaligned_access_skbd_head() 1165 { 1166 atf_set "descr" \ 1167 "btree: small key, big data, byteswap unaligned access" 1168 } 1169 btree_byteswap_unaligned_access_skbd_body() 1170 { 1171 # 484 = 512 - 20 (header) - 7 ("foo1234") - 1 (newline) 1172 (echo foo1234; echo bar1234) | 1173 awk '{ 1174 s = $0 1175 for (i = 0; i < 484; i++) { 1176 s = s "x"; 1177 } 1178 printf("p\nk%s\nd%s\n", $0, s); 1179 }' > in 1180 for order in 1234 4321; do 1181 atf_check \ 1182 "$(prog_db)" -o out -i psize=512,lorder=$order btree in 1183 done 1184 } 1185 1186 atf_test_case btree_known_byte_order 1187 btree_known_byte_order_head() 1188 { 1189 atf_set "descr" \ 1190 "btree: small key, big data, known byte order" 1191 } 1192 btree_known_byte_order_body() 1193 { 1194 local a="-i psize=512,lorder=" 1195 1196 (echo foo1234; echo bar1234) | 1197 awk '{ 1198 s = $0 1199 for (i = 0; i < 484; i++) { 1200 s = s "x"; 1201 } 1202 printf("%s\n", s); 1203 }' > exp 1204 (echo foo1234; echo bar1234) | 1205 awk '{ 1206 s = $0 1207 for (i = 0; i < 484; i++) { 1208 s = s "x"; 1209 } 1210 printf("p\nk%s\nd%s\n", $0, s); 1211 }' > in1 1212 for order in 1234 4321; do 1213 atf_check \ 1214 "$(prog_db)" -f out.$order $a$order btree in1 1215 done 1216 (echo g; echo kfoo1234; echo g; echo kbar1234) > in2 1217 for order in 1234 4321; do 1218 atf_check -o file:exp \ 1219 "$(prog_db)" -s -f out.$order $a$order btree in2 1220 done 1221 } 1222 1223 atf_init_test_cases() 1224 { 1225 atf_add_test_case small_btree 1226 atf_add_test_case small_hash 1227 atf_add_test_case small_recno 1228 atf_add_test_case medium_btree 1229 atf_add_test_case medium_hash 1230 atf_add_test_case medium_recno 1231 atf_add_test_case big_btree 1232 atf_add_test_case big_hash 1233 atf_add_test_case big_recno 1234 atf_add_test_case random_recno 1235 atf_add_test_case reverse_recno 1236 atf_add_test_case alternate_recno 1237 atf_add_test_case delete_btree 1238 atf_add_test_case delete_recno 1239 atf_add_test_case repeated_btree 1240 atf_add_test_case repeated_hash 1241 atf_add_test_case duplicate_btree 1242 atf_add_test_case cursor_flags_btree 1243 atf_add_test_case cursor_flags_recno 1244 atf_add_test_case reverse_order_recno 1245 atf_add_test_case small_page_btree 1246 atf_add_test_case byte_orders_btree 1247 atf_add_test_case byte_orders_hash 1248 atf_add_test_case bsize_ffactor 1249 atf_add_test_case four_char_hash 1250 atf_add_test_case bsize_torture 1251 atf_add_test_case btree_weird_page_split 1252 atf_add_test_case btree_tricky_page_split 1253 atf_add_test_case btree_recursive_traversal 1254 atf_add_test_case btree_byteswap_unaligned_access_bksd 1255 atf_add_test_case btree_byteswap_unaligned_access_skbd 1256 atf_add_test_case btree_known_byte_order 1257 } 1258