1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2003,2008 Oracle.  All rights reserved.
4#
5# $Id: test103.tcl,v 12.6 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	test103
8# TEST	Test bulk get when record numbers wrap around.
9# TEST
10# TEST	Load database with items starting before and ending after
11# TEST	the record number wrap around point.  Run bulk gets (-multi_key)
12# TEST	with various buffer sizes and verify the contents returned match
13# TEST	the results from a regular cursor get.
14# TEST
15# TEST	Then delete items to create a sparse database and make sure it
16# TEST	still works.  Test both -multi and -multi_key since they behave
17# TEST	differently.
18proc test103 { method {nentries 100} {start 4294967250} {tnum "103"} args} {
19	source ./include.tcl
20
21	set args [convert_args $method $args]
22	set omethod [convert_method $method]
23	puts "Test$tnum: $method ($args) Test of bulk get with wraparound."
24
25	if { [is_queueext $method] == 0 } {
26		puts "\tSkipping Test$tnum for method $method."
27		return
28	}
29
30	# Create the database and open the dictionary
31	set txnenv 0
32	set eindex [lsearch -exact $args "-env"]
33	#
34	# If we are using an env, then testfile should just be the db name.
35	# Otherwise it is the test directory and the name.
36	if { $eindex == -1 } {
37		set testfile $testdir/test$tnum.db
38		set env NULL
39	} else {
40		set testfile test$tnum.db
41		incr eindex
42		set env [lindex $args $eindex]
43		set txnenv [is_txnenv $env]
44		if { $txnenv == 1 } {
45			append args " -auto_commit "
46			#
47			# If we are using txns and running with the
48			# default, set the default down a bit.
49			#
50			if { $nentries == 10000 } {
51				set nentries 100
52			}
53		}
54		set testdir [get_home $env]
55	}
56
57	cleanup $testdir $env
58
59	set db [eval {berkdb_open_noerr \
60	     -create -mode 0644} $args $omethod $testfile]
61	error_check_good dbopen [is_valid_db $db] TRUE
62
63	# Find the pagesize so we can use it to size the buffer.
64	set stat [$db stat]
65	set pagesize [get_pagesize $stat]
66
67	set did [open $dict]
68
69	puts "\tTest$tnum.a: put/get loop"
70	set txn ""
71
72	# Here is the loop where we put each key/data pair
73	set count 0
74	set k [expr $start + 1]
75	while { [gets $did str] != -1 && $count < $nentries } {
76		#
77		# We cannot use 'incr' because it gets unhappy since
78		# expr above is using 64-bits.
79		set k [expr $k + 1]
80		#
81		# Detect if we're more than 32 bits now.  If so, wrap
82		# our key back to 1.
83		#
84		if { [expr $k > 0xffffffff] } {
85			set k 1
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 {$k [chop_data $method $str]}]
93		error_check_good db_put $ret 0
94		if { $txnenv == 1 } {
95			error_check_good txn [$t commit] 0
96		}
97		incr count
98	}
99	close $did
100
101	# Run tests in verbose mode for debugging.
102	set verbose 0
103
104	puts "\tTest$tnum.b: Bulk get with large buffer (retrieves all data)."
105	# Buffer is large enough that everything fits in a single get.
106	check_multi_recno $db [expr $pagesize * $nentries] multi_key $verbose
107
108	puts "\tTest$tnum.c: Bulk get with buffer = (2 x pagesize)."
109	# Buffer gets several items at a get, but not all.
110	check_multi_recno $db [expr $pagesize * 2] multi_key $verbose
111
112	# Skip tests if buffer would be smaller than allowed.
113	if { $pagesize >= 1024  } {
114		puts "\tTest$tnum.d: Bulk get with buffer = pagesize."
115		check_multi_recno $db $pagesize multi_key $verbose
116	}
117
118	if { $pagesize >= 2048 } {
119		puts "\tTest$tnum.e: Bulk get with buffer < pagesize\
120		    (returns EINVAL)."
121		catch {
122			check_multi_recno $db [expr $pagesize / 2] \
123			    multi_key $verbose
124		} res
125		error_check_good \
126		    bufsize_less_than_pagesize [is_substr $res "invalid"] 1
127	}
128
129	# For a sparsely populated database, test with both -multi_key and
130	# -multi.  In any sort of record numbered database, -multi does not
131	# return keys, so it returns all items.  -multi_key returns both keys
132	# and data so it skips deleted items.
133	puts "\tTest$tnum.f: Delete every 10th item to create sparse database."
134	if { $txnenv == 1 } {
135		set t [$env txn]
136		error_check_good txn [is_valid_txn $t $env] TRUE
137		set txn "-txn $t"
138	}
139	set curs [ eval {$db cursor} $txn]
140	error_check_good cursor [is_valid_cursor $curs $db] TRUE
141
142	set count 0
143	for { set kd [$curs get -first] } { $count < $nentries } \
144	    { set kd [$curs get -next] } {
145		if { [expr $count % 10 == 0] } {
146			error_check_good cdelete [$curs del] 0
147		}
148		incr count
149	}
150	error_check_good curs_close [$curs close] 0
151	if { $txnenv == 1 } {
152		error_check_good txn [$t commit] 0
153	}
154
155	puts "\tTest$tnum.g: Sparse database, large buffer, multi_key."
156	check_multi_recno $db [expr $pagesize * $nentries] multi_key $verbose
157	puts "\tTest$tnum.h: Sparse database, large buffer, multi."
158	check_multi_recno $db [expr $pagesize * $nentries] multi $verbose
159
160	puts "\tTest$tnum.i: \
161	    Sparse database, buffer = (2 x pagesize), multi_key."
162	check_multi_recno $db [expr $pagesize * 2] multi_key $verbose
163	puts "\tTest$tnum.j: Sparse database, buffer = (2 x pagesize), multi."
164	check_multi_recno $db [expr $pagesize * 2] multi $verbose
165
166	if { $pagesize >= 1024  } {
167		puts "\tTest$tnum.k: \
168		    Sparse database, buffer = pagesize, multi_key."
169		check_multi_recno $db $pagesize multi_key $verbose
170		puts "\tTest$tnum.k: Sparse database, buffer = pagesize, multi."
171		check_multi_recno $db $pagesize multi $verbose
172	}
173
174	error_check_good db_close [$db close] 0
175}
176
177# The proc check_multi_recno is a modification of the utility routine
178# check_multi_key specifically for recno methods.  We use this instead
179# check_multi, even with the -multi flag, because the check_multi utility
180# assumes that dups are being used which can't happen with record-based
181# methods.
182proc check_multi_recno { db size flag {verbose 0}} {
183	source ./include.tcl
184	set c [eval { $db cursor} ]
185	set m [eval { $db cursor} ]
186
187	set j 1
188
189	# Walk the database with -multi_key or -multi bulk get.
190	for {set d [$m get -first -$flag $size] } { [llength $d] != 0 } {
191	    set d [$m get -next -$flag $size] } {
192		if {$verbose == 1 } {
193			puts "FETCH $j"
194			incr j
195		}
196		# For each bulk get return, compare the results to what we
197		# get by walking the db with an ordinary cursor get.
198		for {set i 0} { $i < [llength $d] } { incr i } {
199			set kd [lindex $d $i]
200			set k [lindex $kd 0]
201			set data [lindex $kd 1]
202			set len [string length $data]
203
204			if {$verbose == 1 } {
205				puts ">> $k << >> $len << "
206			}
207			# If we hit a deleted item in -multi, skip over it.
208			if { $flag == "multi" && $len == 0 } {
209				continue
210			}
211
212			set check [$c get -next]
213			set cd [lindex $check 0]
214			set ck [lindex $cd 0]
215			set cdata [lindex $cd 1]
216
217			error_check_good key $k $ck
218			error_check_good data_len $len [string length $cdata]
219			error_check_good data $data $cdata
220		}
221	}
222}
223