1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 2006,2008 Oracle.  All rights reserved.
4#
5# $Id: rep065script.tcl,v 12.19 2008/04/14 14:29:39 sue Exp $
6#
7# rep065script - procs to use at each replication site in the
8# replication upgrade test.
9#
10# type: START, PROCMSGS, VERIFY
11# 	START starts up a replication site and performs an operation.
12#		the operations are:
13#		REPTEST runs the rep_test_upg procedure on the master.
14#		REPTEST_GET run a read-only test on a client.
15#		REPTEST_ELECT runs an election on the site.
16# 	PROCMSGS processes messages until none are left.
17#	VERIFY dumps the log and database contents.
18# role: master or client
19# op: operation to perform
20# envid: environment id number for use in replsend
21# allids: all env ids we need for sending
22# ctldir: controlling directory
23# mydir: directory where this participant runs
24# reputils_path: location of reputils.tcl
25
26proc rep065scr_elect { repenv oplist } {
27	set ver [lindex $oplist 1]
28	set pri [lindex $oplist 2]
29}
30
31proc rep065scr_reptest { repenv oplist markerdb } {
32
33	set method [lindex $oplist 1]
34	set niter [lindex $oplist 2]
35	set loop [lindex $oplist 3]
36	set start 0
37	puts "REPTEST: method $method, niter $niter, loop $loop"
38
39	for {set n 0} {$n < $loop} {incr n} {
40		puts "REPTEST: call rep_test_upg $n"
41		eval rep_test_upg $method $repenv NULL $niter $start $start 0 0
42		incr start $niter
43		tclsleep 3
44	}
45	#
46	# Sleep a bunch to help get the messages worked through.
47	#
48	tclsleep 10
49	puts "put DONE to marker"
50       	error_check_good marker_done [$markerdb put DONE DONE] 0
51       	error_check_good marker_sync [$markerdb sync] 0
52}
53
54proc rep065scr_repget { repenv oplist mydir markerfile } {
55	set dbname "$mydir/test.db"
56	set i 0
57	while { [file exists $dbname] == 0 } {
58		tclsleep 2
59		incr i
60		if { $i >= 15 && $i % 5 == 0 } {
61			puts "After $i seconds, no database exists."
62		}
63		if { $i > 180 } {
64			error "Database never created."
65		}
66	}
67	set loop 1
68	while { 1 } {
69		set markerdb [berkdb_open $markerfile]
70		error_check_good marker [is_valid_db $markerdb] TRUE
71		set kd [$markerdb get DONE]
72		error_check_good marker_close [$markerdb close] 0
73		if { [llength $kd] != 0 } {
74			break
75		}
76		set db [berkdb_open -env $repenv $dbname]
77		error_check_good dbopen [is_valid_db $db] TRUE
78		set dbc [$db cursor]
79		set i 0
80		error_check_good curs [is_valid_cursor $dbc $db] TRUE
81		for { set dbt [$dbc get -first ] } \
82		    { [llength $dbt] > 0 } \
83		    { set dbt [$dbc get -next] } {
84			incr i
85		}
86		error_check_good dbc_close [$dbc close] 0
87		error_check_good db_close [$db close] 0
88		puts "REPTEST_GET: after $loop loops: key count $i"
89		incr loop
90		tclsleep 2
91	}
92}
93proc rep065scr_starttest { role oplist envid msgdir mydir allids markerfile } {
94	global qtestdir
95	global util_path
96
97	puts "repladd_noenv $allids"
98	set qtestdir $msgdir
99	foreach id $allids {
100		repladd_noenv $id
101	}
102
103	set markerdb [berkdb_open -create -btree $markerfile]
104	error_check_good marker [is_valid_db $markerdb] TRUE
105	puts "set up env cmd"
106	set lockmax 40000
107	set logbuf [expr 16 * 1024]
108	set logmax [expr $logbuf * 4]
109	if { $role == "MASTER" } {
110		set rep_env_cmd "berkdb_env_noerr -create -home $mydir \
111		    -log_max $logmax -log_buffer $logbuf \
112		    -lock_max_objects $lockmax -lock_max_locks $lockmax \
113		    -errpfx MASTER -txn -rep_master \
114		    -rep_transport \[list $envid replsend_noenv\]"
115#		set rep_env_cmd "berkdb_env_noerr -create -home $mydir \
116#		    -log_max $logmax -log_buffer $logbuf \
117#		    -lock_max_objects $lockmax -lock_max_locks $lockmax \
118#		    -errpfx MASTER -txn -rep_master \
119#		    -verbose {rep on} -errfile /dev/stderr \
120#		    -rep_transport \[list $envid replsend_noenv\]"
121	} elseif { $role == "CLIENT" } {
122		set rep_env_cmd "berkdb_env_noerr -create -home $mydir \
123		    -log_max $logmax -log_buffer $logbuf \
124		    -lock_max_objects $lockmax -lock_max_locks $lockmax \
125		    -errpfx CLIENT -txn -rep_client \
126		    -rep_transport \[list $envid replsend_noenv\]"
127#		set rep_env_cmd "berkdb_env_noerr -create -home $mydir \
128#		    -log_max $logmax -log_buffer $logbuf \
129#		    -lock_max_objects $lockmax -lock_max_locks $lockmax \
130#		    -errpfx CLIENT -txn -rep_client \
131#		    -verbose {rep on} -errfile /dev/stderr \
132#		    -rep_transport \[list $envid replsend_noenv\]"
133	} else {
134		puts "FAIL: unrecognized replication role $role"
135		return
136	}
137
138	# Change directories to where this will run.
139	# !!!
140	# mydir is an absolute path of the form
141	# <path>/build_unix/TESTDIR/MASTERDIR or
142	# <path>/build_unix/TESTDIR/CLIENTDIR.0
143	#
144	# So we want to run relative to the build_unix directory
145	cd $mydir/../..
146
147	puts "open repenv $rep_env_cmd"
148	set repenv [eval $rep_env_cmd]
149	error_check_good repenv_open [is_valid_env $repenv] TRUE
150
151	puts "repenv is $repenv"
152	#
153	# Indicate that we're done starting up.  Sleep to let
154	# others do the same.
155	#
156	puts "put START$envid to marker"
157        error_check_good marker_done [$markerdb put START$envid START$envid] 0
158        error_check_good marker_sync [$markerdb sync] 0
159	puts "sleeping after marker"
160	tclsleep 3
161
162	# Here is where the real test starts.
163	#
164	# Different operations may have different args in their list.
165	# REPTEST: Args are method, niter, nloops
166	set op [lindex $oplist 0]
167	if { $op == "REPTEST" } {
168		#
169		# This test writes the marker, so close after it runs.
170		#
171		rep065scr_reptest $repenv $oplist $markerdb
172		error_check_good marker_close [$markerdb close] 0
173	}
174	if { $op == "REPTEST_GET" } {
175		#
176		# This test needs to poll the marker.  So close it now.
177		#
178		error_check_good marker_close [$markerdb close] 0
179		rep065scr_repget $repenv $oplist $mydir $markerfile
180	}
181	if { $op == "REP_ELECT" } {
182		#
183		# This test writes the marker, so close after it runs.
184		#
185		rep065scr_elect $repenv $oplist $markerdb
186	}
187	puts "Closing env"
188	$repenv mpool_sync
189	error_check_good envclose [$repenv close] 0
190
191}
192
193proc rep065scr_msgs { role envid msgdir mydir allids markerfile } {
194	global qtestdir
195
196	#
197	# The main test process will write the marker file when it
198	# has started and when it has completed.  We need to
199	# open/close the marker file because we are in a separate
200	# process from the writer and we cannot share an env because
201	# we might be a different BDB release version.
202	#
203	set markerdb [berkdb_open -create -btree $markerfile]
204	error_check_good marker [is_valid_db $markerdb] TRUE
205	set s [$markerdb get START$envid]
206	while { [llength $s] == 0 } {
207		error_check_good marker_close [$markerdb close] 0
208		tclsleep 1
209		set markerdb [berkdb_open $markerfile]
210		error_check_good marker [is_valid_db $markerdb] TRUE
211		set s [$markerdb get START$envid]
212	}
213
214	puts "repladd_noenv $allids"
215	set qtestdir $msgdir
216	foreach id $allids {
217		repladd_noenv $id
218	}
219
220	puts "set up env cmd"
221	if { $role == "MASTER" } {
222		set rep_env_cmd "berkdb_env_noerr -home $mydir \
223		    -errpfx MASTER -txn -rep_master \
224		    -rep_transport \[list $envid replsend_noenv\]"
225#		set rep_env_cmd "berkdb_env_noerr -home $mydir \
226#		    -errpfx MASTER -txn -rep_master \
227#		    -verbose {rep on} -errfile /dev/stderr \
228#		    -rep_transport \[list $envid replsend_noenv\]"
229	} elseif { $role == "CLIENT" } {
230		set rep_env_cmd "berkdb_env_noerr -home $mydir \
231		    -errpfx CLIENT -txn -rep_client \
232		    -rep_transport \[list $envid replsend_noenv\]"
233#		set rep_env_cmd "berkdb_env_noerr -home $mydir \
234#		    -errpfx CLIENT -txn -rep_client \
235#		    -verbose {rep on} -errfile /dev/stderr \
236#		    -rep_transport \[list $envid replsend_noenv\]"
237	} else {
238		puts "FAIL: unrecognized replication role $role"
239		return
240	}
241
242	# Change directories to where this will run.
243	cd $mydir
244
245	puts "open repenv $rep_env_cmd"
246	set repenv [eval $rep_env_cmd]
247	error_check_good repenv_open [is_valid_env $repenv] TRUE
248
249	set envlist "{$repenv $envid}"
250	puts "repenv is $repenv"
251	while { 1 } {
252		if { [llength [$markerdb get DONE]] != 0 } {
253			break
254		}
255		process_msgs $envlist 0 NONE NONE 1
256		error_check_good marker_close [$markerdb close] 0
257		set markerdb [berkdb_open $markerfile]
258		error_check_good marker [is_valid_db $markerdb] TRUE
259		tclsleep 1
260	}
261	#
262	# Process messages in case there are a few more stragglers.
263	# Just because the main test is done doesn't mean that all
264	# the messaging is done.  Loop for messages as long as
265	# progress is being made.
266	#
267	set nummsg 1
268	while { $nummsg != 0 } {
269		process_msgs $envlist 0 NONE NONE 1
270		tclsleep 1
271		# First look at messages from us
272		set nummsg [replmsglen_noenv $envid from]
273		puts "Still have $nummsg not yet processed by others"
274	}
275	error_check_good marker_close [$markerdb close] 0
276	replclear_noenv $envid from
277	tclsleep 1
278	replclear_noenv $envid
279	$repenv mpool_sync
280	error_check_good envclose [$repenv close] 0
281}
282
283proc rep065scr_verify { oplist mydir id } {
284	global util_path
285
286	set rep_env_cmd "berkdb_env_noerr -home $mydir -txn \
287	    -rep_transport \[list $id replnoop\]"
288
289	# Change directories to where this will run.
290	# !!!
291	# mydir is an absolute path of the form
292	# <path>/build_unix/TESTDIR/MASTERDIR or
293	# <path>/build_unix/TESTDIR/CLIENTDIR.0
294	#
295	# So we want to run relative to the build_unix directory
296	cd $mydir/../..
297
298	foreach op $oplist {
299		set repenv [eval $rep_env_cmd]
300		error_check_good env_open [is_valid_env $repenv] TRUE
301		if { $op == "DB" } {
302			set dbname "$mydir/test.db"
303			set db [berkdb_open -env $repenv -rdonly $dbname]
304			error_check_good dbopen [is_valid_db $db] TRUE
305			set txn ""
306			set method [$db get_type]
307			if { [is_record_based $method] == 1 } {
308				dump_file $db $txn $mydir/VERIFY/dbdump \
309				    rep_test_upg.recno.check
310			} else {
311				dump_file $db $txn $mydir/VERIFY/dbdump \
312				    rep_test_upg.check
313			}
314			error_check_good dbclose [$db close] 0
315		}
316		if { $op == "LOG" } {
317			set lgstat [$repenv log_stat]
318			set lgfile [stat_field $repenv log_stat "Current log file number"]
319			set lgoff [stat_field $repenv log_stat "Current log file offset"]
320			puts "Current LSN: $lgfile $lgoff"
321			set f [open $mydir/VERIFY/loglsn w]
322			puts $f $lgfile
323			puts $f $lgoff
324			close $f
325
326			set stat [catch {eval exec $util_path/db_printlog \
327			    -h $mydir > $mydir/VERIFY/prlog} result]
328			if { $stat != 0 } {
329				puts "PRINTLOG: $result"
330			}
331			error_check_good stat_prlog $stat 0
332		}
333		error_check_good envclose [$repenv close] 0
334	}
335	#
336	# Run recovery locally so that any later upgrades are ready
337	# to be upgraded.
338	#
339	set stat [catch {eval exec $util_path/db_recover -h $mydir} result]
340	if { $stat != 0 } {
341		puts "RECOVERY: $result"
342	}
343	error_check_good stat_rec $stat 0
344
345}
346
347set usage "upgradescript type role op envid allids ctldir mydir reputils_path"
348
349# Verify usage
350if { $argc != 8 } {
351	puts stderr "Argc $argc, argv $argv"
352	puts stderr "FAIL:[timestamp] Usage: $usage"
353	exit
354}
355
356# Initialize arguments
357set type [ lindex $argv 0 ]
358set role [ lindex $argv 1 ]
359set op [ lindex $argv 2 ]
360set envid [ lindex $argv 3 ]
361set allids [ lindex $argv 4 ]
362set ctldir [ lindex $argv 5 ]
363set mydir [ lindex $argv 6 ]
364set reputils_path [ lindex $argv 7 ]
365
366set histdir $mydir/../..
367puts "Histdir $histdir"
368
369set msgtestdir $ctldir/TESTDIR
370
371global env
372cd $histdir
373set stat [catch {eval exec ./db_printlog -V} result]
374if { $stat != 0 } {
375	set env(LD_LIBRARY_PATH) ":$histdir:$histdir/.libs:$env(LD_LIBRARY_PATH)"
376}
377source ./include.tcl
378source $test_path/test.tcl
379
380# The global variable noenv_messaging must be set after sourcing
381# test.tcl or its value will be wrong.
382global noenv_messaging
383set noenv_messaging 1
384
385set is_repchild 1
386puts "Did args. now source reputils"
387source $reputils_path/reputils.tcl
388source $reputils_path/reputilsnoenv.tcl
389
390set markerdir $msgtestdir/MARKER
391set markerfile $markerdir/marker.db
392
393puts "Calling proc for type $type"
394if { $type == "START" } {
395	rep065scr_starttest $role $op $envid $msgtestdir $mydir $allids $markerfile
396} elseif { $type == "PROCMSGS" } {
397	rep065scr_msgs $role $envid $msgtestdir $mydir $allids $markerfile
398} elseif { $type == "VERIFY" } {
399	file mkdir $mydir/VERIFY
400	rep065scr_verify $op $mydir $envid
401} else {
402	puts "FAIL: unknown type $type"
403	return
404}
405