xref: /freebsd/crypto/krb5/src/plugins/kdb/db2/libdb2/test/run.test (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
1#!/bin/sh -
2#
3#	@(#)run.test	8.13 (Berkeley) 11/2/95
4#
5
6. ./runenv.sh
7
8# db regression tests
9main()
10{
11
12	PROG=./dbtest
13	TMP1=${TMPDIR-.}/t1
14	TMP2=${TMPDIR-.}/t2
15	TMP3=${TMPDIR-.}/t3
16	BINFILES=${TMPDIR-.}/binfiles
17
18	if [ \! -z "$WORDLIST" -a -f "$WORDLIST" ]; then
19		DICT=$WORDLIST
20	elif [ -f /usr/local/lib/dict/words ]; then
21		DICT=/usr/local/lib/dict/words
22	elif [ -f /usr/share/dict/words ]; then
23		DICT=/usr/share/dict/words
24	elif [ -f /usr/dict/words ]; then
25		DICT=/usr/dict/words
26	elif [ -f /usr/share/lib/dict/words ]; then
27		DICT=/usr/share/lib/dict/words
28	elif [ -f $srcdir/../test/dictionary ]; then
29		DICT=`cd $srcdir/../test && pwd`/dictionary
30	else
31		echo 'run.test: no dictionary'
32		exit 1
33	fi
34
35	dictsize=`wc -l < $DICT`
36
37	bindir=/bin/.
38	find $bindir -type f -exec test -r {} \; -print | head -100 > $BINFILES
39
40	if [ $# -eq 0 ]; then
41		for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 20 40 41 50 60 61 62 63; do
42			test$t
43		done
44	else
45		while [ $# -gt 0 ]
46			do case "$1" in
47			test*)
48				$1;;
49			[0-9]*)
50				test$1;;
51			btree)
52				for t in 1 2 3 7 8 9 10 12 13 40 41 50 60 61 62 63; do
53					test$t
54				done;;
55			hash)
56				for t in 1 2 3 8 13 20; do
57					test$t
58				done;;
59			recno)
60				for t in 1 2 3 4 5 6 7 10 11; do
61					test$t
62				done;;
63			*)
64				echo "run.test: unknown test $1"
65				echo "usage: run.test test# | type"
66				exit 1
67			esac
68			shift
69		done
70	fi
71	rm -f $TMP1 $TMP2 $TMP3 $BINFILES
72	exit 0
73}
74
75getnwords() {
76	# Delete blank lines because the db code appears not to like
77	# empty keys.  Omit lines with non-alphanumeric characters to
78	# avoid shell metacharacters and non-ASCII characters which
79	# could cause 'rev' to choke.
80	LC_ALL=C sed -e '/^$/d' -e '/[^A-Za-z]/d' < $DICT | sed -e ${1}q
81}
82
83# Take the first hundred entries in the dictionary, and make them
84# be key/data pairs.
85test1()
86{
87	echo "Test 1: btree, hash: small key, small data pairs"
88	getnwords 200 > $TMP1
89	for type in btree hash; do
90		rm -f $TMP2 $TMP3
91		for i in `cat $TMP1`; do
92			echo p
93			echo k$i
94			echo d$i
95			echo g
96			echo k$i
97		done > $TMP2
98		$PROG -o $TMP3 $type $TMP2
99		if (cmp -s $TMP1 $TMP3) ; then :
100		else
101			echo "test1: type $type: failed"
102			exit 1
103		fi
104	done
105	echo "Test 1: recno: small key, small data pairs"
106	rm -f $TMP2 $TMP3
107	awk '{
108		++i;
109		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
110	}' < $TMP1 > $TMP2
111	$PROG -o $TMP3 recno $TMP2
112	if (cmp -s $TMP1 $TMP3) ; then :
113	else
114		echo "test1: type recno: failed"
115		exit 1
116	fi
117}
118
119# Take the first 200 entries in the dictionary, and give them
120# each a medium size data entry.
121test2()
122{
123	echo "Test 2: btree, hash: small key, medium data pairs"
124	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
125	echo $mdata |
126	awk '{ for (i = 1; i < 201; ++i) print $0 }' > $TMP1
127	for type in hash btree; do
128		rm -f $TMP2 $TMP3
129		for i in `getnwords 200`; do
130			echo p
131			echo k$i
132			echo d$mdata
133			echo g
134			echo k$i
135		done > $TMP2
136		$PROG -o $TMP3 $type $TMP2
137		if (cmp -s $TMP1 $TMP3) ; then :
138		else
139			echo "test2: type $type: failed"
140			exit 1
141		fi
142	done
143	echo "Test 2: recno: small key, medium data pairs"
144	rm -f $TMP2 $TMP3
145	echo $mdata |
146	awk '{  for (i = 1; i < 201; ++i)
147		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
148	}' > $TMP2
149	$PROG -o $TMP3 recno $TMP2
150	if (cmp -s $TMP1 $TMP3) ; then :
151	else
152		echo "test2: type recno: failed"
153		exit 1
154	fi
155}
156
157# Insert the programs in $bindir with their paths as their keys.
158test3()
159{
160	echo "Test 3: hash: small key, big data pairs"
161	rm -f $TMP1
162	xargs cat < $BINFILES > $TMP1
163	for type in hash; do
164		rm -f $TMP2 $TMP3
165		for i in `cat $BINFILES`; do
166			echo p
167			echo k$i
168			echo D$i
169			echo g
170			echo k$i
171		done > $TMP2
172		$PROG -o $TMP3 $type $TMP2
173		if (cmp -s $TMP1 $TMP3) ; then :
174		else
175			echo "test3: $type: failed"
176			exit 1
177		fi
178	done
179	echo "Test 3: btree: small key, big data pairs"
180	for psize in 512 16384 65536; do
181		echo "    page size $psize"
182		for type in btree; do
183			rm -f $TMP2 $TMP3
184			for i in `cat $BINFILES`; do
185				echo p
186				echo k$i
187				echo D$i
188				echo g
189				echo k$i
190			done > $TMP2
191			$PROG -i psize=$psize -o $TMP3 $type $TMP2
192			if (cmp -s $TMP1 $TMP3) ; then :
193			else
194				echo "test3: $type: page size $psize: failed"
195				exit 1
196			fi
197		done
198	done
199	echo "Test 3: recno: big data pairs"
200	rm -f $TMP2 $TMP3
201	awk '{
202		++i;
203		printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i);
204	}' < $BINFILES > $TMP2
205	for psize in 512 16384 65536; do
206		echo "    page size $psize"
207		$PROG -i psize=$psize -o $TMP3 recno $TMP2
208		if (cmp -s $TMP1 $TMP3) ; then :
209		else
210			echo "test3: recno: page size $psize: failed"
211			exit 1
212		fi
213	done
214}
215
216# Do random recno entries.
217test4()
218{
219	echo "Test 4: recno: random entries"
220	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
221	awk '{
222		for (i = 37; i <= 37 + 88 * 17; i += 17) {
223			if (i % 41)
224				s = substr($0, 1, i % 41);
225			else
226				s = substr($0, 1);
227			printf("input key %d: %s\n", i, s);
228		}
229		for (i = 1; i <= 15; ++i) {
230			if (i % 41)
231				s = substr($0, 1, i % 41);
232			else
233				s = substr($0, 1);
234			printf("input key %d: %s\n", i, s);
235		}
236		for (i = 19234; i <= 19234 + 61 * 27; i += 27) {
237			if (i % 41)
238				s = substr($0, 1, i % 41);
239			else
240				s = substr($0, 1);
241			printf("input key %d: %s\n", i, s);
242		}
243		exit
244	}' > $TMP1
245	rm -f $TMP2 $TMP3
246	cat $TMP1 |
247	awk 'BEGIN {
248			i = 37;
249			incr = 17;
250		}
251		{
252			printf("p\nk%d\nd%s\n", i, $0);
253			if (i == 19234 + 61 * 27)
254				exit;
255			if (i == 37 + 88 * 17) {
256				i = 1;
257				incr = 1;
258			} else if (i == 15) {
259				i = 19234;
260				incr = 27;
261			} else
262				i += incr;
263		}
264		END {
265			for (i = 37; i <= 37 + 88 * 17; i += 17)
266				printf("g\nk%d\n", i);
267			for (i = 1; i <= 15; ++i)
268				printf("g\nk%d\n", i);
269			for (i = 19234; i <= 19234 + 61 * 27; i += 27)
270				printf("g\nk%d\n", i);
271		}' > $TMP2
272	$PROG -o $TMP3 recno $TMP2
273	if (cmp -s $TMP1 $TMP3) ; then :
274	else
275		echo "test4: type recno: failed"
276		exit 1
277	fi
278}
279
280# Do reverse order recno entries.
281test5()
282{
283	echo "Test 5: recno: reverse order entries"
284	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
285	awk ' {
286		for (i = 1500; i; --i) {
287			if (i % 34)
288				s = substr($0, 1, i % 34);
289			else
290				s = substr($0, 1);
291			printf("input key %d: %s\n", i, s);
292		}
293		exit;
294	}' > $TMP1
295	rm -f $TMP2 $TMP3
296	cat $TMP1 |
297	awk 'BEGIN {
298			i = 1500;
299		}
300		{
301			printf("p\nk%d\nd%s\n", i, $0);
302			--i;
303		}
304		END {
305			for (i = 1500; i; --i)
306				printf("g\nk%d\n", i);
307		}' > $TMP2
308	$PROG -o $TMP3 recno $TMP2
309	if (cmp -s $TMP1 $TMP3) ; then :
310	else
311		echo "test5: type recno: failed"
312		exit 1
313	fi
314}
315
316# Do alternating order recno entries.
317test6()
318{
319	echo "Test 6: recno: alternating order entries"
320	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
321	awk ' {
322		for (i = 1; i < 1200; i += 2) {
323			if (i % 34)
324				s = substr($0, 1, i % 34);
325			else
326				s = substr($0, 1);
327			printf("input key %d: %s\n", i, s);
328		}
329		for (i = 2; i < 1200; i += 2) {
330			if (i % 34)
331				s = substr($0, 1, i % 34);
332			else
333				s = substr($0, 1);
334			printf("input key %d: %s\n", i, s);
335		}
336		exit;
337	}' > $TMP1
338	rm -f $TMP2 $TMP3
339	cat $TMP1 |
340	awk 'BEGIN {
341			i = 1;
342			even = 0;
343		}
344		{
345			printf("p\nk%d\nd%s\n", i, $0);
346			i += 2;
347			if (i >= 1200) {
348				if (even == 1)
349					exit;
350				even = 1;
351				i = 2;
352			}
353		}
354		END {
355			for (i = 1; i < 1200; ++i)
356				printf("g\nk%d\n", i);
357		}' > $TMP2
358	$PROG -o $TMP3 recno $TMP2
359	sort -o $TMP1 $TMP1
360	sort -o $TMP3 $TMP3
361	if (cmp -s $TMP1 $TMP3) ; then :
362	else
363		echo "test6: type recno: failed"
364		exit 1
365	fi
366}
367
368# Delete cursor record
369test7()
370{
371	echo "Test 7: btree, recno: delete cursor record"
372	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
373	awk '{
374		for (i = 1; i <= 120; ++i)
375			printf("%05d: input key %d: %s\n", i, i, $0);
376		printf("%05d: input key %d: %s\n", 120, 120, $0);
377		printf("seq failed, no such key\n");
378		printf("%05d: input key %d: %s\n", 1, 1, $0);
379		printf("%05d: input key %d: %s\n", 2, 2, $0);
380		exit;
381	}' > $TMP1
382	rm -f $TMP2 $TMP3
383
384	for type in btree recno; do
385		cat $TMP1 |
386		awk '{
387			if (i == 120)
388				exit;
389			printf("p\nk%d\nd%s\n", ++i, $0);
390		}
391		END {
392			printf("fR_NEXT\n");
393			for (i = 1; i <= 120; ++i)
394				printf("s\n");
395			printf("fR_CURSOR\ns\nk120\n");
396			printf("r\n");
397			printf("fR_NEXT\ns\n");
398			printf("fR_CURSOR\ns\nk1\n");
399			printf("r\n");
400			printf("fR_FIRST\ns\n");
401		}' > $TMP2
402		$PROG -o $TMP3 recno $TMP2
403		if (cmp -s $TMP1 $TMP3) ; then :
404		else
405			echo "test7: type $type: failed"
406			exit 1
407		fi
408	done
409}
410
411# Make sure that overflow pages are reused.
412test8()
413{
414	echo "Test 8: btree: repeated small key, big data pairs"
415	rm -f $TMP1
416	# /bin/csh is no longer ubiquitous - find a substitute
417	# The test stores contents of a known file
418	tfile=""
419	for tp in /bin/csh /bin/ls /usr/bin/ls /bin/cat /usr/bin/cat; do
420	    if [ "x$tfile" = "x" -a -f $tp ]; then
421		tfile=$tp
422	    fi
423	done
424	if [ "x$tfile" = "x" ]; then
425	    echo "No suitable file for testing purposes"
426	    exit 1
427	fi
428	echo "" |
429	awk 'BEGIN {
430		for (i = 1; i <= 10; ++i) {
431			printf("p\nkkey1\nD/bin/sh\n");
432			printf("p\nkkey2\nD'$tfile'\n");
433			if (i % 8 == 0) {
434				printf("c\nkkey2\nD'$tfile'\n");
435				printf("c\nkkey1\nD/bin/sh\n");
436				printf("e\t%d of 10 (comparison)\n", i);
437			} else
438				printf("e\t%d of 10             \n", i);
439			printf("r\nkkey1\nr\nkkey2\n");
440		}
441	}' > $TMP1
442	if $PROG btree $TMP1 ; then
443	    true
444	else
445	    echo "test8: btree tests failed"
446	    exit 1
447	fi
448#	$PROG hash $TMP1
449	# No explicit test for success.
450}
451
452# Test btree duplicate keys
453test9()
454{
455	echo "Test 9: btree: duplicate keys"
456	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
457	awk '{
458		for (i = 1; i <= 543; ++i)
459			printf("%05d: input key %d: %s\n", i, i, $0);
460		exit;
461	}' > $TMP1
462	rm -f $TMP2 $TMP3
463
464	for type in btree; do
465		cat $TMP1 |
466		awk '{
467			if (i++ % 2)
468				printf("p\nkduplicatekey\nd%s\n", $0);
469			else
470				printf("p\nkunique%dkey\nd%s\n", i, $0);
471		}
472		END {
473				printf("o\n");
474		}' > $TMP2
475		$PROG -iflags=1 -o $TMP3 $type $TMP2
476		sort -o $TMP3 $TMP3
477		if (cmp -s $TMP1 $TMP3) ; then :
478		else
479			echo "test9: type $type: failed"
480			exit 1
481		fi
482	done
483}
484
485# Test use of cursor flags without initialization
486test10()
487{
488	echo "Test 10: btree, recno: test cursor flag use"
489	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
490	awk '{
491		for (i = 1; i <= 20; ++i)
492			printf("%05d: input key %d: %s\n", i, i, $0);
493		exit;
494	}' > $TMP1
495	rm -f $TMP2 $TMP3
496
497	# Test that R_CURSOR doesn't succeed before cursor initialized
498	for type in btree recno; do
499		cat $TMP1 |
500		awk '{
501			if (i == 10)
502				exit;
503			printf("p\nk%d\nd%s\n", ++i, $0);
504		}
505		END {
506			printf("fR_CURSOR\nr\n");
507			printf("eR_CURSOR SHOULD HAVE FAILED\n");
508		}' > $TMP2
509		$PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
510		if [ -s $TMP3 ] ; then
511			echo "Test 10: delete: R_CURSOR SHOULD HAVE FAILED"
512			exit 1
513		fi
514	done
515	for type in btree recno; do
516		cat $TMP1 |
517		awk '{
518			if (i == 10)
519				exit;
520			printf("p\nk%d\nd%s\n", ++i, $0);
521		}
522		END {
523			printf("fR_CURSOR\np\nk1\ndsome data\n");
524			printf("eR_CURSOR SHOULD HAVE FAILED\n");
525		}' > $TMP2
526		$PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
527		if [ -s $TMP3 ] ; then
528			echo "Test 10: put: R_CURSOR SHOULD HAVE FAILED"
529			exit 1
530		fi
531	done
532}
533
534# Test insert in reverse order.
535test11()
536{
537	echo "Test 11: recno: reverse order insert"
538	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
539	awk '{
540		for (i = 1; i <= 779; ++i)
541			printf("%05d: input key %d: %s\n", i, i, $0);
542		exit;
543	}' > $TMP1
544	rm -f $TMP2 $TMP3
545
546	for type in recno; do
547		cat $TMP1 |
548		awk '{
549			if (i == 0) {
550				i = 1;
551				printf("p\nk1\nd%s\n", $0);
552				printf("%s\n", "fR_IBEFORE");
553			} else
554				printf("p\nk1\nd%s\n", $0);
555		}
556		END {
557				printf("or\n");
558		}' > $TMP2
559		$PROG -o $TMP3 $type $TMP2
560		if (cmp -s $TMP1 $TMP3) ; then :
561		else
562			echo "test11: type $type: failed"
563			exit 1
564		fi
565	done
566}
567
568# Take the first 20000 entries in the dictionary, reverse them, and give
569# them each a small size data entry.  Use a small page size to make sure
570# the btree split code gets hammered.
571test12()
572{
573	if ( rev < /dev/null ) > /dev/null 2>&1 ; then
574		:
575	else
576		echo "Test 12: skipped, rev not found"
577		return
578	fi
579	if test $dictsize -lt 20001 ; then
580		echo "Test 12: skipped, dictionary too small"
581		return
582	else
583		:
584	fi
585	echo "Test 12: btree: lots of keys, small page size"
586	mdata=abcdefghijklmnopqrstuvwxy
587	echo $mdata |
588	awk '{ for (i = 1; i < 20001; ++i) print $0 }' > $TMP1
589	for type in btree; do
590		rm -f $TMP2 $TMP3
591		for i in `getnwords 20000 | rev`; do
592			echo p
593			echo k$i
594			echo d$mdata
595			echo g
596			echo k$i
597		done > $TMP2
598		$PROG -i psize=512 -o $TMP3 $type $TMP2
599		if (cmp -s $TMP1 $TMP3) ; then :
600		else
601			echo "test12: type $type: failed"
602			exit 1
603		fi
604	done
605}
606
607# Test different byte orders.
608test13()
609{
610	echo "Test 13: btree, hash: differing byte orders"
611	getnwords 50 > $TMP1
612	for order in 1234 4321; do
613		for type in btree hash; do
614			rm -f byte.file $TMP2 $TMP3
615			for i in `cat $TMP1`; do
616				echo p
617				echo k$i
618				echo d$i
619				echo S
620				echo g
621				echo k$i
622			done > $TMP2
623			$PROG -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
624			if (cmp -s $TMP1 $TMP3) ; then :
625			else
626				echo "test13: $type/$order put failed"
627				exit 1
628			fi
629			for i in `cat $TMP1`; do
630				echo g
631				echo k$i
632			done > $TMP2
633			$PROG -s \
634			    -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
635			if (cmp -s $TMP1 $TMP3) ; then :
636			else
637				echo "test13: $type/$order get failed"
638				exit 1
639			fi
640		done
641	done
642	rm -f byte.file
643}
644
645# Try a variety of bucketsizes and fill factors for hashing
646test20()
647{
648	if test $dictsize -lt 10001 ; then
649		echo "Test 20: skipped, dictionary too small"
650		return
651	else
652		:
653	fi
654	echo\
655    "Test 20: hash: bucketsize, fill factor; nelem 25000 cachesize 65536"
656	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
657	awk '{
658		for (i = 1; i <= 10000; ++i) {
659			if (i % 34)
660				s = substr($0, 1, i % 34);
661			else
662				s = substr($0, 1);
663			printf("%s\n", s);
664		}
665		exit;
666	}' > $TMP1
667	getnwords 10000 |
668	awk 'BEGIN {
669		ds="abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg"
670	}
671	{
672		if (++i % 34)
673			s = substr(ds, 1, i % 34);
674		else
675			s = substr(ds, 1);
676		printf("p\nk%s\nd%s\n", $0, s);
677	}' > $TMP2
678	getnwords 10000 |
679	awk '{
680		++i;
681		printf("g\nk%s\n", $0);
682	}' >> $TMP2
683	bsize=256
684	for ffactor in 11 14 21; do
685		echo "    bucketsize $bsize, fill factor $ffactor"
686		$PROG -o$TMP3 \
687		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
688		    hash $TMP2
689		if (cmp -s $TMP1 $TMP3) ; then :
690		else
691			echo "test20: type hash:\
692bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
693			exit 1
694		fi
695	done
696	bsize=512
697	for ffactor in 21 28 43; do
698		echo "    bucketsize $bsize, fill factor $ffactor"
699		$PROG -o$TMP3 \
700		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
701		    hash $TMP2
702		if (cmp -s $TMP1 $TMP3) ; then :
703		else
704			echo "test20: type hash:\
705bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
706			exit 1
707		fi
708	done
709	bsize=1024
710	for ffactor in 43 57 85; do
711		echo "    bucketsize $bsize, fill factor $ffactor"
712		$PROG -o$TMP3 \
713		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
714		    hash $TMP2
715		if (cmp -s $TMP1 $TMP3) ; then :
716		else
717			echo "test20: type hash:\
718bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
719			exit 1
720		fi
721	done
722	bsize=2048
723	for ffactor in 85 114 171; do
724		echo "    bucketsize $bsize, fill factor $ffactor"
725		$PROG -o$TMP3 \
726		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
727		    hash $TMP2
728		if (cmp -s $TMP1 $TMP3) ; then :
729		else
730			echo "test20: type hash:\
731bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
732			exit 1
733		fi
734	done
735	bsize=4096
736	for ffactor in 171 228 341; do
737		echo "    bucketsize $bsize, fill factor $ffactor"
738		$PROG -o$TMP3 \
739		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
740		    hash $TMP2
741		if (cmp -s $TMP1 $TMP3) ; then :
742		else
743			echo "test20: type hash:\
744bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
745			exit 1
746		fi
747	done
748	bsize=8192
749	for ffactor in 341 455 683; do
750		echo "    bucketsize $bsize, fill factor $ffactor"
751		$PROG -o$TMP3 \
752		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
753		    hash $TMP2
754		if (cmp -s $TMP1 $TMP3) ; then :
755		else
756			echo "test20: type hash:\
757bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
758			exit 1
759		fi
760	done
761}
762
763# Test for a weird page split condition where an insertion into index
764# 0 of a page that would cause the new item to be the only item on the
765# left page results in index 0 of the right page being erroneously
766# skipped; this only happens with one particular key+data length for
767# each page size.
768test40 () {
769	echo "Test 40: btree: page split on index 0"
770	e=:
771	for psize in 512 1024 2048 4096 8192; do
772		echo "    page size $psize"
773		kdsizes=`awk 'BEGIN {
774			psize = '$psize'; hsize = int(psize/2);
775			for (kdsize = hsize-40; kdsize <= hsize; kdsize++) {
776				print kdsize;
777			}
778		}' /dev/null`
779
780		# Use a series of keylen+datalen values in the right
781		# neighborhood to find the one that triggers the bug.
782		# We could compute the exact size that triggers the
783		# bug but this additional fuzz may be useful.
784
785		# Insert keys in reverse order to maximize the chances
786		# for a split on index 0.
787
788		for kdsize in $kdsizes; do
789			awk 'BEGIN {
790				kdsize = '$kdsize';
791				for (i = 8; i-- > 0; ) {
792					s = sprintf("a%03d:%09d", i, kdsize);
793					for (j = 0; j < kdsize-20; j++) {
794						s = s "x";
795					}
796					printf("p\nka%03d\nd%s\n", i, s);
797				}
798				print "o";
799			}' /dev/null > $TMP2
800			sed -n 's/^d//p' $TMP2 | sort > $TMP1
801			$PROG -o $TMP3 -i psize=$psize btree $TMP2
802			if (cmp -s $TMP1 $TMP3); then :
803			else
804				echo "test40: btree: page size $psize, \
805keylen+datalen=$kdsize failed"
806				e='exit 1'
807			fi
808		done
809	done
810	$e
811}
812
813# Extremely tricky test attempting to replicate some unusual database
814# corruption seen in the field: pieces of the database becoming
815# inaccessible to random access, sequential access, or both.  The
816# hypothesis is that at least some of these are triggered by the bug
817# in page splits on index 0 with a particular exact keylen+datalen.
818# (See Test 40.)  For psize=4096, this size is exactly 2024.
819
820# The order of operations here relies on very specific knowledge of
821# the internals of the btree access method in order to place records
822# at specific offsets in a page and to create certain keys on internal
823# pages.  The to-be-split page immediately prior to the bug-triggering
824# split has the following properties:
825#
826# * is not the leftmost leaf page
827# * key on the parent page is compares less than the key of the item
828#   on index 0
829# * triggering record's key also compares greater than the key on the
830#   parent page
831
832# Additionally, we prime the mpool LRU chain so that the head page on
833# the chain has the following properties:
834#
835# * record at index 0 is located where it will not get overwritten by
836#   items written to the right-hand page during the split
837# * key of the record at index 0 compares less than the key of the
838#   bug-triggering record
839
840# If the page-split bug exists, this test appears to create a database
841# where some records are inaccessible to a search, but still remain in
842# the file and are accessible by sequential traversal.  At least one
843# record gets duplicated out of sequence.
844
845test41 () {
846	echo "Test 41: btree: no unsearchables due to page split on index 0"
847	# list of individual retrievals in a variable for easy reuse
848	list=`(for i in a b c d; do
849			for j in 990 998 999; do
850				echo g ${i}${j} 1024
851			done
852		done;
853		echo g y997 2014
854		for i in y z; do
855			for j in 998 999; do
856				echo g ${i}${j} 1024
857			done
858		done)`
859	# Exact number for trigger condition accounts for newlines
860	# retained by dbtest with -ofile but not without; we use
861	# -ofile, so count newlines.  keylen=5,datalen=5+2014 for
862	# psize=4096 here.
863	(cat - <<EOF
864p z999 1024
865p z998 1024
866p y999 1024
867p y990 1024
868p d999 1024
869p d990 1024
870p c999 1024
871p c990 1024
872p b999 1024
873p b990 1024
874p a999 1024
875p a990 1024
876p y998 1024
877r y990
878p d998 1024
879p d990 1024
880p c998 1024
881p c990 1024
882p b998 1024
883p b990 1024
884p a998 1024
885p a990 1024
886p y997 2014
887S
888o
889EOF
890	echo "$list") |
891	# awk script input:
892	# {p|g|r} key [datasize]
893	awk '/^[pgr]/{
894		printf("%s\nk%s\n", $1, $2);
895	}
896	/^p/{
897		s = $2;
898		for (i = 0; i < $3; i++) {
899			s = s "x";
900		}
901		printf("d%s\n", s);
902	}
903	!/^[pgr]/{
904		print $0;
905	}' > $TMP2
906	(echo "$list"; echo "$list") | awk '{
907		s = $2;
908		for (i = 0; i < $3; i++) {
909			s = s "x";
910		}
911		print s;
912	}' > $TMP1
913	$PROG -o $TMP3 -i psize=4096 btree $TMP2
914	if (cmp -s $TMP1 $TMP3); then :
915	else
916		echo "test41: btree: failed"
917		exit 1
918	fi
919}
920
921# Test for recursive traversal successfully retrieving records that
922# are inaccessible to normal sequential (sibling-link) traversal.
923# This works by unlinking a few leaf pages but leaving their parent
924# links intact.  To verify that the unlink actually makes records
925# inaccessible, the test first uses "o" to do a normal sequential
926# traversal, followed by "O" to do a recursive traversal.
927test50 () {
928	echo "Test 50: btree: recursive traversal"
929	fill="abcdefghijklmnopqrstuvwxyzy"
930	script='{
931		for (i = 0; i < 20000; i++) {
932			printf("p\nkAA%05d\nd%05d%s\n", i, i, $0);
933		}
934		print "u";
935		print "u";
936		print "u";
937		print "u";
938	}'
939	(echo $fill | awk "$script"; echo o) > $TMP2
940	echo $fill |
941	awk '{
942		for (i = 0; i < 20000; i++) {
943			printf("%05d%s\n", i, $0);
944		}
945	}' > $TMP1
946	$PROG -o $TMP3 -i psize=512 btree $TMP2
947	if (cmp -s $TMP1 $TMP3); then
948		echo "test50: btree: unexpected success after unlinking pages"
949		exit 1
950	fi
951	(echo $fill | awk "$script"; echo O) > $TMP2
952	$PROG -o $TMP3 -i psize=512 btree $TMP2
953	if (cmp -s $TMP1 $TMP3); then :
954	else
955		echo "test50: btree: failed"
956		exit 1
957	fi
958}
959
960test60 () {
961	echo "Test 60: btree: big key, small data, byteswap unaligned access"
962	# 488 = 512 - 20 (header) - 3 ("foo") - 1 (newline)
963	(echo foo; echo bar) |
964	awk '{
965		s = $0
966		for (i = 0; i < 488; i++) {
967			s = s "x";
968		}
969		printf("p\nk%s\ndx\n", s);
970	}' > $TMP2
971	for order in 1234 4321; do
972		$PROG -o $TMP3 -i psize=512,lorder=$order btree $TMP2
973	done
974}
975
976test61 () {
977	echo "Test 61: btree: small key, big data, byteswap unaligned access"
978	# 484 = 512 - 20 (header) - 7 ("foo1234") - 1 (newline)
979	(echo foo1234; echo bar1234) |
980	awk '{
981		s = $0
982		for (i = 0; i < 484; i++) {
983			s = s "x";
984		}
985		printf("p\nk%s\nd%s\n", $0, s);
986	}' > $TMP2
987	for order in 1234 4321; do
988		$PROG -o $TMP3 -i psize=512,lorder=$order btree $TMP2
989	done
990}
991
992test62 () {
993	echo "Test 62: btree: small key, big data, known byte order files"
994	(echo foo1234; echo bar1234) |
995	awk '{
996		s = $0
997		for (i = 0; i < 484; i++) {
998			s = s "x";
999		}
1000		printf("%s\n", s);
1001	}' > $TMP1
1002	(echo g; echo kfoo1234; echo g; echo kbar1234) > $TMP2
1003	for f in t.le.db t.be.db; do
1004		echo "    $f"
1005		$PROG -f $f -s -o $TMP3 btree $TMP2
1006		if (cmp -s $TMP1 $TMP3); then :
1007		else
1008			echo "test62: btree: failed"
1009			exit 1
1010		fi
1011	done
1012}
1013
1014test63 () {
1015	echo "Test 63: btree: big key, medium data, bt_split unaligned access"
1016	# 488 = 512 - 20 (header) - 3 ("foo") - 1 (newline)
1017	# 223 = 232 - 8 (key pointer)
1018	# 232 = bt_ovflsize = (512 - 20 (header)) / 2 (DEFMINKEYPAGE)
1019	#	- (2 (indx_t) + 12 (NBLEAFDBT(0,0)))
1020	awk 'BEGIN {
1021		s = "";
1022		for (i = 0; i < 488; i++) {
1023			s = s "x";
1024		}
1025		d = "";
1026		for (i = 0; i < 223; i++) {
1027			d = d "x";
1028		}
1029		for (i = 0; i < 128; i++) {
1030			printf("p\nk%s%03d\nd%s\n", s, i, d);
1031		}
1032	}' /dev/null > $TMP2
1033	$PROG -o $TMP3 -i psize=512 btree $TMP2
1034}
1035
1036main $*
1037