1 # See the file LICENSE for redistribution information.
3 # Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
7 # Process script for the multi-process db tester.
10 source $test_path/test.tcl
11 source $test_path/testutils.tcl
19 # In Tcl, when there are multiple catch handlers, *all* handlers
20 # are called, so we have to resort to this hack.
22 global exception_handled
24 set exception_handled 0
26 set datastr $alphabet$alphabet
28 # Usage: mdbscript dir file nentries iter procid procs seed
29 # dir: DBHOME directory
30 # file: db file on which to operate
31 # nentries: number of entries taken from dictionary
32 # iter: number of operations to run
33 # procid: this processes' id number
34 # procs: total number of processes running
35 set usage "mdbscript method dir file nentries iter procid procs"
39 puts "FAIL:[timestamp] test042: Usage: $usage"
43 # Initialize arguments
44 set method [lindex $argv 0]
45 set dir [lindex $argv 1]
46 set file [lindex $argv 2]
47 set nentries [ lindex $argv 3 ]
48 set iter [ lindex $argv 4 ]
49 set procid [ lindex $argv 5 ]
50 set procs [ lindex $argv 6 ]
51 set args [ lindex $argv 7 ]
57 set renum [is_rrecno $method]
58 set omethod [convert_method $method]
60 if { [is_record_based $method] == 1 } {
61 append gflags " -recno"
67 # We want repeatable results, but we also want each instance of mdbscript
68 # to do something different. So we add the procid to the fixed seed.
69 # (Note that this is a serial number given by the caller, not a pid.)
70 berkdb srand [expr $rand_init + $procid]
72 puts "Beginning execution for [pid] $method"
75 puts "$nentries data elements"
76 puts "$iter iterations"
77 puts "$procid process id"
78 puts "$procs processes"
84 # Note: all I/O operations, and especially flush, are expensive
85 # on Win2000 at least with Tcl version 8.3.2. So we'll avoid
86 # flushes in the main part of the loop below.
89 set dbenv [berkdb_env -create -cdb -home $dir]
90 #set dbenv [berkdb_env -create -cdb -log -home $dir]
91 error_check_good dbenv [is_valid_env $dbenv] TRUE
93 set locker [ $dbenv lock_id ]
95 set db [eval {berkdb_open} -env $dbenv $omethod $args {$file}]
96 error_check_good dbopen [is_valid_db $db] TRUE
98 # Init globals (no data)
99 set nkeys [db_init $db 0]
100 puts "Initial number of keys: $nkeys"
103 proc get_lock { k } {
109 global DB_LOCK_NOWAIT
111 global exception_handled
112 # Make sure that the key isn't in the middle of
114 if {[catch {$dbenv lock_get -nowait write $locker $k} klock] != 0 } {
115 set exception_handled 1
118 get_lock [is_substr $errorInfo "DB_LOCK_NOTGRANTED"] 1
119 puts "Warning: key $k locked"
123 error_check_good get_lock [is_valid_lock $klock $dbenv] TRUE
128 # If we are renumbering, then each time we delete an item, the number of
129 # items in the file is temporarily decreased, so the highest record numbers
130 # do not exist. To make sure this doesn't happen, we never generate the
131 # highest few record numbers as keys.
133 # For record-based methods, record numbers begin at 1, while for other keys,
134 # we begin at 0 to index into an array.
135 proc rand_key { method nkeys renum procs} {
137 return [berkdb random_int 1 [expr $nkeys - $procs]]
138 } elseif { [is_record_based $method] == 1 } {
139 return [berkdb random_int 1 $nkeys]
141 return [berkdb random_int 0 [expr $nkeys - 1]]
145 # On each iteration we're going to randomly pick a key.
146 # 1. We'll either get it (verifying that its contents are reasonable).
147 # 2. Put it (using an overwrite to make the data be datastr:ID).
148 # 3. Get it and do a put through the cursor, tacking our ID on to
149 # 4. Get it, read forward some random number of keys.
150 # 5. Get it, read forward some random number of keys and do a put (replace).
151 # 6. Get it, read forward some random number of keys and do a del. And then
152 # do a put of the key.
159 set dlen [string length $datastr]
161 for { set i 0 } { $i < $iter } { incr i } {
162 set op [berkdb random_int 0 5]
163 puts "iteration $i operation $op"
169 set k [rand_key $method $nkeys $renum $procs]
170 if {[is_record_based $method] == 1} {
173 set key [lindex $l_keys $k]
176 if { [get_lock $key] == 1 } {
181 set rec [eval {$db get} $txn $gflags {$key}]
182 error_check_bad "$db get $key" [llength $rec] 0
183 set partial [string range \
184 [lindex [lindex $rec 0] 1] 0 [expr $dlen - 1]]
186 "$db get $key" $partial [pad_data $method $datastr]
190 set k [rand_key $method $nkeys $renum $procs]
191 if {[is_record_based $method] == 1} {
194 set key [lindex $l_keys $k]
197 set data $datastr:$procid
198 set ret [eval {$db put} \
199 $txn $pflags {$key [chop_data $method $data]}]
200 error_check_good "$db put $key" $ret 0
204 set dbc [$db cursor -update]
205 error_check_good "$db cursor" \
206 [is_valid_cursor $dbc $db] TRUE
208 set k [rand_key $method $nkeys $renum $procs]
209 if {[is_record_based $method] == 1} {
212 set key [lindex $l_keys $k]
215 if { [get_lock $key] == 1 } {
217 error_check_good "$dbc close" \
223 set ret [$dbc get -set $key]
225 "$dbc get $key" [llength [lindex $ret 0]] 2
226 set rec [lindex [lindex $ret 0] 1]
227 set partial [string range $rec 0 [expr $dlen - 1]]
229 "$dbc get $key" $partial [pad_data $method $datastr]
230 append rec ":$procid"
232 -current [chop_data $method $rec]]
233 error_check_good "$dbc put $key" $ret 0
234 error_check_good "$dbc close" [$dbc close] 0
245 set dbc [eval {$db cursor} $flags]
246 error_check_good "$db cursor" \
247 [is_valid_cursor $dbc $db] TRUE
249 set k [rand_key $method $nkeys $renum $procs]
250 if {[is_record_based $method] == 1} {
253 set key [lindex $l_keys $k]
256 if { [get_lock $key] == 1 } {
258 error_check_good "$dbc close" \
264 set ret [$dbc get -set $key]
266 "$dbc get $key" [llength [lindex $ret 0]] 2
268 # Now read a few keys sequentially
269 set nloop [berkdb random_int 0 10]
270 if { [berkdb random_int 0 1] == 0 } {
275 while { $nloop > 0 } {
277 set ret [eval {$dbc get} $flags]
278 # Might read beginning/end of file
279 if { [llength $ret] == 0} {
291 set rec [lindex [lindex $ret 0] 1]
292 set partial [string range $rec 0 \
294 error_check_good "$dbc get $key" \
295 $partial [pad_data $method $datastr]
296 append rec ":$procid"
297 set ret [$dbc put -current \
298 [chop_data $method $rec]]
300 "$dbc put $key" $ret 0
304 set k [lindex [lindex $ret 0] 0]
305 # We need to lock the item we're
306 # deleting so that someone else can't
307 # try to do a get while we're
309 error_check_good "$klock put" \
312 set cur [$dbc get -current]
313 error_check_bad get_current \
315 set key [lindex [lindex $cur 0] 0]
316 if { [get_lock $key] == 1 } {
318 error_check_good "$dbc close" \
324 error_check_good "$dbc del" $ret 0
326 append rec ":$procid"
328 set ret [$dbc put -before \
329 [chop_data $method $rec]]
331 "$dbc put $k" $ret $k
333 [is_record_based $method] == 1 } {
334 error_check_good "$dbc close" \
337 set ret [$db put $k \
338 [chop_data $method $rec]]
342 set ret [$dbc put -keylast $k \
343 [chop_data $method $rec]]
349 if { $close_cursor == 1 } {
351 "$dbc close" [$dbc close] 0
358 global exception_handled;
362 set fnl [string first "\n" $errorInfo]
363 set theError [string range $errorInfo 0 [expr $fnl - 1]]
365 if { [string compare $klock NOLOCK] != 0 } {
368 if {$close_cursor == 1} {
373 if {[string first FAIL $theError] == 0 && \
374 $exception_handled != 1} {
376 error "FAIL:[timestamp] test042: key $k: $theError"
378 set exception_handled 0
380 if { [string compare $klock NOLOCK] != 0 } {
381 error_check_good "$klock put" [$klock put] 0
387 error_check_good db_close_catch [catch {$db close} ret] 0
388 error_check_good db_close $ret 0
389 error_check_good dbenv_close [$dbenv close] 0
394 puts "[timestamp] [pid] Complete"
395 puts "Successful ops: "
397 puts "\t$overwrite overwrites"
398 puts "\t$getput getputs"
399 puts "\t$seqread seqread"
400 puts "\t$seqput seqput"
401 puts "\t$seqdel seqdel"