1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2003-2009 Oracle.  All rights reserved.
4#
5# $Id$
6#
7# TEST	txn011
8# TEST	Test durable and non-durable txns.
9# TEST	Test a mixed env (with both durable and non-durable
10# TEST	dbs), then a purely non-durable env.  Make sure commit
11# TEST	and abort work, and that only the log records we
12# TEST	expect are written.
13# TEST	Test that we can't get a durable handle on an open ND
14# TEST	database, or vice versa.  Test that all subdb's
15# TEST	must be of the same type (D or ND).
16proc txn011 { {ntxns 100} } {
17	source ./include.tcl
18	global util_path
19
20	foreach envtype { "" "-private" } {
21		puts "Txn011: Non-durable txns ($envtype)."
22		env_cleanup $testdir
23
24		puts "\tTxn011.a: Persistent env recovery with -log_inmemory"
25		set lbuf [expr 8 * [expr 1024 * 1024]]
26		set env_cmd "berkdb_env -create \
27		    -home $testdir -txn -log_inmemory -log_buffer $lbuf"
28		set ndenv [eval $env_cmd $envtype]
29		set db [berkdb_open -create -auto_commit \
30		    -btree -env $ndenv -notdurable test.db]
31		check_log_records $testdir
32		error_check_good db_close [$db close] 0
33		error_check_good ndenv_close [$ndenv close] 0
34
35		# Run recovery with -e to retain environment.
36		set stat [catch {exec $util_path/db_recover -e -h $testdir} ret]
37		error_check_good db_printlog $stat 0
38
39		# Rejoin env and make sure that the db is still there.
40		set ndenv [berkdb_env -home $testdir]
41		set db [berkdb_open -auto_commit -env $ndenv test.db]
42		error_check_good db_close [$db close] 0
43		error_check_good ndenv_close [$ndenv close] 0
44		env_cleanup $testdir
45
46		# Start with a new env for the next test.
47		set ndenv [eval $env_cmd]
48		error_check_good env_open [is_valid_env $ndenv] TRUE
49
50		# Open/create the database.
51		set testfile notdurable.db
52		set db [eval berkdb_open -create \
53		    -auto_commit -env $ndenv -notdurable -btree $testfile]
54		error_check_good dbopen [is_valid_db $db] TRUE
55
56		puts "\tTxn011.b: Abort txns in in-memory logging env."
57		txn011_runtxns $ntxns $db $ndenv abort
58		# Make sure there is nothing in the db.
59		txn011_check_empty $db $ndenv
60
61		puts "\tTxn011.c: Commit txns in in-memory logging env."
62		txn011_runtxns $ntxns $db $ndenv commit
63
64		# Make sure we haven't written any inappropriate log records
65		check_log_records $testdir
66
67		# Clean up non-durable env tests.
68		error_check_good db_close [$db close] 0
69		error_check_good ndenv_close [$ndenv close] 0
70		env_cleanup $testdir
71
72		puts "\tTxn011.d: Set up mixed durable/non-durable test."
73		# Open/create the mixed environment
74		set mixed_env_cmd "berkdb_env_noerr -create \
75			-home $testdir -txn -log_inmemory -log_buffer $lbuf"
76		set env [eval $mixed_env_cmd]
77		error_check_good env_open [is_valid_env $env] TRUE
78		check_log_records $testdir
79
80		# Open/create the non-durable database
81		set nondurfile nondurable.db
82		set ndb [berkdb_open_noerr -create\
83		    -auto_commit -env $env -btree -notdurable $nondurfile]
84		error_check_good dbopen [is_valid_db $ndb] TRUE
85		check_log_records $testdir
86
87		puts "\tTxn011.e: Abort txns in non-durable db."
88		txn011_runtxns $ntxns $ndb $env abort
89		# Make sure there is nothing in the db.
90		txn011_check_empty $ndb $env
91		check_log_records $testdir
92
93		puts "\tTxn011.f: Commit txns in non-durable db."
94		txn011_runtxns $ntxns $ndb $env commit
95		check_log_records $testdir
96
97		# Open/create the durable database
98		set durfile durable.db
99		set ddb [eval berkdb_open_noerr \
100		   -create -auto_commit -env $env -btree $durfile]
101		error_check_good dbopen [is_valid_db $ddb] TRUE
102
103		# Try to get a not-durable handle on the durable db.
104		puts "\tTxn011.g: Try to get a not-durable handle on\
105		    an open durable db."
106		set errormsg "Cannot open DURABLE and NOT DURABLE handles"
107		catch {berkdb_open_noerr \
108		    -auto_commit -env $env -notdurable $durfile} res
109		error_check_good handle_error1 [is_substr $res $errormsg] 1
110		error_check_good ddb_close [$ddb close] 0
111
112		# Try to get a not-durable handle when reopening the durable
113		# db (this should work).
114		set db [berkdb_open_noerr \
115		    -auto_commit -env $env -notdurable $durfile]
116		error_check_good db_reopen [is_valid_db $db] TRUE
117		error_check_good db_close [$db close] 0
118
119		# Now reopen as durable for the remainder of the test.
120		set ddb [berkdb_open_noerr \
121		    -auto_commit -env $env -btree $durfile]
122		error_check_good dbopen [is_valid_db $ddb] TRUE
123
124		puts "\tTxn011.h: Abort txns in durable db."
125		# Add items to db in several txns but abort every one.
126		txn011_runtxns $ntxns $ddb $env abort
127		# Make sure there is nothing in the db.
128		txn011_check_empty $ddb $env
129
130		puts "\tTxn011.i: Commit txns in durable db."
131		txn011_runtxns $ntxns $ddb $env commit
132
133		puts "\tTxn011.j: Subdbs must all be durable or all not durable."
134		# Ask for -notdurable on durable db/subdb
135		set sdb1 [eval berkdb_open_noerr -create -auto_commit \
136		    -env $env -btree testfile1.db subdb1]
137		catch {set sdb2 [eval berkdb_open_noerr -create -auto_commit \
138		    -env $env -btree -notdurable testfile1.db subdb2]} res
139		error_check_good same_type_subdb1 [is_substr $res $errormsg] 1
140		error_check_good sdb1_close [$sdb1 close] 0
141
142		# Ask for durable on notdurable db/subdb
143		set sdb3 [eval berkdb_open_noerr -create -auto_commit \
144		    -env $env -btree -notdurable testfile2.db subdb3]
145		catch {set sdb4 [eval berkdb_open_noerr -create -auto_commit \
146		    -env $env -btree testfile2.db subdb4]} res
147		error_check_good same_type_subdb2 [is_substr $res $errormsg] 1
148		error_check_good sdb3_close [$sdb3 close] 0
149
150		puts "\tTxn011.k: Try to get a durable handle on a\
151		    not-durable db."
152		# Try to get a durable handle on a not-durable database,
153		# while open.  This should fail, but getting a durable handle
154		# when re-opening should work.
155		catch {berkdb_open_noerr -auto_commit -env $env $nondurfile} res
156		error_check_good handle_error [is_substr $res $errormsg] 1
157		error_check_good ndb_close [$ndb close] 0
158
159		set ndb [berkdb_open_noerr -auto_commit -env $env $nondurfile]
160		error_check_good ndb_reopen [is_valid_db $ndb] TRUE
161		error_check_good ndb_close [$ndb close] 0
162
163		# Clean up mixed env.
164		error_check_good ddb_close [$ddb close] 0
165		error_check_good env_close [$env close] 0
166	}
167}
168
169proc txn011_runtxns { ntxns db env end } {
170	source ./include.tcl
171
172	set did [open $dict]
173	set i 0
174	while { [gets $did str] != -1 && $i < $ntxns } {
175		set txn [$env txn]
176		error_check_good txn_begin [is_valid_txn $txn $env] TRUE
177
178		error_check_good db_put_txn [$db put -txn $txn $i $str] 0
179		error_check_good txn_$end [$txn $end] 0
180		incr i
181	}
182	close $did
183}
184
185# Verify that a database is empty
186proc txn011_check_empty { db env } {
187	# Start a transaction
188	set t [$env txn]
189	error_check_good txn [is_valid_txn $t $env] TRUE
190	set txn "-txn $t"
191
192	# If a cursor get -first returns nothing, the db is empty.
193	set dbc [eval {$db cursor} $txn]
194	error_check_good db_cursor [is_substr $dbc $db] 1
195	set ret [$dbc get -first]
196	error_check_good get_on_empty [string length $ret] 0
197	error_check_good dbc_close [$dbc close] 0
198
199	# End transaction
200	error_check_good txn [$t commit] 0
201}
202
203# Some log records are still produced when we run create in a
204# non-durable db in a regular env.  Just make sure we don't see
205# any unexpected types.
206proc check_log_records { dir } {
207	global util_path
208
209	set tmpfile $dir/printlog.out
210	set stat [catch {exec $util_path/db_printlog -h $dir > $tmpfile} ret]
211	error_check_good db_printlog $stat 0
212
213	set f [open $tmpfile r]
214	while { [gets $f record] >= 0 } {
215		set r [regexp {\[[^\]]*\]\[[^\]]*\]([^\:]*)\:} $record whl name]
216		if { $r == 1 && [string match *_debug $name] != 1 && \
217		    [string match __txn_regop $name] != 1 && \
218		    [string match __txn_child $name] != 1 } {
219			puts "FAIL: unexpected log record $name found"
220		}
221	}
222	close $f
223	fileremove $tmpfile
224}
225