1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1996,2008 Oracle.  All rights reserved.
4#
5# $Id: test092.tcl,v 12.7 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	test092
8# TEST	Test of DB_DIRTY_READ [#3395]
9# TEST
10# TEST	We set up a database with nentries in it.  We then open the
11# TEST	database read-only twice.  One with dirty reads and one without.
12# TEST	We open the database for writing and update some entries in it.
13# TEST	Then read those new entries via db->get (clean and dirty), and
14# TEST	via cursors (clean and dirty).
15proc test092 { method {nentries 1000} args } {
16	source ./include.tcl
17	#
18	# If we are using an env, then skip this test.  It needs its own.
19	set eindex [lsearch -exact $args "-env"]
20	if { $eindex != -1 } {
21		incr eindex
22		set env [lindex $args $eindex]
23		puts "Test092 skipping for env $env"
24		return
25	}
26	set args [convert_args $method $args]
27	set encargs ""
28	set args [split_encargs $args encargs]
29	set omethod [convert_method $method]
30
31	puts "Test092: Dirty Read Test $method $nentries"
32
33	# Create the database and open the dictionary
34	set testfile test092.db
35	set t1 $testdir/t1
36	set t2 $testdir/t2
37	set t3 $testdir/t3
38
39	env_cleanup $testdir
40
41	set lmax [expr $nentries * 2]
42	set lomax [expr $nentries * 2]
43	set env [eval {berkdb_env -create -txn} $encargs -home $testdir \
44	    -lock_max_locks $lmax -lock_max_objects $lomax]
45	error_check_good dbenv [is_valid_env $env] TRUE
46
47	set db [eval {berkdb_open -env $env -create \
48	    -mode 0644 $omethod} $args {$testfile}]
49	error_check_good dbopen [is_valid_db $db] TRUE
50
51	# Here is the loop where we put each key/data pair.
52	# Key is entry, data is entry also.
53	puts "\tTest092.a: put loop"
54	set count 0
55	set did [open $dict]
56	while { [gets $did str] != -1 && $count < $nentries } {
57		if { [is_record_based $method] == 1 } {
58			global kvals
59
60			set key [expr $count + 1]
61			set kvals($key) [pad_data $method $str]
62		} else {
63			set key $str
64		}
65		set ret [eval {$db put} {$key [chop_data $method $str]}]
66		error_check_good put:$db $ret 0
67		incr count
68	}
69	close $did
70	error_check_good close:$db [$db close] 0
71
72	puts "\tTest092.b: Opening all the handles"
73	#
74	# Open all of our handles.
75	# We need:
76	# 1.  Our main txn (t).
77	# 2.  A txn that can read dirty data (tdr).
78	# 3.  A db handle for writing via txn (dbtxn).
79	# 4.  A db handle for clean data (dbcl).
80	# 5.  A db handle for dirty data (dbdr).
81	# 6.  A cursor handle for dirty txn data (clean db handle using
82	#    the dirty txn handle on the cursor call) (dbccl1).
83	# 7.  A cursor handle for dirty data (dirty on get call) (dbcdr0).
84	# 8.  A cursor handle for dirty data (dirty on cursor call) (dbcdr1).
85	set t [$env txn]
86	error_check_good txnbegin [is_valid_txn $t $env] TRUE
87
88	set tdr [$env txn -read_uncommitted]
89	error_check_good txnbegin:dr [is_valid_txn $tdr $env] TRUE
90	set dbtxn [eval {berkdb_open -auto_commit -env $env -read_uncommitted \
91	    -mode 0644 $omethod} {$testfile}]
92	error_check_good dbopen:dbtxn [is_valid_db $dbtxn] TRUE
93
94	set dbcl [eval {berkdb_open -auto_commit -env $env \
95	    -rdonly -mode 0644 $omethod} {$testfile}]
96	error_check_good dbopen:dbcl [is_valid_db $dbcl] TRUE
97
98	set dbdr [eval {berkdb_open -auto_commit -env $env -read_uncommitted \
99	    -rdonly -mode 0644 $omethod} {$testfile}]
100	error_check_good dbopen:dbdr [is_valid_db $dbdr] TRUE
101
102	set dbccl [$dbcl cursor -txn $tdr]
103	error_check_good dbcurs:dbcl [is_valid_cursor $dbccl $dbcl] TRUE
104
105	set dbcdr0 [$dbdr cursor]
106	error_check_good dbcurs:dbdr0 [is_valid_cursor $dbcdr0 $dbdr] TRUE
107
108	set dbcdr1 [$dbdr cursor -read_uncommitted]
109	error_check_good dbcurs:dbdr1 [is_valid_cursor $dbcdr1 $dbdr] TRUE
110
111	# Test that $db stat can use -read_uncommitted flag.
112	puts "\tTest092.c: Smoke test for db_stat -txn -read_uncommitted"
113	if { [catch \
114	    {set statret [$dbcl stat -txn $t -read_uncommitted]} res] } {
115		puts "FAIL: db_stat -txn -read_uncommitted returned $res"
116	}
117
118	#
119	# Now that we have all of our handles, change all the data in there
120	# to be the key and data the same, but data is capitalized.
121	puts "\tTest092.d: put/get data within a txn"
122	set gflags ""
123	if { [is_record_based $method] == 1 } {
124		set checkfunc test092dr_recno.check
125		append gflags " -recno"
126	} else {
127		set checkfunc test092dr.check
128	}
129	set count 0
130	set did [open $dict]
131	while { [gets $did str] != -1 && $count < $nentries } {
132		if { [is_record_based $method] == 1 } {
133			set key [expr $count + 1]
134		} else {
135			set key $str
136		}
137		set ustr [string toupper $str]
138		set clret [list [list $key [pad_data $method $str]]]
139		set drret [list [list $key [pad_data $method $ustr]]]
140		#
141		# Put the data in the txn.
142		#
143		set ret [eval {$dbtxn put} -txn $t \
144		    {$key [chop_data $method $ustr]}]
145		error_check_good put:$dbtxn $ret 0
146
147		#
148		# Now get the data using the different db handles and
149		# make sure it is dirty or clean data.
150		#
151		# Using the dirty txn should show us dirty data
152		set ret [eval {$dbcl get -txn $tdr} $gflags {$key}]
153		error_check_good dbdr2:get $ret $drret
154
155		set ret [eval {$dbdr get -read_uncommitted} $gflags {$key}]
156		error_check_good dbdr1:get $ret $drret
157
158		set ret [eval {$dbdr get -txn $tdr} $gflags {$key}]
159		error_check_good dbdr2:get $ret $drret
160
161		incr count
162	}
163	close $did
164
165	puts "\tTest092.e: Check dirty data using dirty txn and clean db/cursor"
166	dump_file_walk $dbccl $t1 $checkfunc "-first" "-next"
167
168	puts "\tTest092.f: Check dirty data using -read_uncommitted cget flag"
169	dump_file_walk \
170	    $dbcdr0 $t2 $checkfunc "-first" "-next" "-read_uncommitted"
171
172	puts "\tTest092.g: Check dirty data using -read_uncommitted cursor"
173	dump_file_walk $dbcdr1 $t3 $checkfunc "-first" "-next"
174
175	#
176	# We must close these before aborting the real txn
177	# because they all hold read locks on the pages.
178	#
179	error_check_good dbccl:close [$dbccl close] 0
180	error_check_good dbcdr0:close [$dbcdr0 close] 0
181	error_check_good dbcdr1:close [$dbcdr1 close] 0
182
183	#
184	# Now abort the modifying transaction and rerun the data checks.
185	#
186	puts "\tTest092.h: Aborting the write-txn"
187	error_check_good txnabort [$t abort] 0
188
189	set dbccl [$dbcl cursor -txn $tdr]
190	error_check_good dbcurs:dbcl [is_valid_cursor $dbccl $dbcl] TRUE
191
192	set dbcdr0 [$dbdr cursor]
193	error_check_good dbcurs:dbdr0 [is_valid_cursor $dbcdr0 $dbdr] TRUE
194
195	set dbcdr1 [$dbdr cursor -read_uncommitted]
196	error_check_good dbcurs:dbdr1 [is_valid_cursor $dbcdr1 $dbdr] TRUE
197
198	if { [is_record_based $method] == 1 } {
199		set checkfunc test092cl_recno.check
200	} else {
201		set checkfunc test092cl.check
202	}
203	puts "\tTest092.i: Check clean data using -read_uncommitted cget flag"
204	dump_file_walk $dbccl $t1 $checkfunc "-first" "-next"
205
206	puts "\tTest092.j: Check clean data using -read_uncommitted cget flag"
207	dump_file_walk \
208	    $dbcdr0 $t2 $checkfunc "-first" "-next" "-read_uncommitted"
209
210	puts "\tTest092.k: Check clean data using -read_uncommitted cursor"
211	dump_file_walk $dbcdr1 $t3 $checkfunc "-first" "-next"
212
213	# Clean up our handles
214	error_check_good dbccl:close [$dbccl close] 0
215	error_check_good tdrcommit [$tdr commit] 0
216	error_check_good dbcdr0:close [$dbcdr0 close] 0
217	error_check_good dbcdr1:close [$dbcdr1 close] 0
218	error_check_good dbclose [$dbcl close] 0
219	error_check_good dbclose [$dbdr close] 0
220	error_check_good dbclose [$dbtxn close] 0
221	error_check_good envclose [$env close] 0
222}
223
224# Check functions for test092; keys and data are identical
225# Clean checks mean keys and data are identical.
226# Dirty checks mean data are uppercase versions of keys.
227proc test092cl.check { key data } {
228	error_check_good "key/data mismatch" $key $data
229}
230
231proc test092cl_recno.check { key data } {
232	global kvals
233
234	error_check_good key"$key"_exists [info exists kvals($key)] 1
235	error_check_good "key/data mismatch, key $key" $data $kvals($key)
236}
237
238proc test092dr.check { key data } {
239	error_check_good "key/data mismatch" $key [string tolower $data]
240}
241
242proc test092dr_recno.check { key data } {
243	global kvals
244
245	error_check_good key"$key"_exists [info exists kvals($key)] 1
246	error_check_good "key/data mismatch, key $key" $data \
247	    [string toupper $kvals($key)]
248}
249
250