summaryrefslogtreecommitdiff
path: root/db/test/test089.tcl
blob: 303a9ce81245b3556f23c3b59ae1d2b1e40481ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# See the file LICENSE for redistribution information.
#
# Copyright (c) 1996-2006
#	Oracle Corporation.  All rights reserved.
#
# $Id: test089.tcl,v 12.4 2006/08/24 14:46:41 bostic Exp $
#
# TEST	test089
# TEST	Concurrent Data Store test (CDB)
# TEST
# TEST	Enhanced CDB testing to test off-page dups, cursor dups and
# TEST	cursor operations like c_del then c_get.
proc test089 { method {nentries 1000} args } {
	global datastr
	global encrypt
	source ./include.tcl

	#
	# If we are using an env, then skip this test.  It needs its own.
	set eindex [lsearch -exact $args "-env"]
	if { $eindex != -1 } {
		incr eindex
		set env [lindex $args $eindex]
		puts "Test089 skipping for env $env"
		return
	}
	set encargs ""
	set args [convert_args $method $args]
	set oargs [split_encargs $args encargs]
	set omethod [convert_method $method]

	puts "Test089: ($oargs) $method CDB Test cursor/dup operations"

	# Process arguments
	# Create the database and open the dictionary
	set testfile test089.db
	set testfile1 test089a.db

	env_cleanup $testdir

	set env [eval {berkdb_env -create -cdb} $encargs -home $testdir]
	error_check_good dbenv [is_valid_env $env] TRUE

	set db [eval {berkdb_open -env $env -create \
	    -mode 0644 $omethod} $oargs {$testfile}]
	error_check_good dbopen [is_valid_db $db] TRUE

	set db1 [eval {berkdb_open -env $env -create \
	    -mode 0644 $omethod} $oargs {$testfile1}]
	error_check_good dbopen [is_valid_db $db1] TRUE

	set pflags ""
	set gflags ""
	set txn ""
	set count 0

	# Here is the loop where we put each key/data pair
	puts "\tTest089.a: Put loop"
	set did [open $dict]
	while { [gets $did str] != -1 && $count < $nentries } {
		if { [is_record_based $method] == 1 } {
			set key [expr $count + 1]
		} else {
			set key $str
		}
		set ret [eval {$db put} \
		    $txn $pflags {$key [chop_data $method $datastr]}]
		error_check_good put:$db $ret 0
		set ret [eval {$db1 put} \
		    $txn $pflags {$key [chop_data $method $datastr]}]
		error_check_good put:$db1 $ret 0
		incr count
	}
	close $did
	error_check_good close:$db [$db close] 0
	error_check_good close:$db1 [$db1 close] 0

	# Database is created, now set up environment

	# Remove old mpools and Open/create the lock and mpool regions
	error_check_good env:close:$env [$env close] 0
	set ret [eval {berkdb envremove} $encargs -home $testdir]
	error_check_good env_remove $ret 0

	set env [eval {berkdb_env_noerr -create -cdb} $encargs -home $testdir]
	error_check_good dbenv [is_valid_widget $env env] TRUE

	puts "\tTest089.b: CDB cursor dups"

	set db1 [eval {berkdb_open_noerr -env $env -create \
	    -mode 0644 $omethod} $oargs {$testfile1}]
	error_check_good dbopen [is_valid_db $db1] TRUE

	# Create a read-only cursor and make sure we can't write with it.
	set dbcr [$db1 cursor]
	error_check_good dbcursor [is_valid_cursor $dbcr $db1] TRUE
	set ret [$dbcr get -first]
	catch { [$dbcr put -current data] } ret
	error_check_good is_read_only \
	    [is_substr $ret "Write attempted on read-only cursor"] 1
	error_check_good dbcr_close [$dbcr close] 0

	# Create a write cursor and duplicate it.
	set dbcw [$db1 cursor -update]
	error_check_good dbcursor [is_valid_cursor $dbcw $db1] TRUE
	set dup_dbcw [$dbcw dup]
	error_check_good dup_write_cursor [is_valid_cursor $dup_dbcw $db1] TRUE

	# Position both cursors at get -first.  They should find the same data.
	set get_first [$dbcw get -first]
	set get_first_dup [$dup_dbcw get -first]
	error_check_good dup_read $get_first $get_first_dup

	# Test that the write cursors can both write and that they
	# read each other's writes correctly.  First write reversed
	# datastr with original cursor and read with dup cursor.
	error_check_good put_current_orig \
	    [$dbcw put -current [chop_data $method [reverse $datastr]]] 0
	set reversed [$dup_dbcw get -current]
	error_check_good check_with_dup [lindex [lindex $reversed 0] 1] \
	    [pad_data $method [reverse $datastr]]

	# Write forward datastr with dup cursor and read with original.
	error_check_good put_current_dup \
	    [$dup_dbcw put -current [chop_data $method $datastr]] 0
	set forward [$dbcw get -current]
	error_check_good check_with_orig $forward $get_first

	error_check_good dbcw_close [$dbcw close] 0
	error_check_good dup_dbcw_close [$dup_dbcw close] 0

	# This tests the failure found in #1923
	puts "\tTest089.c: Test delete then get"

	set dbc [$db1 cursor -update]
	error_check_good dbcursor [is_valid_cursor $dbc $db1] TRUE

	for {set kd [$dbc get -first] } { [llength $kd] != 0 } \
	    {set kd [$dbc get -next] } {
		error_check_good dbcdel [$dbc del] 0
	}
	error_check_good dbc_close [$dbc close] 0
	error_check_good db_close [$db1 close] 0
	error_check_good env_close [$env close] 0

	if { [is_btree $method] != 1 } {
		puts "Skipping rest of test089 for $method method."
		return
	}
	set pgindex [lsearch -exact $args "-pagesize"]
	if { $pgindex != -1 } {
		puts "Skipping rest of test089 for specific pagesizes"
		return
	}
	append oargs " -dup "
	test089_dup $testdir $encargs $oargs $omethod $nentries
	append oargs " -dupsort "
	test089_dup $testdir $encargs $oargs $omethod $nentries
}

proc test089_dup { testdir encargs oargs method nentries } {
	env_cleanup $testdir
	set env [eval {berkdb_env -create -cdb} $encargs -home $testdir]
	error_check_good dbenv [is_valid_env $env] TRUE

	#
	# Set pagesize small to generate lots of off-page dups
	#
	set page 512
	set nkeys 5
	set data "data"
	set key "test089_key"
	set testfile test089.db
	puts "\tTest089.d: CDB ($oargs) off-page dups"
	set oflags "-env $env -create -mode 0644 $oargs $method"
	set db [eval {berkdb_open} -pagesize $page $oflags $testfile]
	error_check_good dbopen [is_valid_db $db] TRUE

	puts "\tTest089.e: Fill page with $nkeys keys, with $nentries dups"
	for { set k 0 } { $k < $nkeys } { incr k } {
		for { set i 0 } { $i < $nentries } { incr i } {
			set ret [$db put $key$k $i$data$k]
			error_check_good dbput $ret 0
		}
	}

	# Verify we have off-page duplicates
	set stat [$db stat]
	error_check_bad stat:offpage [is_substr $stat "{{Internal pages} 0}"] 1

	# This tests the failure reported in #6950.  Skip for -dupsort.
	puts "\tTest089.f: Clear locks for duped off-page dup cursors."
	if { [is_substr $oargs dupsort] != 1 } {
		# Create a read cursor, put it on an off-page dup.
		set dbcr [$db cursor]
		error_check_good dbcr [is_valid_cursor $dbcr $db] TRUE
		set offpage [$dbcr get -get_both test089_key4 900data4]
		error_check_bad offpage [llength $offpage] 0

		# Create a write cursor, put it on an off-page dup.
		set dbcw [$db cursor -update]
		error_check_good dbcw [is_valid_cursor $dbcw $db] TRUE
		set offpage [$dbcw get -get_both test089_key3 900data3]
		error_check_bad offpage [llength $offpage] 0

		# Add a new item using the write cursor, then close the cursor.
		error_check_good add_dup [$dbcw put -after $data] 0
		error_check_good close_dbcw [$dbcw close] 0

		# Get next dup with read cursor, then close the cursor.
		set nextdup [$dbcr get -nextdup]
		error_check_good close_dbcr [$dbcr close] 0
	}

	puts "\tTest089.g: CDB duplicate write cursors with off-page dups"
	# Create a write cursor and duplicate it.
	set dbcw [$db cursor -update]
	error_check_good dbcursor [is_valid_cursor $dbcw $db] TRUE
	set dup_dbcw [$dbcw dup]
	error_check_good dup_write_cursor [is_valid_cursor $dup_dbcw $db] TRUE

	# Position both cursors at get -first.  They should find the same data.
	set get_first [$dbcw get -first]
	set get_first_dup [$dup_dbcw get -first]
	error_check_good dup_read $get_first $get_first_dup

	# Test with -after and -before.  Skip for -dupsort.
	if { [is_substr $oargs dupsort] != 1 } {
		# Original and duplicate cursors both point to first item.
		# Do a put -before of new string with original cursor,
		# and a put -after of new string with duplicate cursor.
		set newdata "newdata"
		error_check_good put_before [$dbcw put -before $newdata] 0
		error_check_good put_after [$dup_dbcw put -after $newdata] 0

		# Now walk forward with original cursor ...
		set first [$dbcw get -first]
		error_check_good check_first [lindex [lindex $first 0] 1] $newdata
		set next1 [$dbcw get -next]
		error_check_good check_next1 $next1 $get_first
		set next2 [$dbcw get -next]
		error_check_good check_next2 [lindex [lindex $next2 0] 1] $newdata

		# ... and backward with duplicate cursor.
		set current [$dup_dbcw get -current]
		error_check_good check_current [lindex [lindex $current 0] 1] $newdata
		set prev1 [$dup_dbcw get -prev]
		error_check_good check_prev1 $prev1 $get_first
		set prev2 [$dup_dbcw get -prev]
		error_check_good check_prev2 [lindex [lindex $prev2 0] 1] $newdata
	}

	puts "\tTest089.h: test delete then get of off-page dups"
	for {set kd [$dbcw get -first] } { [llength $kd] != 0 } \
	    {set kd [$dbcw get -next] } {
		error_check_good dbcdel [$dbcw del] 0
	}

	error_check_good dbcw_close [$dbcw close] 0
	error_check_good dup_dbcw_close [$dup_dbcw close] 0

	error_check_good db_close [$db close] 0
	error_check_good env_close [$env close] 0
}