summaryrefslogtreecommitdiff
path: root/test/tcl/rep091.tcl
blob: 36fa18caeab80561ee1c1e8291d6e976f29de827 (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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
# See the file LICENSE for redistribution information.
#
# Copyright (c) 2010, 2012 Oracle and/or its affiliates.  All rights reserved.
#
# TEST	rep091
# TEST	Read-your-writes consistency.
# TEST	Write transactions at the master, and then call the txn_applied()
# TEST	method to see whether the client has received and applied them yet.
#
proc rep091 { method { niter 20 } { tnum "091" } args } {
	source ./include.tcl
	global databases_in_memory
	global repfiles_in_memory

	# Skip for all methods except btree.
	if { $checking_valid_methods } {
		set test_methods { btree }
		return $test_methods
	}
	if { [is_btree $method] == 0 } {
		puts "Rep091: Skipping for method $method."
		return
	}

	# Set up for on-disk or in-memory databases and make dbname match 
	# the one assigned in rep_test.
	if { $databases_in_memory == 1 } {
		set dbname { "" "test.db" }
		set msg "using named in-memory databases"
	} else {
		set dbname "test.db"
		set msg "using on-disk databases"
	}

	# For this test it's important to test both ways, so for now run both
	# under our control.  Later, when the containing test infrastructure for
	# doing this automatically is more fully developed, we can remove this
	# loop and just let the infrastructure handle it.
	# 
	set orig $repfiles_in_memory
	foreach repfiles_in_memory {0 1} {

		if { $repfiles_in_memory } {
			set msg2 "and in-memory replication files"
		} else {
			set msg2 "and on-disk replication files"
		}
		puts "Rep$tnum ($method $args): Test of\
		    read-your-writes consistency $msg $msg2."
		
		rep091a_sub $method $niter $tnum no $dbname $args
		rep091a_sub $method $niter $tnum yes $dbname $args
		rep091b_sub $method $niter $tnum $dbname $args
		rep091c_sub $method $niter $tnum no $dbname $args
		rep091c_sub $method $niter $tnum yes $dbname $args
		rep091d_sub $method $niter $tnum no $dbname $args
		rep091d_sub $method $niter $tnum yes $dbname $args
		rep091e_sub $method $niter $tnum $dbname $args
		if { $repfiles_in_memory } {
			rep091f_sub $method $niter $tnum $dbname $args
		}
	}

	# Restore original setting, in case any other tests are going to be run
	# after this one.
	# 
	set repfiles_in_memory $orig
}

proc rep091a_sub { method niter tnum future_gen dbname largs } {
	global rep_verbose
	global testdir
	global verbose_type
	global repfiles_in_memory

	puts -nonewline "Rep$tnum: read-your-writes consistency, basic test"
	if { $future_gen } {
		puts ", with extra gen cycle."
	} else {
		puts "."
	}

	set verbargs ""
	if { $rep_verbose == 1 } {
		set verbargs " -verbose {$verbose_type on} "
	}

	set repmemargs ""
	if { $repfiles_in_memory } {
		set repmemargs "-rep_inmem_files "
	}

	env_cleanup $testdir

	replsetup $testdir/MSGQUEUEDIR

	set masterdir $testdir/MASTERDIR
	set clientdir $testdir/CLIENTDIR

	file mkdir $masterdir
	file mkdir $clientdir

	puts "\tRep$tnum.a: Create master and client."
	repladd 1
	set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \
	    $repmemargs \
	    $verbargs -home $masterdir -rep_transport \[list 1 replsend\]"
	set masterenv [eval $ma_envcmd -rep_master]

	repladd 2
	set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \
	    $repmemargs \
	    $verbargs -home $clientdir -rep_transport \[list 2 replsend\]"
	set clientenv [eval $cl_envcmd -rep_client]

	set envlist "{$masterenv 1} {$clientenv 2}"
	process_msgs $envlist

	if { $future_gen } {
		# Cycle the gen an extra time, so that the client sees not only
		# a future transaction, but a future gen.  Restart the master as
		# a client first, and communicate with the surviving other
		# client, to make sure the master realizes the correct gen.  We
		# can get away without doing this in the normal case, but when
		# repfiles are in memory the master otherwise starts over from
		# gen 0, leading to quite a mess.
		# 
		$masterenv close
		set masterenv [eval $ma_envcmd -rep_client -recover]
		set envlist "{$masterenv 1} {$clientenv 2}"
		process_msgs $envlist
		
		$masterenv rep_start -master
	}

	set start 0
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter

	puts "\tRep$tnum.b: Write txn and get its commit token."
	set omethod [convert_method $method]
	set dbargs [convert_args $method $largs]
	set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
		-create $omethod $dbargs $dbname ]
	set txn [$masterenv txn -token]
	$db put -txn $txn "key1" "data1"
	set token [$txn commit]

# binary scan $token IIIII r1 r2 r3 r4 r5
# puts "the token value is $r1 $r2 $r3 $r4 $r5"

	# For the most part, we're interested in checking txn_applied at
	# clients.  But it's also supposed to work in a degenerate, simple
	# manner at the master.
	#
	error_check_good applied_at_master [$masterenv txn_applied $token] 0

	# While we're at it, verify that if we don't ask for the commit token,
	# the result of [$env commit] is just a plain "0".  (This is more of a
	# sanity check on the Tcl API, to help us believe that the rest of this
	# test is valid.)
	# 
	set txn [$masterenv txn]
	$db put -txn $txn "other key" "any data"
	set result [$txn commit]
	error_check_good commit_no_token $result 0

	$db close

	puts "\tRep$tnum.c: Check the applied status of the transaction at the client."

	# Before processing messages, the client will not have heard of the
	# transaction yet.  But afterwards it should.  Check it once with no
	# timeout (default 0), and again with a timeout specified to do a simple
	# test of waiting.  (Multi-thread waiting tests will be done
	# separately.)
	#
	set result [$clientenv txn_applied $token]
	error_check_good not_applied [is_substr $result DB_TIMEOUT] 1

	set start [clock seconds]
	set result [$clientenv txn_applied -timeout 10000000 $token]
	set duration [expr [clock seconds] - $start]
	error_check_good not_yet_applied [expr $duration >= 10] 1

	process_msgs $envlist
	error_check_good txn_applied [$clientenv txn_applied $token] 0

	# "Empty" transactions are not really interesting either, but again
	# they're supposed to be allowed:
	#
	set txn [$masterenv txn -token]
	set token [$txn commit]
	set result [$masterenv txn_applied $token]
	error_check_good empty_txn [is_substr $result DB_KEYEMPTY] 1
	set result [$clientenv txn_applied $token]
	error_check_good empty_txn2 [is_substr $result DB_KEYEMPTY] 1

	# Check a few simple invalid cases.
	#
	error_check_bad client_token [catch {$clientenv txn -token} result] 0
	error_check_good cl_tok_msg [is_substr $result "invalid arg"] 1
	set txn [$masterenv txn]
	error_check_bad child_token \
	    [catch {$masterenv txn -token -parent $txn} result] 0
	error_check_good parent_tok_msg [is_substr $result "invalid arg"] 1

	$txn abort
	$clientenv close
	$masterenv close

	replclose $testdir/MSGQUEUEDIR
}

# Verify that an LSN history database appears correctly at a client even if the
# client is created via a hot backup (instead of internal init).  Sites "A" and
# "B" alternate the master role, in order to facilitate accumulating a history
# of gen changes (especially in the in-mem case, where otherwise our LSN history
# database would be lost each time we restarted the master).  The "CLIENT2" site
# will be the one to be initialized via hot backup.
# 
proc rep091b_sub { method niter tnum dbname largs } {
	global rep_verbose
	global testdir
	global verbose_type
	global util_path
	global repfiles_in_memory

	puts "Rep$tnum: read-your-writes consistency, hot backup."

	set verbargs ""
	if { $rep_verbose == 1 } {
		set verbargs " -verbose {$verbose_type on} "
	}

	set repmemargs ""
	if { $repfiles_in_memory } {
		set repmemargs "-rep_inmem_files "
	}

	env_cleanup $testdir

	replsetup $testdir/MSGQUEUEDIR

	set dira $testdir/DIRA
	set dirb $testdir/DIRB
	set clientdir2 $testdir/CLIENTDIR2

	file mkdir $dira
	file mkdir $dirb
	file mkdir $clientdir2

	repladd 1
	set envcmd_a "berkdb_env_noerr -create -txn -errpfx SITE_A \
	    $repmemargs \
	    $verbargs -home $dira -rep_transport \[list 1 replsend\]"
	set masterenv [eval $envcmd_a -rep_master]

	repladd 2
	set envcmd_b "berkdb_env_noerr -create -txn -errpfx SITE_B \
	    $repmemargs \
	    $verbargs -home $dirb -rep_transport \[list 2 replsend\]"
	set clientenv [eval $envcmd_b -rep_client]

	set envlist "{$masterenv 1} {$clientenv 2}"
	process_msgs $envlist

	set start 0

	# Swap master and client role, some arbitrary number of times, in order
	# to change the generation number, before writing our transaction of
	# interest.
	# 
	set count 2
	for { set i 0 } { $i < $count } { incr i } {
		eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
		incr start $niter
		process_msgs $envlist

		set tmp $masterenv
		set masterenv $clientenv
		set clientenv $tmp
		$clientenv rep_start -client
		$masterenv rep_start -master
		process_msgs $envlist
	}

	set omethod [convert_method $method]
	set dbargs [convert_args $method $largs]
	set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$masterenv txn -token]
	$db put -txn $txn "some key" "some data"
	set token [$txn commit]

	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	process_msgs $envlist

	# Cycle the master gen a few more times, in order to force the token gen
	# not to be at the top of the history.  Again, the count is arbitrary.
	# 
	$db close
	set count 3
	for { set i 0 } { $i < $count } { incr i } {
		set tmp $masterenv
		set masterenv $clientenv
		set clientenv $tmp
		$clientenv rep_start -client
		$masterenv rep_start -master
		process_msgs $envlist

		eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
		incr start $niter
		process_msgs $envlist
	}

	# Note that the choice of which existing directory ("a" or "b") we use
	# as the source of the copy doesn't matter.
	# 
	exec $util_path/db_hotbackup -h $dira -b $clientdir2

	set count 2
	for { set i 0 } { $i < $count } { incr i } {
		set tmp $masterenv
		set masterenv $clientenv
		set clientenv $tmp
		$clientenv rep_start -client
		$masterenv rep_start -master
		process_msgs $envlist

		eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
		incr start $niter
		process_msgs $envlist
	}

	# Create a second transaction, after a few more master gen changes, and
	# get its token too.
	# 
	set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$masterenv txn -token]
	$db put -txn $txn "other key" "different data"
	set token2 [$txn commit]

	# Start the new client, by running "catastrophic" recovery on the
	# hot-backup files.
	# 
	exec $util_path/db_recover -c -h $clientdir2
	repladd 3
	set cl2_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT2 \
	    $repmemargs \
	    $verbargs -home $clientdir2 -rep_transport \[list 3 replsend\]"
	set clientenv2 [eval $cl2_envcmd -rep_client]
	$clientenv2 rep_config {autoinit off}

	# Before syncing with the master, we should be able to confirm the first
	# transaction, but not the second one, because the hot backup should
	# include an (old) copy of the LSN history database.
	#
	if {$repfiles_in_memory} {
		set result [$clientenv2 txn_applied $token]
		error_check_good still_waiting [is_substr $result DB_TIMEOUT] 1
		set result2 [$clientenv2 txn_applied $token2]
		error_check_good not_yet_applied [is_substr $result2 DB_TIMEOUT] 1
	} else {
		error_check_good txn_applied [$clientenv2 txn_applied $token] 0
		set result2 [$clientenv2 txn_applied $token2]
		error_check_good not_yet_applied [is_substr $result2 DB_NOTFOUND] 1
	}

	# Sync with master, and this time token2 should be there.
	# 
	lappend envlist [list $clientenv2 3]
	process_msgs $envlist
	error_check_good txn_applied2 [$clientenv2 txn_applied $token2] 0

	$db close
	$clientenv2 close
	$clientenv close
	$masterenv close

	replclose $testdir/MSGQUEUEDIR
}

# Test detection of rollbacks.
# 
proc rep091c_sub { method niter tnum future_gen dbname largs } {
	global rep_verbose
	global testdir
	global verbose_type
	global repfiles_in_memory

	puts "Rep$tnum: read-your-writes consistency, rollbacks."

	set verbargs ""
	if { $rep_verbose == 1 } {
		set verbargs " -verbose {$verbose_type on} "
	}

	set repmemargs ""
	if { $repfiles_in_memory } {
		set repmemargs "-rep_inmem_files "
	}

	env_cleanup $testdir

	replsetup $testdir/MSGQUEUEDIR

	set masterdir $testdir/MASTERDIR
	set clientdir $testdir/CLIENTDIR
	set clientdir2 $testdir/CLIENTDIR2

	file mkdir $masterdir
	file mkdir $clientdir
	file mkdir $clientdir2

	puts "\tRep$tnum.a: Create a group of three."
	repladd 1
	set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \
	    $repmemargs \
	    $verbargs -home $masterdir -rep_transport \[list 1 replsend\]"
	set masterenv [eval $ma_envcmd -rep_master]

	repladd 2
	set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \
	    $repmemargs \
	    $verbargs -home $clientdir -rep_transport \[list 2 replsend\]"
	set clientenv [eval $cl_envcmd -rep_client]

	repladd 3
	set cl2_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT2 \
	    $repmemargs \
	    $verbargs -home $clientdir2 -rep_transport \[list 3 replsend\]"
	set clientenv2 [eval $cl2_envcmd -rep_client]

	set envlist "{$masterenv 1} {$clientenv 2} {$clientenv2 3}"
	process_msgs $envlist

	set start 0
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	process_msgs $envlist

	# If desired, test the case where the token has a "future" gen, by
	# bumping of the gen a few times after cutting off the disconnected
	# client.
	# 
	if { $future_gen } {
		for { set count 3 } { $count > 0 } { incr count -1 } {
			$masterenv close
			set masterenv [eval $ma_envcmd -rep_master -recover]
			eval rep_test $method $masterenv NULL \
			    $niter $start $start 0 $largs
			incr start $niter
		}
		set envlist "{$masterenv 1} {$clientenv 2} {$clientenv2 3}"
	}

	# Write some more transactions, taking a token for one of them, but
	# prevent one of the clients from seeing any of them.
	# 
	puts "\tRep$tnum.b: Write transactions, and get token."
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	set omethod [convert_method $method]
	set dbargs [convert_args $method $largs]
	set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$masterenv txn -token]
	$db put -txn $txn "some key" "some data"
	set token [$txn commit]
	$db close
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	replclear 2
	process_msgs $envlist

	puts "\tRep$tnum.c: Switch master, forcing a rollback."
	$masterenv close
# 	$clientenv rep_start -master
	$clientenv rep_start -client; # 
	set envlist "{$clientenv 2} {$clientenv2 3}"; # 
	process_msgs $envlist;			      # 
	$clientenv rep_start -master;		      # 
	eval rep_test $method $clientenv NULL $niter $start $start 0 $largs
	incr start $niter
	replclear 1
# 	set envlist "{$clientenv 2} {$clientenv2 3}"
	process_msgs $envlist

	puts "\tRep$tnum.d: Check txn_applied at client and at (new) master."
	set result [$clientenv2 txn_applied $token]
	error_check_good rolled_back [is_substr $result DB_NOTFOUND] 1

	set result [$clientenv txn_applied $token]
	error_check_good rolled_back2 [is_substr $result DB_NOTFOUND] 1

	$clientenv close
	$clientenv2 close
	replclose $testdir/MSGQUEUEDIR
}

# Test envid check.  Simulate a network partition: two masters proceed at the
# same gen, in the same LSN range.  The envid would be the only way we would
# know that a transaction from the disconnected master is not correctly applied
# at a client in the other partition.
# 
proc rep091d_sub { method niter tnum extra_gen dbname largs } {
	global rep_verbose
	global testdir
	global verbose_type
	global repfiles_in_memory

	puts -nonewline "Rep$tnum: read-your-writes consistency, partition"
	if { $extra_gen } {
		puts ", with extra gen."
	} else {
		puts "."
	}

	set verbargs ""
	if { $rep_verbose == 1 } {
		set verbargs " -verbose {$verbose_type on} "
	}

	set repmemargs ""
	if { $repfiles_in_memory } {
		set repmemargs "-rep_inmem_files "
	}

	env_cleanup $testdir

	replsetup $testdir/MSGQUEUEDIR

	set masterdir $testdir/MASTERDIR
	set clientdir $testdir/CLIENTDIR
	set clientdir2 $testdir/CLIENTDIR2

	file mkdir $masterdir
	file mkdir $clientdir
	file mkdir $clientdir2

	puts "\tRep$tnum.a: Create a group of three."
	repladd 1
	set ma_envcmd "berkdb_env_noerr -create -txn -errpfx MASTER \
	    $repmemargs \
	    $verbargs -home $masterdir -rep_transport \[list 1 replsend\]"
	set masterenv [eval $ma_envcmd -rep_master]

	repladd 2
	set cl_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT \
	    $repmemargs \
	    $verbargs -home $clientdir -rep_transport \[list 2 replsend\]"
	set clientenv [eval $cl_envcmd -rep_client]

	repladd 3
	set cl2_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT2 \
	    $repmemargs \
	    $verbargs -home $clientdir2 -rep_transport \[list 3 replsend\]"
	set clientenv2 [eval $cl2_envcmd -rep_client]

	set envlist "{$masterenv 1} {$clientenv 2} {$clientenv2 3}"
	process_msgs $envlist

	set start 0
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	process_msgs $envlist

	# Bounce master and client1.  Then when they come back up, pretend
	# client1 is disconnected, and somehow decides to act as a master (an
	# application not using elections, obviously).  Note that we must
	# replclear appropriately in both directions.
	# 
	$masterenv close
	$clientenv close
	set masterenv [eval $ma_envcmd -rep_master -recover]
	replclear 2
	set clientenv [eval $cl_envcmd -rep_master -recover]
	replclear 1
	replclear 3
	set envlist "{$masterenv 1} {$clientenv2 3}"

	puts "\tRep$tnum.b: Run identical series of txns at two masters."
	set orig_start $start
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	set omethod [convert_method $method]
	set dbargs [convert_args $method $largs]
	set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$masterenv txn]
	$db put -txn $txn "some key" "some data"
	$txn commit
	$db close
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	replclear 2
	process_msgs $envlist

	set start $orig_start
	eval rep_test $method $clientenv NULL $niter $start $start 0 $largs
	incr start $niter
	set db [eval berkdb_open_noerr -env $clientenv -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$clientenv txn -token]
	$db put -txn $txn "some key" "some data"
	set token [$txn commit]
	$db close
	eval rep_test $method $clientenv NULL $niter $start $start 0 $largs
	incr start $niter
	replclear 1
	replclear 3

	if { $extra_gen } {
		$masterenv close
		set masterenv [eval $ma_envcmd -rep_master -recover]
		set envlist "{$masterenv 1} {$clientenv2 3}"
		eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
		replclear 2
		process_msgs $envlist
	}

	puts "\tRep$tnum.c: Check txn_applied."
	set result [$clientenv2 txn_applied $token]
	error_check_good not_found [is_substr $result DB_NOTFOUND] 1

	$clientenv close
	$clientenv2 close
	$masterenv close
	replclose $testdir/MSGQUEUEDIR
}

# Test the simplified, degenerate behavior of a non-replication environment: a
# valid transaction is always considered applied, unless it disappears in a
# backup/restore.
# 
proc rep091e_sub { method niter tnum dbname largs } {
	global testdir
	global util_path

	set backupdir "$testdir/backup"
	file mkdir $backupdir

	puts "Rep$tnum: read-your-writes consistency, non-rep env."
	env_cleanup $testdir

	set dir $testdir
	set envcmd "berkdb_env_noerr -create -txn -home $dir"
	set env [eval $envcmd]

	set start 0
	eval rep_test $method $env NULL $niter $start $start 0 $largs
	incr start $niter

	exec $util_path/db_hotbackup -h $testdir -b $backupdir

	set omethod [convert_method $method]
	set dbargs [convert_args $method $largs]
	set db [eval berkdb_open_noerr -env $env -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$env txn -token]
	$db put -txn $txn "some key" "some data"
	set token [$txn commit]
	$db close

	eval rep_test $method $env NULL $niter $start $start 0 $largs
	incr start $niter

	error_check_good applied [$env txn_applied $token] 0
	$env close
	
	set envcmd "berkdb_env_noerr -create -txn -home $backupdir -recover_fatal"
	set env [eval $envcmd]
	set result [$env txn_applied $token]
	error_check_good restored [is_substr $result DB_NOTFOUND] 1
	$env close
}

# Check proper behavior of txn_applied() at a client before in-mem DB's have
# been materialized.  This is only relevant when repfiles_in_memory, so skip it
# in the default case.  Sites "A" and "B" will take turns being master, and
# CLIENT2 will be the one whose behavior is under test.
# 
proc rep091f_sub { method niter tnum dbname largs } {
	global rep_verbose
	global testdir
	global verbose_type
	global util_path
	global repfiles_in_memory

	if { $repfiles_in_memory } {
		set repmemargs "-rep_inmem_files "
		puts "Rep$tnum: read-your-writes consistency, missing in-mem DB."
	} else {
		puts "Rep$tnum: skipping missing in-mem DB test."
		return
	}

	set verbargs ""
	if { $rep_verbose == 1 } {
		set verbargs " -verbose {$verbose_type on} "
	}

	env_cleanup $testdir

	replsetup $testdir/MSGQUEUEDIR

	set dira $testdir/DIRA
	set dirb $testdir/DIRB
	set clientdir2 $testdir/CLIENTDIR2

	file mkdir $dira
	file mkdir $dirb
	file mkdir $clientdir2

	repladd 1
	set envcmd_a "berkdb_env_noerr -create -txn -errpfx SITE_A \
	    $repmemargs \
	    $verbargs -home $dira -rep_transport \[list 1 replsend\]"
	set masterenv [eval $envcmd_a -rep_master]

	repladd 2
	set envcmd_b "berkdb_env_noerr -create -txn -errpfx SITE_B \
	    $repmemargs \
	    $verbargs -home $dirb -rep_transport \[list 2 replsend\]"
	set clientenv [eval $envcmd_b -rep_client]

	repladd 3
	set cl2_envcmd "berkdb_env_noerr -create -txn -errpfx CLIENT2 \
	    $repmemargs \
	    $verbargs -home $clientdir2 -rep_transport \[list 3 replsend\]"
	set clientenv2 [eval $cl2_envcmd -rep_client]

	set envlist "{$masterenv 1} {$clientenv 2} {$clientenv2 3}"
	process_msgs $envlist

	set start 0
	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter

	# Write the transaction of interest in gen 1.
	# 
	set omethod [convert_method $method]
	set dbargs [convert_args $method $largs]
	set db [eval berkdb_open_noerr -env $masterenv -auto_commit \
		 $omethod $dbargs $dbname ]
	set txn [$masterenv txn -token]
	$db put -txn $txn "some key" "some data"
	set token [$txn commit]
	$db close

	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	process_msgs $envlist

	set tmp $masterenv
	set masterenv $clientenv
	set clientenv $tmp
	$clientenv rep_start -client
	$masterenv rep_start -master
	process_msgs $envlist

	eval rep_test $method $masterenv NULL $niter $start $start 0 $largs
	incr start $niter
	process_msgs $envlist
	
	# Bounce the client.  Even though it has the transaction of interest,
	# and had observed the change to gen 2, when we restart it it won't have
	# its LSN history database.
	#
	$clientenv2 close
	set clientenv2 [eval $cl2_envcmd -rep_client -recover]

	set result [$clientenv2 txn_applied $token]
	error_check_good not_yet [is_substr $result DB_TIMEOUT] 1

	# Sync with master, and this time token should be confirmed.
	# 
	set envlist [lreplace $envlist end end [list $clientenv2 3]]
	process_msgs $envlist
	error_check_good txn_applied [$clientenv2 txn_applied $token] 0

	$clientenv2 close
	$clientenv close
	$masterenv close

	replclose $testdir/MSGQUEUEDIR
}