1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2005,2008 Oracle.  All rights reserved.
4#
5# $Id: si008.tcl,v 12.10 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	si008
8# TEST	Secondary index put/delete with lorder test
9# TEST
10# TEST  This test is the same as si001 except that we
11# TEST	create the secondaries with different byte orders:
12# TEST  one native, one swapped.
13
14proc si008 { methods {nentries 10} {tnum "008"} args } {
15	source ./include.tcl
16	global dict nsecondaries
17
18	# Primary method/args.
19	set pmethod [lindex $methods 0]
20	set pargs [convert_args $pmethod $args]
21	if [big_endian] {
22		set nativeargs " -lorder 4321"
23		set swappedargs " -lorder 1234"
24	} else {
25		set swappedargs " -lorder 4321"
26		set nativeargs " -lorder 1234"
27	}
28	set argtypes "{$nativeargs} {$swappedargs}"
29	set pomethod [convert_method $pmethod]
30
31	# Renumbering recno databases can't be used as primaries.
32	if { [is_rrecno $pmethod] == 1 } {
33		puts "Skipping si$tnum for method $pmethod"
34		return
35	}
36
37	# Method/args for all the secondaries.  If only one method
38	# was specified, assume the same method (for btree or hash)
39	# and a standard number of secondaries.  If primary is not
40	# btree or hash, force secondaries to be one btree, one hash.
41	set methods [lrange $methods 1 end]
42	if { [llength $methods] == 0 } {
43		for { set i 0 } { $i < $nsecondaries } { incr i } {
44			if { [is_btree $pmethod] || [is_hash $pmethod] } {
45				lappend methods $pmethod
46			} else {
47				if { [expr $i % 2] == 0 } {
48					lappend methods "-btree"
49				} else {
50					lappend methods "-hash"
51				}
52			}
53		}
54	}
55
56	set argses [convert_argses $methods $args]
57	set omethods [convert_methods $methods]
58
59	# If we are given an env, use it.  Otherwise, open one.
60	set eindex [lsearch -exact $args "-env"]
61	if { $eindex == -1 } {
62		env_cleanup $testdir
63		set cacheargs " -cachesize {0 1048576 1} "
64		set env [eval berkdb_env -create $cacheargs -home $testdir]
65		error_check_good env_open [is_valid_env $env] TRUE
66	} else {
67		incr eindex
68		set env [lindex $args $eindex]
69		set envflags [$env get_open_flags]
70		if { [lsearch -exact $envflags "-thread"] != -1 &&\
71			[is_queue $pmethod] == 1 } {
72			puts "Skipping si$tnum for threaded env"
73			return
74		}
75		set testdir [get_home $env]
76	}
77
78	set pname "primary$tnum.db"
79	set snamebase "secondary$tnum"
80
81	foreach pbyteargs $argtypes {
82		if { $pbyteargs == $nativeargs } {
83			puts "Si$tnum: Using native\
84			    byteorder $nativeargs for primary."
85		} else {
86			puts "Si$tnum: Using swapped\
87			    byteorder $swappedargs for primary."
88		}
89
90		puts "si$tnum\
91		    \{\[ list $pmethod $methods \]\} $nentries"
92		cleanup $testdir $env
93
94		# Open primary.
95		set pdb [eval {berkdb_open -create -env} $env \
96		    $pomethod $pargs $pbyteargs $pname]
97		error_check_good primary_open [is_valid_db $pdb] TRUE
98
99		# Open and associate the secondaries
100		set sdbs {}
101		for { set i 0 } { $i < [llength $omethods] } { incr i } {
102			if { [expr $i % 2]  == 0 } {
103				set sbyteargs $nativeargs
104			} else {
105				set sbyteargs $swappedargs
106			}
107
108			if { $sbyteargs == $nativeargs } {
109				puts "Si$tnum: Using native byteorder\
110				    $nativeargs for secondary $i."
111			} else {
112				puts "Si$tnum: Using swapped byteorder\
113				    $swappedargs for secondary $i."
114			}
115
116			set sdb [eval {berkdb_open -create -env} $env \
117			    [lindex $omethods $i] [lindex $argses $i] \
118			    $sbyteargs $snamebase.$i.db]
119			error_check_good second_open($i) [is_valid_db $sdb] TRUE
120
121			error_check_good db_associate($i) \
122			    [$pdb associate [callback_n $i] $sdb] 0
123			lappend sdbs $sdb
124		}
125
126		puts "\tSi$tnum.a: Put loop"
127		set did [open $dict]
128		for { set n 0 } { [gets $did str] != -1 && $n < $nentries } { incr n } {
129			if { [is_record_based $pmethod] == 1 } {
130				set key [expr $n + 1]
131				set datum $str
132			} else {
133				set key $str
134				gets $did datum
135			}
136			set keys($n) $key
137			set data($n) [pad_data $pmethod $datum]
138
139			set ret [eval {$pdb put}\
140			    {$key [chop_data $pmethod $datum]}]
141			error_check_good put($n) $ret 0
142		}
143		close $did
144
145		check_secondaries $pdb $sdbs $nentries keys data "Si$tnum.a"
146
147		puts "\tSi$tnum.b: Put/overwrite loop"
148		for { set n 0 } { $n < $nentries } { incr n } {
149			set newd $data($n).$keys($n)
150			set ret [eval {$pdb put}\
151			    {$keys($n) [chop_data $pmethod $newd]}]
152			error_check_good put_overwrite($n) $ret 0
153			set data($n) [pad_data $pmethod $newd]
154		}
155		check_secondaries\
156		    $pdb $sdbs $nentries keys data "Si$tnum.b"
157
158		# Delete the second half of the entries through
159		# the primary.  We do the second half so we can
160		# just pass keys(0 ... n/2) to check_secondaries.
161		set half [expr $nentries / 2]
162		puts "\tSi$tnum.c:\
163		    Primary delete loop: deleting $half entries"
164		for { set n $half } { $n < $nentries } { incr n } {
165			set ret [$pdb del $keys($n)]
166			error_check_good pdel($n) $ret 0
167		}
168		check_secondaries\
169		    $pdb $sdbs $half keys data "Si$tnum.c"
170
171		# Delete half of what's left through
172		# the first secondary.
173		set quar [expr $half / 2]
174		puts "\tSi$tnum.d:\
175		    Secondary delete loop: deleting $quar entries"
176		set sdb [lindex $sdbs 0]
177		set callback [callback_n 0]
178		for { set n $quar } { $n < $half } { incr n } {
179			set skey [$callback $keys($n)\
180			    [pad_data $pmethod $data($n)]]
181			set ret [$sdb del $skey]
182			error_check_good sdel($n) $ret 0
183		}
184		check_secondaries\
185		    $pdb $sdbs $quar keys data "Si$tnum.d"
186		set left $quar
187
188		# For queue and recno only, test append, adding back
189		# a quarter of the original number of entries.
190		if { [is_record_based $pmethod] == 1 } {
191			set did [open $dict]
192			puts "\tSi$tnum.e:\
193			    Append loop: append $quar entries"
194			for { set n 0 } { $n < $nentries } { incr n } {
195				# Skip over dictionary entries we've
196				# already used.
197				gets $did str
198			}
199			for { set n $quar } \
200			    { [gets $did str] != -1 && $n < $half } \
201			    { incr n } {
202				set key [expr $n + 1]
203				set datum $str
204				set keys($n) $key
205				set data($n) [pad_data $pmethod $datum]
206
207				set ret [eval {$pdb put} \
208				    {$key [chop_data $pmethod $datum]}]
209				error_check_good put($n) $ret 0
210			}
211			close $did
212
213			check_secondaries\
214			    $pdb $sdbs $half keys data "Si$tnum.e"
215			set left $half
216		}
217
218		puts "\tSi$tnum.f:\
219		    Truncate primary, check secondaries are empty."
220		error_check_good truncate [$pdb truncate] $left
221		foreach sdb $sdbs {
222			set scursor [$sdb cursor]
223			error_check_good\
224			    db_cursor [is_substr $scursor $sdb] 1
225			set ret [$scursor get -first]
226			error_check_good\
227			    sec_empty [string length $ret] 0
228			error_check_good cursor_close [$scursor close] 0
229		}
230
231
232		puts "\tSi$tnum.g: Closing/disassociating primary first"
233		error_check_good primary_close [$pdb close] 0
234		foreach sdb $sdbs {
235			error_check_good secondary_close [$sdb close] 0
236		}
237
238		# Don't close the env if this test was given one.
239		# Skip the test of truncating the secondary since
240		# we can't close and reopen the outside env.
241		if { $eindex == -1 } {
242			error_check_good env_close [$env close] 0
243
244			# Reopen with _noerr for test of
245			# truncate secondary.
246			puts "\tSi$tnum.h:\
247			    Truncate secondary (should fail)"
248
249			set env [berkdb_env_noerr\
250			    -create -home $testdir]
251			error_check_good\
252			    env_open [is_valid_env $env] TRUE
253
254			set pdb [eval {berkdb_open_noerr -create -env}\
255			    $env $pomethod $pargs $pname]
256			set sdb [eval {berkdb_open_noerr -create -env}\
257			    $env [lindex $omethods 0]\
258			    [lindex $argses 0] $snamebase.0.db ]
259			$pdb associate [callback_n 0] $sdb
260
261			set ret [catch {$sdb truncate} ret]
262			error_check_good trunc_secondary $ret 1
263
264			error_check_good primary_close [$pdb close] 0
265			error_check_good secondary_close [$sdb close] 0
266		}
267	}
268
269	# If this test made the last env, close it.
270	if { $eindex == -1 } {
271		error_check_good env_close [$env close] 0
272	}
273}
274