summaryrefslogtreecommitdiff
path: root/db-4.8.30/test/fop001.tcl
blob: 2fc099d6dfbaffebccea4171bc887be85eb26ad4 (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
# See the file LICENSE for redistribution information.
#
# Copyright (c) 2000-2009 Oracle.  All rights reserved.
#
# $Id$
#
# TEST	fop001.tcl
# TEST	Test file system operations, combined in a transaction. [#7363]
proc fop001 { method { inmem 0 } args } {
	source ./include.tcl

	set args [convert_args $method $args]
	set omethod [convert_method $method]

	# The variable inmem determines whether the test is being
	# run with regular named databases or named in-memory databases.
	if { $inmem == 0 } {
		set tnum "001"
		set string "regular named databases"
		set operator do_op
	} else {
		set tnum "007"
		set string "in-memory named databases"
		set operator do_inmem_op
	}

	puts "\nFop$tnum: ($method)\
	    Two file system ops in one transaction for $string."

	set exists {a b}
	set noexist {foo bar}
	set open {}
	set cases {}
	set ops {rename remove open open_create open_excl truncate}

	# Set up all sensible two-op cases (op1 succeeds).
	foreach retval { 0 "file exists" "no such file" } {
		foreach op1 {rename remove open open_excl \
		    open_create truncate} {
			foreach op2 $ops {
				append cases " " [create_tests $op1 $op2 \
				    $exists $noexist $open $retval]
			}
		}
	}

	# Set up evil two-op cases (op1 fails).  Omit open_create
	# and truncate from op1 list -- open_create always succeeds
	# and truncate requires a successful open.
	foreach retval { 0 "file exists" "no such file" } {
		foreach op1 { rename remove open open_excl } {
			foreach op2 $ops {
				append cases " " [create_badtests $op1 $op2 \
					$exists $noexist $open $retval]
			}
		}
	}

	# The structure of each case is:
	# {{op1 {names1} result end1} {op2 {names2} result}}
	# A result of "0" indicates no error is expected.
	# Otherwise, the result is the expected error message.
	#
	# The "end1" variable indicates whether the first txn
	# ended with an abort or a commit, and is not used
	# in this test.
	#
	# Comment this loop out to remove the list of cases.
#	set i 1
#	foreach case $cases {
#		puts "\tFop$tnum:$i: $case"
#		incr i
#	}

	set testid 0

	# Run all the cases
	foreach case $cases {
		env_cleanup $testdir
		incr testid

		# Extract elements of the case
		set op1 [lindex [lindex $case 0] 0]
		set names1 [lindex [lindex $case 0] 1]
		set res1 [lindex [lindex $case 0] 2]

		set op2 [lindex [lindex $case 1] 0]
		set names2 [lindex [lindex $case 1] 1]
		set res2 [lindex [lindex $case 1] 2]

		puts "\tFop$tnum.$testid: $op1 ($names1), then $op2 ($names2)."

		# The variable 'when' describes when to resolve a txn -- 
		# before or after closing any open databases. 
		foreach when { before after } {

			# Create transactional environment.
			set env [berkdb_env -create -home $testdir -txn]
			error_check_good is_valid_env [is_valid_env $env] TRUE
	
			# Create two databases, dba and dbb.
			if { $inmem == 0 } {
				set dba [eval {berkdb_open -create} $omethod \
				    $args -env $env -auto_commit a]
			} else {
				set dba [eval {berkdb_open -create} $omethod \
				    $args -env $env -auto_commit { "" a }]
			}
			error_check_good dba_open [is_valid_db $dba] TRUE
			error_check_good dba_put [$dba put 1 a] 0
			error_check_good dba_close [$dba close] 0
	
			if { $inmem == 0 } {
				set dbb [eval {berkdb_open -create} $omethod \
				    $args -env $env -auto_commit b]
			} else {
				set dbb [eval {berkdb_open -create} $omethod \
				    $args -env $env -auto_commit { "" b }]
			}
			error_check_good dbb_open [is_valid_db $dbb] TRUE
			error_check_good dbb_put [$dbb put 1 b] 0
			error_check_good dbb_close [$dbb close] 0
	
			# The variable 'end' describes how to resolve the txn.
			# We run the 'abort' first because that leaves the env
			# properly set up for the 'commit' test.
			foreach end {abort commit} {
	
				puts "\t\tFop$tnum.$testid:\
				    $end $when closing database."
	
				# Start transaction
				set txn [$env txn]
	
				# Execute and check operation 1
				set result1 [$operator \
				    $omethod $op1 $names1 $txn $env $args]
				if { $res1 == 0 } {
					error_check_good \
					    op1_should_succeed $result1 $res1
				} else {
					set error [extract_error $result1]
					error_check_good \
					    op1_wrong_failure $error $res1
				}
	
				# Execute and check operation 2
				set result2 [$operator \
				    $omethod $op2 $names2 $txn $env $args]
				if { $res2 == 0 } {
					error_check_good \
					    op2_should_succeed $result2 $res2
				} else {
					set error [extract_error $result2]
					error_check_good \
					    op2_wrong_failure $error $res2
				}
	
				if { $when == "before" } {
					error_check_good txn_$end [$txn $end] 0
		
					# If the txn was aborted, we still
					# have the original two databases.
					if { $end == "abort" } {
						database_exists \
						    $inmem $testdir a
						database_exists \
						    $inmem $testdir b
					}
					close_db_handles 
				} else {
					close_db_handles
					error_check_good txn_$end [$txn $end] 0
	
					if { $end == "abort" } {
						database_exists \
						    $inmem $testdir a
						database_exists \
						    $inmem $testdir b
					}
				}		
			}
	
			# Clean up for next case
			error_check_good env_close [$env close] 0
			error_check_good envremove \
			    [berkdb envremove -home $testdir] 0
			env_cleanup $testdir
		}
	}
}

proc database_exists { inmem testdir name } {
	if { $inmem == 1 } {
		error_check_good db_exists [inmem_exists $testdir $name] 1
	} else {
		error_check_good db_exists [file exists $testdir/$name] 1
	}	
}

# This is a real hack.  We need to figure out if an in-memory named
# file exists.  In a perfect world we could use mpool stat.  Unfortunately,
# mpool_stat returns files that have deadfile set and we need to not consider
# those files to be meaningful.  So, we are parsing the output of db_stat -MA
# (I told you this was a hack)  If we ever change the output, this is going
# to break big time.  Here is what we assume:
# A file is represented by: File #N name
# The last field printed for a file is Flags
# If the file is dead, deadfile will show up in the flags
proc inmem_exists { dir filename } {
      source ./include.tcl
      set infile 0
      set islive 0
      set name ""
      set s [exec $util_path/db_stat -MA -h $dir]
      foreach i $s {
              if { $i == "File" } {
                      set infile 1
                      set islive 1
                      set name ""
              } elseif { $i == "Flags" } {
                      set infile 0
                      if { $name != "" && $islive } {
                              return 1
                      }
              } elseif { $infile != 0 } {
                      incr infile
              }

              if { $islive && $i == "deadfile" } {
                      set islive 0
              }

              if { $infile == 3 } {
                      if { $i == $filename } {
                              set name $filename
                      }
              }
      }

      return 0
}