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