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