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