1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1999,2008 Oracle.  All rights reserved.
4#
5# $Id: test053.tcl,v 12.6 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	test053
8# TEST	Test of the DB_REVSPLITOFF flag in the Btree and Btree-w-recnum
9# TEST	methods.
10proc test053 { method args } {
11	global alphabet
12	global errorCode
13	global is_je_test
14	source ./include.tcl
15
16	set args [convert_args $method $args]
17	set omethod [convert_method $method]
18
19	puts "\tTest053: Test of cursor stability across btree splits."
20	if { [is_btree $method] != 1 && [is_rbtree $method] != 1 } {
21		puts "Test053: skipping for method $method."
22		return
23	}
24
25	set pgindex [lsearch -exact $args "-pagesize"]
26	if { $pgindex != -1 } {
27		puts "Test053: skipping for specific pagesizes"
28		return
29	}
30
31	set txn ""
32	set flags ""
33
34	puts "\tTest053.a: Create $omethod $args database."
35	set txnenv 0
36	set eindex [lsearch -exact $args "-env"]
37	#
38	# If we are using an env, then testfile should just be the db name.
39	# Otherwise it is the test directory and the name.
40	if { $eindex == -1 } {
41		set testfile $testdir/test053.db
42		set env NULL
43	} else {
44		set testfile test053.db
45		incr eindex
46		set env [lindex $args $eindex]
47		set txnenv [is_txnenv $env]
48		if { $txnenv == 1 } {
49			append args " -auto_commit "
50		}
51		set testdir [get_home $env]
52	}
53	set t1 $testdir/t1
54	cleanup $testdir $env
55
56	set oflags \
57	    "-create -revsplitoff -pagesize 1024 $args $omethod"
58	set db [eval {berkdb_open} $oflags $testfile]
59	error_check_good dbopen [is_valid_db $db] TRUE
60
61	set nkeys 8
62	set npages 15
63
64	# We want to create a db with npages leaf pages, and have each page
65	# be near full with keys that we can predict. We set pagesize above
66	# to 1024 bytes, it should breakdown as follows (per page):
67	#
68	#	~20 bytes overhead
69	#	key: ~4 bytes overhead, XXX0N where X is a letter, N is 0-9
70	#	data: ~4 bytes overhead, + 100 bytes
71	#
72	# then, with 8 keys/page we should be just under 1024 bytes
73	puts "\tTest053.b: Create $npages pages with $nkeys pairs on each."
74	set keystring [string range $alphabet 0 [expr $npages -1]]
75	set data [repeat DATA 22]
76	for { set i 0 } { $i < $npages } {incr i } {
77		set key ""
78		set keyroot \
79		    [repeat [string toupper [string range $keystring $i $i]] 3]
80		set key_set($i) $keyroot
81		for {set j 0} { $j < $nkeys} {incr j} {
82			if { $j < 10 } {
83				set key [set keyroot]0$j
84			} else {
85				set key $keyroot$j
86			}
87			if { $txnenv == 1 } {
88				set t [$env txn]
89				error_check_good txn [is_valid_txn $t $env] TRUE
90				set txn "-txn $t"
91			}
92			set ret [eval {$db put} $txn {$key $data}]
93			error_check_good dbput $ret 0
94			if { $txnenv == 1 } {
95				error_check_good txn [$t commit] 0
96			}
97		}
98	}
99
100	if { !$is_je_test } {
101		puts "\tTest053.c: Check page count."
102		error_check_good page_count:check \
103		    [is_substr [$db stat] "{Leaf pages} $npages"] 1
104	}
105
106	puts "\tTest053.d: Delete all but one key per page."
107	for {set i 0} { $i < $npages } {incr i } {
108		for {set j 1} { $j < $nkeys } {incr j } {
109			if { $txnenv == 1 } {
110				set t [$env txn]
111				error_check_good txn [is_valid_txn $t $env] TRUE
112				set txn "-txn $t"
113			}
114			set ret [eval {$db del} $txn {$key_set($i)0$j}]
115			error_check_good dbdel $ret 0
116			if { $txnenv == 1 } {
117				error_check_good txn [$t commit] 0
118			}
119		}
120	}
121
122	if { !$is_je_test } {
123		puts "\tTest053.e: Check to make sure all pages are still there."
124		error_check_good page_count:check \
125		    [is_substr [$db stat] "{Leaf pages} $npages"] 1
126	}
127
128	if { $txnenv == 1 } {
129		set t [$env txn]
130		error_check_good txn [is_valid_txn $t $env] TRUE
131		set txn "-txn $t"
132	}
133	set dbc [eval {$db cursor} $txn]
134	error_check_good db:cursor [is_valid_cursor $dbc $db] TRUE
135
136	# walk cursor through tree forward, backward.
137	# delete one key, repeat
138	for {set i 0} { $i < $npages} {incr i} {
139		puts -nonewline \
140		    "\tTest053.f.$i: Walk curs through tree: forward..."
141		for { set j $i; set curr [$dbc get -first]} { $j < $npages} { \
142		    incr j; set curr [$dbc get -next]} {
143			error_check_bad dbc:get:next [llength $curr] 0
144			error_check_good dbc:get:keys \
145			    [lindex [lindex $curr 0] 0] $key_set($j)00
146		}
147		puts -nonewline "backward..."
148		for { set j [expr $npages - 1]; set curr [$dbc get -last]} { \
149		    $j >= $i } { \
150		    set j [incr j -1]; set curr [$dbc get -prev]} {
151			error_check_bad dbc:get:prev [llength $curr] 0
152			error_check_good dbc:get:keys \
153			    [lindex [lindex $curr 0] 0] $key_set($j)00
154		}
155		puts "complete."
156
157		if { [is_rbtree $method] == 1} {
158			puts "\t\tTest053.f.$i:\
159			    Walk through tree with record numbers."
160			for {set j 1} {$j <= [expr $npages - $i]} {incr j} {
161				set curr [eval {$db get} $txn {-recno $j}]
162				error_check_bad \
163				    db_get:recno:$j [llength $curr] 0
164				error_check_good db_get:recno:keys:$j \
165				    [lindex [lindex $curr 0] 0] \
166				    $key_set([expr $j + $i - 1])00
167			}
168		}
169		puts "\tTest053.g.$i:\
170		    Delete single key ([expr $npages - $i] keys left)."
171		set ret [eval {$db del} $txn {$key_set($i)00}]
172		error_check_good dbdel $ret 0
173		error_check_good del:check \
174		    [llength [eval {$db get} $txn {$key_set($i)00}]] 0
175	}
176
177	# end for loop, verify db_notfound
178	set ret [$dbc get -first]
179	error_check_good dbc:get:verify [llength $ret] 0
180
181	# loop: until single key restored on each page
182	for {set i 0} { $i < $npages} {incr i} {
183		puts "\tTest053.i.$i:\
184		    Restore single key ([expr $i + 1] keys in tree)."
185		set ret [eval {$db put} $txn {$key_set($i)00 $data}]
186		error_check_good dbput $ret 0
187
188		puts -nonewline \
189		    "\tTest053.j: Walk cursor through tree: forward..."
190		for { set j 0; set curr [$dbc get -first]} { $j <= $i} {\
191				  incr j; set curr [$dbc get -next]} {
192			error_check_bad dbc:get:next [llength $curr] 0
193			error_check_good dbc:get:keys \
194			    [lindex [lindex $curr 0] 0] $key_set($j)00
195		}
196		error_check_good dbc:get:next [llength $curr] 0
197
198		puts -nonewline "backward..."
199		for { set j $i; set curr [$dbc get -last]} { \
200		    $j >= 0 } { \
201		    set j [incr j -1]; set curr [$dbc get -prev]} {
202			error_check_bad dbc:get:prev [llength $curr] 0
203			error_check_good dbc:get:keys \
204			    [lindex [lindex $curr 0] 0] $key_set($j)00
205		}
206		puts "complete."
207		error_check_good dbc:get:prev [llength $curr] 0
208
209		if { [is_rbtree $method] == 1} {
210			puts "\t\tTest053.k.$i:\
211			    Walk through tree with record numbers."
212			for {set j 1} {$j <= [expr $i + 1]} {incr j} {
213				set curr [eval {$db get} $txn {-recno $j}]
214				error_check_bad \
215				    db_get:recno:$j [llength $curr] 0
216				error_check_good db_get:recno:keys:$j \
217				    [lindex [lindex $curr 0] 0] \
218				    $key_set([expr $j - 1])00
219			}
220		}
221	}
222
223	error_check_good dbc_close [$dbc close] 0
224	if { $txnenv == 1 } {
225		error_check_good txn [$t commit] 0
226	}
227	error_check_good db_close [$db close] 0
228
229	puts "Test053 complete."
230}
231