summaryrefslogtreecommitdiffstats
path: root/contrib/netbsd-tests/lib/libc/db/t_db.sh
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/netbsd-tests/lib/libc/db/t_db.sh')
-rwxr-xr-xcontrib/netbsd-tests/lib/libc/db/t_db.sh442
1 files changed, 406 insertions, 36 deletions
diff --git a/contrib/netbsd-tests/lib/libc/db/t_db.sh b/contrib/netbsd-tests/lib/libc/db/t_db.sh
index d256508..6858e36 100755
--- a/contrib/netbsd-tests/lib/libc/db/t_db.sh
+++ b/contrib/netbsd-tests/lib/libc/db/t_db.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_db.sh,v 1.4 2013/07/29 10:43:15 skrll Exp $
+# $NetBSD: t_db.sh,v 1.7 2016/09/24 20:12:33 christos Exp $
#
# Copyright (c) 2008 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -25,11 +25,16 @@
# POSSIBILITY OF SUCH DAMAGE.
#
-prog()
+prog_db()
{
echo $(atf_get_srcdir)/h_db
}
+prog_lfsr()
+{
+ echo $(atf_get_srcdir)/h_lfsr
+}
+
dict()
{
if [ -f /usr/share/dict/words ]; then
@@ -37,6 +42,7 @@ dict()
elif [ -f /usr/dict/words ]; then
echo /usr/dict/words
else
+ echo ""
atf_fail "no dictionary found"
fi
}
@@ -44,12 +50,7 @@ dict()
# Begin FreeBSD
dict()
{
- if [ -f /usr/share/dict/words ]; then
- echo /usr/share/dict/words
- else
- echo /nonexistent
- atf_skip "Test requires dict/words"
- fi
+ echo /usr/share/dict/words
}
# End FreeBSD
@@ -62,6 +63,9 @@ small_btree_head()
"Checks btree database using small keys and small data" \
"pairs: takes the first hundred entries in the dictionary," \
"and makes them be key/data pairs."
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
small_btree_body()
{
@@ -78,7 +82,7 @@ small_btree_body()
echo k$i
done >in
- atf_check -o file:exp "$(prog)" btree in
+ atf_check -o file:exp "$(prog_db)" btree in
}
atf_test_case small_hash
@@ -88,6 +92,9 @@ small_hash_head()
"Checks hash database using small keys and small data" \
"pairs: takes the first hundred entries in the dictionary," \
"and makes them be key/data pairs."
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
small_hash_body()
{
@@ -104,7 +111,7 @@ small_hash_body()
echo k$i
done >in
- atf_check -o file:exp "$(prog)" hash in
+ atf_check -o file:exp "$(prog_db)" hash in
}
atf_test_case small_recno
@@ -114,6 +121,9 @@ small_recno_head()
"Checks recno database using small keys and small data" \
"pairs: takes the first hundred entries in the dictionary," \
"and makes them be key/data pairs."
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
small_recno_body()
{
@@ -128,7 +138,7 @@ small_recno_body()
printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
}' >in
- atf_check -o file:exp "$(prog)" recno in
+ atf_check -o file:exp "$(prog_db)" recno in
}
atf_test_case medium_btree
@@ -138,6 +148,9 @@ medium_btree_head()
"Checks btree database using small keys and medium" \
"data pairs: takes the first 200 entries in the" \
"dictionary, and gives them each a medium size data entry."
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
medium_btree_body()
{
@@ -156,7 +169,7 @@ medium_btree_body()
echo k$i
done >in
- atf_check -o file:exp "$(prog)" btree in
+ atf_check -o file:exp "$(prog_db)" btree in
}
atf_test_case medium_hash
@@ -166,6 +179,9 @@ medium_hash_head()
"Checks hash database using small keys and medium" \
"data pairs: takes the first 200 entries in the" \
"dictionary, and gives them each a medium size data entry."
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
medium_hash_body()
{
@@ -184,7 +200,7 @@ medium_hash_body()
echo k$i
done >in
- atf_check -o file:exp "$(prog)" hash in
+ atf_check -o file:exp "$(prog_db)" hash in
}
atf_test_case medium_recno
@@ -209,7 +225,7 @@ medium_recno_body()
printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
}' >in
- atf_check -o file:exp "$(prog)" recno in
+ atf_check -o file:exp "$(prog_db)" recno in
}
atf_test_case big_btree
@@ -238,7 +254,7 @@ big_btree_body()
echo k$i
done >in
- atf_check "$(prog)" -o out btree in
+ atf_check "$(prog_db)" -o out btree in
cmp -s exp out || atf_fail "test failed for page size: $psize"
done
}
@@ -266,7 +282,7 @@ big_hash_body()
echo k$i
done >in
- atf_check "$(prog)" -o out hash in
+ atf_check "$(prog_db)" -o out hash in
cmp -s exp out || atf_fail "test failed"
}
@@ -294,7 +310,7 @@ big_recno_body()
for psize in 512 16384 65536; do
echo "checking page size: $psize"
- atf_check "$(prog)" -o out recno in
+ atf_check "$(prog_db)" -o out recno in
cmp -s exp out || atf_fail "test failed for page size: $psize"
done
}
@@ -362,7 +378,7 @@ random_recno_body()
printf("g\nk%d\n", i);
}' >in
- atf_check -o file:exp "$(prog)" recno in
+ atf_check -o file:exp "$(prog_db)" recno in
}
atf_test_case reverse_recno
@@ -400,7 +416,7 @@ reverse_recno_body()
printf("g\nk%d\n", i);
}' >in
- atf_check -o file:exp "$(prog)" recno in
+ atf_check -o file:exp "$(prog_db)" recno in
}
atf_test_case alternate_recno
@@ -452,7 +468,7 @@ alternate_recno_body()
printf("g\nk%d\n", i);
}' >in
- atf_check "$(prog)" -o out recno in
+ atf_check "$(prog_db)" -o out recno in
sort -o exp exp
sort -o out out
@@ -521,7 +537,7 @@ h_delete()
}' >> exp
fi
- atf_check "$(prog)" -o out $type in
+ atf_check "$(prog_db)" -o out $type in
atf_check -o file:exp cat out
}
@@ -547,6 +563,7 @@ delete_recno_body()
h_repeated()
{
+ local type="$1"
TMPDIR="$(pwd)/db_dir"; export TMPDIR
mkdir ${TMPDIR}
@@ -565,7 +582,7 @@ h_repeated()
}
}' >in
- $(prog) btree in
+ $(prog_db) $type in
}
atf_test_case repeated_btree
@@ -620,16 +637,15 @@ duplicate_btree_body()
printf("o\n");
}' >in
- atf_check -o file:exp -x "$(prog) -iflags=1 btree in | sort"
+ atf_check -o file:exp -x "$(prog_db) -iflags=1 btree in | sort"
}
h_cursor_flags()
{
+ local type=$1
TMPDIR="$(pwd)/db_dir"; export TMPDIR
mkdir ${TMPDIR}
- type=$1
-
echo $SEVEN_SEVEN |
awk '{
for (i = 1; i <= 20; ++i)
@@ -649,7 +665,7 @@ h_cursor_flags()
printf("eR_CURSOR SHOULD HAVE FAILED\n");
}' >in
- atf_check -o ignore -e ignore -s ne:0 "$(prog)" -o out $type in
+ atf_check -o ignore -e ignore -s ne:0 "$(prog_db)" -o out $type in
atf_check -s ne:0 test -s out
cat exp |
@@ -663,7 +679,7 @@ h_cursor_flags()
printf("eR_CURSOR SHOULD HAVE FAILED\n");
}' >in
- atf_check -o ignore -e ignore -s ne:0 "$(prog)" -o out $type in
+ atf_check -o ignore -e ignore -s ne:0 "$(prog_db)" -o out $type in
atf_check -s ne:0 test -s out
}
@@ -719,7 +735,7 @@ reverse_order_recno_body()
printf("or\n");
}' >in
- atf_check -o file:exp "$(prog)" recno in
+ atf_check -o file:exp "$(prog_db)" recno in
}
atf_test_case small_page_btree
@@ -731,6 +747,9 @@ small_page_btree_head()
"reverses them, and gives them each a small size data" \
"entry. Uses a small page size to make sure the btree" \
"split code gets hammered."
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
small_page_btree_body()
{
@@ -749,7 +768,7 @@ small_page_btree_body()
echo k$i
done >in
- atf_check -o file:exp "$(prog)" -i psize=512 btree in
+ atf_check -o file:exp "$(prog_db)" -i psize=512 btree in
}
h_byte_orders()
@@ -765,18 +784,19 @@ h_byte_orders()
echo p
echo k$i
echo d$i
+ echo S
echo g
echo k$i
done >in
- atf_check -o file:exp "$(prog)" -ilorder=$order -f byte.file $type in
+ atf_check -o file:exp "$(prog_db)" -ilorder=$order -f byte.file $type in
for i in `sed 50q $(dict)`; do
echo g
echo k$i
done >in
- atf_check -o file:exp "$(prog)" -s -ilorder=$order -f byte.file $type in
+ atf_check -o file:exp "$(prog_db)" -s -ilorder=$order -f byte.file $type in
done
}
@@ -784,6 +804,9 @@ atf_test_case byte_orders_btree
byte_orders_btree_head()
{
atf_set "descr" "Checks btree database using differing byte orders"
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
byte_orders_btree_body()
{
@@ -806,16 +829,19 @@ h_bsize_ffactor()
ffactor=$2
echo "bucketsize $bsize, fill factor $ffactor"
- atf_check -o file:exp "$(prog)" "-ibsize=$bsize,\
+ atf_check -o file:exp "$(prog_db)" "-ibsize=$bsize,\
ffactor=$ffactor,nelem=25000,cachesize=65536" hash in
}
atf_test_case bsize_ffactor
bsize_ffactor_head()
{
- atf_set "timeout" "480"
+ atf_set "timeout" "1800"
atf_set "descr" "Checks hash database with various" \
"bucketsizes and fill factors"
+ # Begin FreeBSD
+ atf_set "require.files" /usr/share/dict/words
+ # End FreeBSD
}
bsize_ffactor_body()
{
@@ -876,9 +902,27 @@ bsize_ffactor_body()
h_bsize_ffactor 8192 341
h_bsize_ffactor 8192 455
h_bsize_ffactor 8192 683
+
+ h_bsize_ffactor 16384 341
+ h_bsize_ffactor 16384 455
+ h_bsize_ffactor 16384 683
+
+ h_bsize_ffactor 32768 341
+ h_bsize_ffactor 32768 455
+ h_bsize_ffactor 32768 683
+
+ # Begin FreeBSD
+ if false; then
+ # End FreeBSD
+ h_bsize_ffactor 65536 341
+ h_bsize_ffactor 65536 455
+ h_bsize_ffactor 65536 683
+ # Begin FreeBSD
+ fi
+ # End FreeBSD
}
-# FIXME: what does it test?
+# This tests 64K block size addition/removal
atf_test_case four_char_hash
four_char_hash_head()
{
@@ -901,15 +945,328 @@ EOF
# Begin FreeBSD
if true; then
- atf_check "$(prog)" -i bsize=32768 hash in
+ atf_check "$(prog_db)" -i bsize=32768 hash in
else
# End FreeBSD
- atf_check "$(prog)" -i bsize=65536 hash in
+ atf_check "$(prog_db)" -i bsize=65536 hash in
# Begin FreeBSD
fi
# End FreeBSD
}
+
+atf_test_case bsize_torture
+bsize_torture_head()
+{
+ atf_set "timeout" "36000"
+ atf_set "descr" "Checks hash database with various bucket sizes"
+}
+bsize_torture_body()
+{
+ TMPDIR="$(pwd)/db_dir"; export TMPDIR
+ mkdir ${TMPDIR}
+ # Begin FreeBSD
+ #
+ # db(3) doesn't support 64kB bucket sizes
+ for i in 2048 4096 8192 16384 32768 # 65536
+ # End FreeBSD
+ do
+ atf_check "$(prog_lfsr)" $i
+ done
+}
+
+atf_test_case btree_weird_page_split
+btree_weird_page_split_head()
+{
+ atf_set "descr" \
+ "Test for a weird page split condition where an insertion " \
+ "into index 0 of a page that would cause the new item to " \
+ "be the only item on the left page results in index 0 of " \
+ "the right page being erroneously skipped; this only " \
+ "happens with one particular key+data length for each page size."
+}
+btree_weird_page_split_body()
+{
+ for psize in 512 1024 2048 4096 8192; do
+ echo " page size $psize"
+ kdsizes=`awk 'BEGIN {
+ psize = '$psize'; hsize = int(psize/2);
+ for (kdsize = hsize-40; kdsize <= hsize; kdsize++) {
+ print kdsize;
+ }
+ }' /dev/null`
+
+ # Use a series of keylen+datalen values in the right
+ # neighborhood to find the one that triggers the bug.
+ # We could compute the exact size that triggers the
+ # bug but this additional fuzz may be useful.
+
+ # Insert keys in reverse order to maximize the chances
+ # for a split on index 0.
+
+ for kdsize in $kdsizes; do
+ awk 'BEGIN {
+ kdsize = '$kdsize';
+ for (i = 8; i-- > 0; ) {
+ s = sprintf("a%03d:%09d", i, kdsize);
+ for (j = 0; j < kdsize-20; j++) {
+ s = s "x";
+ }
+ printf("p\nka%03d\nd%s\n", i, s);
+ }
+ print "o";
+ }' /dev/null > in
+ sed -n 's/^d//p' in | sort > exp
+ atf_check -o file:exp \
+ "$(prog_db)" -i psize=$psize btree in
+ done
+ done
+}
+
+# Extremely tricky test attempting to replicate some unusual database
+# corruption seen in the field: pieces of the database becoming
+# inaccessible to random access, sequential access, or both. The
+# hypothesis is that at least some of these are triggered by the bug
+# in page splits on index 0 with a particular exact keylen+datalen.
+# (See Test 40.) For psize=4096, this size is exactly 2024.
+
+# The order of operations here relies on very specific knowledge of
+# the internals of the btree access method in order to place records
+# at specific offsets in a page and to create certain keys on internal
+# pages. The to-be-split page immediately prior to the bug-triggering
+# split has the following properties:
+#
+# * is not the leftmost leaf page
+# * key on the parent page is compares less than the key of the item
+# on index 0
+# * triggering record's key also compares greater than the key on the
+# parent page
+
+# Additionally, we prime the mpool LRU chain so that the head page on
+# the chain has the following properties:
+#
+# * record at index 0 is located where it will not get overwritten by
+# items written to the right-hand page during the split
+# * key of the record at index 0 compares less than the key of the
+# bug-triggering record
+
+# If the page-split bug exists, this test appears to create a database
+# where some records are inaccessible to a search, but still remain in
+# the file and are accessible by sequential traversal. At least one
+# record gets duplicated out of sequence.
+
+atf_test_case btree_tricky_page_split
+btree_tricky_page_split_head()
+{
+ atf_set "descr" \
+ "btree: no unsearchables due to page split on index 0"
+}
+btree_tricky_page_split_body()
+{
+ list=`(for i in a b c d; do
+ for j in 990 998 999; do
+ echo g ${i}${j} 1024
+ done
+ done;
+ echo g y997 2014
+ for i in y z; do
+ for j in 998 999; do
+ echo g ${i}${j} 1024
+ done
+ done)`
+ # Exact number for trigger condition accounts for newlines
+ # retained by dbtest with -ofile but not without; we use
+ # -ofile, so count newlines. keylen=5,datalen=5+2014 for
+ # psize=4096 here.
+ (cat - <<EOF
+p z999 1024
+p z998 1024
+p y999 1024
+p y990 1024
+p d999 1024
+p d990 1024
+p c999 1024
+p c990 1024
+p b999 1024
+p b990 1024
+p a999 1024
+p a990 1024
+p y998 1024
+r y990
+p d998 1024
+p d990 1024
+p c998 1024
+p c990 1024
+p b998 1024
+p b990 1024
+p a998 1024
+p a990 1024
+p y997 2014
+S
+o
+EOF
+ echo "$list") |
+ # awk script input:
+ # {p|g|r} key [datasize]
+ awk '/^[pgr]/{
+ printf("%s\nk%s\n", $1, $2);
+ }
+ /^p/{
+ s = $2;
+ for (i = 0; i < $3; i++) {
+ s = s "x";
+ }
+ printf("d%s\n", s);
+ }
+ !/^[pgr]/{
+ print $0;
+ }' > in
+ (echo "$list"; echo "$list") | awk '{
+ s = $2;
+ for (i = 0; i < $3; i++) {
+ s = s "x";
+ }
+ print s;
+ }' > exp
+ atf_check -o file:exp \
+ "$(prog_db)" -i psize=4096 btree in
+}
+
+# Begin FreeBSD
+if false; then
+# End FreeBSD
+atf_test_case btree_recursive_traversal
+btree_recursive_traversal_head()
+{
+ atf_set "descr" \
+ "btree: Test for recursive traversal successfully " \
+ "retrieving records that are inaccessible to normal " \
+ "sequential 'sibling-link' traversal. This works by " \
+ "unlinking a few leaf pages but leaving their parent " \
+ "links intact. To verify that the unlink actually makes " \
+ "records inaccessible, the test first uses 'o' to do a " \
+ "normal sequential traversal, followed by 'O' to do a " \
+ "recursive traversal."
+}
+btree_recursive_traversal_body()
+{
+ fill="abcdefghijklmnopqrstuvwxyzy"
+ script='{
+ for (i = 0; i < 20000; i++) {
+ printf("p\nkAA%05d\nd%05d%s\n", i, i, $0);
+ }
+ print "u";
+ print "u";
+ print "u";
+ print "u";
+ }'
+ (echo $fill | awk "$script"; echo o) > in1
+ echo $fill |
+ awk '{
+ for (i = 0; i < 20000; i++) {
+ if (i >= 5 && i <= 40)
+ continue;
+ printf("%05d%s\n", i, $0);
+ }
+ }' > exp1
+ atf_check -o file:exp1 \
+ "$(prog_db)" -i psize=512 btree in1
+ echo $fill |
+ awk '{
+ for (i = 0; i < 20000; i++) {
+ printf("%05d%s\n", i, $0);
+ }
+ }' > exp2
+ (echo $fill | awk "$script"; echo O) > in2
+ atf_check -o file:exp2 \
+ "$(prog_db)" -i psize=512 btree in2
+}
+# Begin FreeBSD
+fi
+# End FreeBSD
+
+atf_test_case btree_byteswap_unaligned_access_bksd
+btree_byteswap_unaligned_access_bksd_head()
+{
+ atf_set "descr" \
+ "btree: big key, small data, byteswap unaligned access"
+}
+btree_byteswap_unaligned_access_bksd_body()
+{
+ (echo foo; echo bar) |
+ awk '{
+ s = $0
+ for (i = 0; i < 488; i++) {
+ s = s "x";
+ }
+ printf("p\nk%s\ndx\n", s);
+ }' > in
+ for order in 1234 4321; do
+ atf_check \
+ "$(prog_db)" -o out -i psize=512,lorder=$order btree in
+ done
+}
+
+atf_test_case btree_byteswap_unaligned_access_skbd
+btree_byteswap_unaligned_access_skbd_head()
+{
+ atf_set "descr" \
+ "btree: small key, big data, byteswap unaligned access"
+}
+btree_byteswap_unaligned_access_skbd_body()
+{
+ # 484 = 512 - 20 (header) - 7 ("foo1234") - 1 (newline)
+ (echo foo1234; echo bar1234) |
+ awk '{
+ s = $0
+ for (i = 0; i < 484; i++) {
+ s = s "x";
+ }
+ printf("p\nk%s\nd%s\n", $0, s);
+ }' > in
+ for order in 1234 4321; do
+ atf_check \
+ "$(prog_db)" -o out -i psize=512,lorder=$order btree in
+ done
+}
+
+atf_test_case btree_known_byte_order
+btree_known_byte_order_head()
+{
+ atf_set "descr" \
+ "btree: small key, big data, known byte order"
+}
+btree_known_byte_order_body()
+{
+ local a="-i psize=512,lorder="
+
+ (echo foo1234; echo bar1234) |
+ awk '{
+ s = $0
+ for (i = 0; i < 484; i++) {
+ s = s "x";
+ }
+ printf("%s\n", s);
+ }' > exp
+ (echo foo1234; echo bar1234) |
+ awk '{
+ s = $0
+ for (i = 0; i < 484; i++) {
+ s = s "x";
+ }
+ printf("p\nk%s\nd%s\n", $0, s);
+ }' > in1
+ for order in 1234 4321; do
+ atf_check \
+ "$(prog_db)" -f out.$order $a$order btree in1
+ done
+ (echo g; echo kfoo1234; echo g; echo kbar1234) > in2
+ for order in 1234 4321; do
+ atf_check -o file:exp \
+ "$(prog_db)" -s -f out.$order $a$order btree in2
+ done
+}
+
atf_init_test_cases()
{
atf_add_test_case small_btree
@@ -937,4 +1294,17 @@ atf_init_test_cases()
atf_add_test_case byte_orders_hash
atf_add_test_case bsize_ffactor
atf_add_test_case four_char_hash
+ atf_add_test_case bsize_torture
+ atf_add_test_case btree_weird_page_split
+ atf_add_test_case btree_tricky_page_split
+ # Begin FreeBSD
+ if false; then
+ # End FreeBSD
+ atf_add_test_case btree_recursive_traversal
+ # Begin FreeBSD
+ fi
+ # End FreeBSD
+ atf_add_test_case btree_byteswap_unaligned_access_bksd
+ atf_add_test_case btree_byteswap_unaligned_access_skbd
+ atf_add_test_case btree_known_byte_order
}
OpenPOWER on IntegriCloud