1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2003,2008 Oracle.  All rights reserved.
4#
5# $Id: rep042.tcl,v 12.19 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	rep042
8# TEST	Concurrency with updates.
9# TEST
10# TEST 	Verify racing role changes and updates don't result in
11# TEST  pages with LSN 0,1.  Set up an environment that is master.
12# TEST  Spawn child process that does a delete, but using the
13# TEST  $env check so that it sleeps in the middle of the call.
14# TEST  Master downgrades and then sleeps as a client so that
15# TEST  child will run.  Verify child does not succeed (should
16# TEST  get read-only error) due to role change in the middle of
17# TEST  its call.
18proc rep042 { method { niter 10 } { tnum "042" } args } {
19
20	source ./include.tcl
21	if { $is_windows9x_test == 1 } {
22		puts "Skipping replication test on Win 9x platform."
23		return
24	}
25
26	# Valid for all access methods.
27	if { $checking_valid_methods } {
28		return "ALL"
29	}
30
31	set args [convert_args $method $args]
32	set logsets [create_logsets 2]
33
34	# Run the body of the test with and without recovery.
35	foreach r $test_recopts {
36		foreach l $logsets {
37			set logindex [lsearch -exact $l "in-memory"]
38			if { $r == "-recover" && $logindex != -1 } {
39				puts "Rep$tnum: Skipping\
40				    for in-memory logs with -recover."
41				continue
42			}
43
44			puts "Rep$tnum ($method $r):\
45			    Concurrency with updates."
46			puts "Rep$tnum: Master logs are [lindex $l 0]"
47			puts "Rep$tnum: Client logs are [lindex $l 1]"
48			rep042_sub $method $niter $tnum $l $r $args
49		}
50	}
51}
52
53proc rep042_sub { method niter tnum logset recargs largs } {
54	source ./include.tcl
55	global perm_response_list
56	global rep_verbose
57	global verbose_type
58
59	set verbargs ""
60	if { $rep_verbose == 1 } {
61		set verbargs " -verbose {$verbose_type on} "
62	}
63
64	env_cleanup $testdir
65	set omethod [convert_method $method]
66
67	replsetup $testdir/MSGQUEUEDIR
68
69	set masterdir $testdir/MASTERDIR
70	set clientdir $testdir/CLIENTDIR
71
72	file mkdir $masterdir
73	file mkdir $clientdir
74	set m_logtype [lindex $logset 0]
75	set c_logtype [lindex $logset 1]
76
77	# In-memory logs require a large log buffer, and cannot
78	# be used with -txn nosync.
79	set m_logargs [adjust_logargs $m_logtype]
80	set c_logargs [adjust_logargs $c_logtype]
81	set m_txnargs [adjust_txnargs $m_logtype]
82	set c_txnargs [adjust_txnargs $c_logtype]
83
84	# Open a master.
85	repladd 1
86	set ma_cmd "berkdb_env_noerr -create \
87	    -log_max 1000000 $m_txnargs $m_logargs $verbargs \
88	    -home $masterdir -rep_master -errpfx MASTER \
89	    -rep_transport \[list 1 replsend\]"
90	set masterenv [eval $ma_cmd $recargs]
91
92	# Open a client
93	repladd 2
94	set cl_cmd "berkdb_env_noerr -create -home $clientdir \
95	    $c_txnargs $c_logargs $verbargs -errpfx CLIENT -rep_client \
96	    -rep_transport \[list 2 replsend\]"
97	set clientenv [eval $cl_cmd $recargs]
98
99	# Bring the client online.
100	process_msgs "{$masterenv 1} {$clientenv 2}"
101
102	puts "\tRep$tnum.a: Create and populate database."
103	set dbname rep042.db
104	set db [eval "berkdb_open_noerr -create $omethod -auto_commit \
105	    -env $masterenv $largs $dbname"]
106	for { set i 1 } { $i < $niter } { incr i } {
107		set t [$masterenv txn]
108		error_check_good db_put \
109		    [eval $db put -txn $t $i [chop_data $method data$i]] 0
110		error_check_good txn_commit [$t commit] 0
111	}
112	process_msgs "{$masterenv 1} {$clientenv 2}"
113
114	set ops {del truncate}
115	foreach op $ops {
116		# Fork child process on client.  The child will do a delete.
117		set sleepval 4
118		set scrlog $testdir/repscript.log
119		puts "\tRep$tnum.b: Fork child process on client ($op)."
120		set pid [exec $tclsh_path $test_path/wrap.tcl \
121		    rep042script.tcl $scrlog \
122		    $masterdir $sleepval $dbname $op &]
123
124		# Wait for child process to start up.
125		while { 1 } {
126			if { [file exists $masterdir/marker.db] == 0  } {
127				tclsleep 1
128			} else {
129				tclsleep 1
130				break
131			}
132		}
133
134 		puts "\tRep$tnum.c: Downgrade during child $op."
135		error_check_good downgrade [$masterenv rep_start -client] 0
136
137		puts "\tRep$tnum.d: Waiting for child ..."
138		# Watch until the child is done.
139		watch_procs $pid 5
140		puts "\tRep$tnum.e: Upgrade to master again ..."
141		error_check_good upgrade [$masterenv rep_start -master] 0
142		set end [expr $niter * 2]
143		for { set i $niter } { $i <= $end } { incr i } {
144			set t [$masterenv txn]
145			error_check_good db_put \
146			    [eval $db put -txn $t $i [chop_data $method data$i]] 0
147			error_check_good txn_commit [$t commit] 0
148		}
149		process_msgs "{$masterenv 1} {$clientenv 2}"
150
151		# We expect to find the error "attempt to modify a read-only
152		# database."  If we don't, report what we did find as a failure.
153		set readonly_error [check_script $scrlog "read-only"]
154		if { $readonly_error != 1 } {
155			set errstrings [eval findfail $scrlog]
156			if { [llength $errstrings] > 0 } {
157				puts "FAIL: unexpected error(s)\
158				    found in file $scrlog:$errstrings"
159			}
160		}
161		fileremove -f $masterdir/marker.db
162	}
163
164	# Clean up.
165	error_check_good db_close [$db close] 0
166	error_check_good masterenv_close [$masterenv close] 0
167	error_check_good clientenv_close [$clientenv close] 0
168
169	replclose $testdir/MSGQUEUEDIR
170}
171
172proc check_script { log str } {
173	set ret 0
174	set res [catch {open $log} id]
175	if { $res != 0 } {
176		puts "FAIL: open of $log failed: $id"
177		# Return 0
178		return $ret
179	}
180	while { [gets $id val] != -1 } {
181#		puts "line: $val"
182		if { [is_substr $val $str] } {
183			set ret 1
184			break
185		}
186	}
187	close $id
188	return $ret
189}
190