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