summaryrefslogtreecommitdiff
path: root/test/dbscript.tcl
blob: 8906b3f169f8043cf616ca52d245c13724a066dd (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
# See the file LICENSE for redistribution information.
#
# Copyright (c) 1996-2009 Oracle.  All rights reserved.
#
# $Id$
#
# Random db tester.
# Usage: dbscript file numops min_del max_add key_avg data_avgdups
# method: method (we pass this in so that fixed-length records work)
# file: db file on which to operate
# numops: number of operations to do
# ncurs: number of cursors
# min_del: minimum number of keys before you disable deletes.
# max_add: maximum number of keys before you disable adds.
# key_avg: average key size
# data_avg: average data size
# dups: 1 indicates dups allowed, 0 indicates no dups
# errpct: What percent of operations should generate errors
# seed: Random number generator seed (-1 means use pid)

source ./include.tcl
source $test_path/test.tcl
source $test_path/testutils.tcl

set usage "dbscript file numops ncurs min_del max_add key_avg data_avg dups errpcnt args"

# Verify usage
if { $argc < 10 } {
	puts stderr "FAIL:[timestamp] Usage: $usage"
	exit
}

# Initialize arguments
set method [lindex $argv 0]
set file [lindex $argv 1]
set numops [ lindex $argv 2 ]
set ncurs [ lindex $argv 3 ]
set min_del [ lindex $argv 4 ]
set max_add [ lindex $argv 5 ]
set key_avg [ lindex $argv 6 ]
set data_avg [ lindex $argv 7 ]
set dups [ lindex $argv 8 ]
set errpct [ lindex $argv 9 ]
set args [ lindex $argv 10 ]

berkdb srand $rand_init

puts "Beginning execution for [pid]"
puts "$file database"
puts "$numops Operations"
puts "$ncurs cursors"
puts "$min_del keys before deletes allowed"
puts "$max_add or fewer keys to add"
puts "$key_avg average key length"
puts "$data_avg average data length"
puts "$method $args"
if { $dups != 1 } {
	puts "No dups"
} else {
	puts "Dups allowed"
}
puts "$errpct % Errors"

flush stdout

set db [eval {berkdb_open} $args $file]
set cerr [catch {error_check_good dbopen [is_substr $db db] 1} cret]
if {$cerr != 0} {
	puts $cret
	return
}
# set method [$db get_type]
set record_based [is_record_based $method]

# Initialize globals including data
global nkeys
global l_keys
global a_keys

set nkeys [db_init $db 1]
puts "Initial number of keys: $nkeys"

set pflags ""
set gflags ""
set txn ""

# Open the cursors
set curslist {}
for { set i 0 } { $i < $ncurs } { incr i } {
	set dbc [$db cursor]
	set cerr [catch {error_check_good dbcopen [is_substr $dbc $db.c] 1} cret]
	if {$cerr != 0} {
		puts $cret
		return
	}
	set cerr [catch {error_check_bad cursor_create $dbc NULL} cret]
	if {$cerr != 0} {
		puts $cret
		return
	}
	lappend curslist $dbc

}

# On each iteration we're going to generate random keys and
# data.  We'll select either a get/put/delete operation unless
# we have fewer than min_del keys in which case, delete is not
# an option or more than max_add in which case, add is not
# an option.  The tcl global arrays a_keys and l_keys keep track
# of key-data pairs indexed by key and a list of keys, accessed
# by integer.
set adds 0
set puts 0
set gets 0
set dels 0
set bad_adds 0
set bad_puts 0
set bad_gets 0
set bad_dels 0

for { set iter 0 } { $iter < $numops } { incr iter } {
	set op [pick_op $min_del $max_add $nkeys]
	set err [is_err $errpct]

	# The op0's indicate that there aren't any duplicates, so we
	# exercise regular operations.  If dups is 1, then we'll use
	# cursor ops.
	switch $op$dups$err {
		add00 {
			incr adds

			set k [random_data $key_avg 1 a_keys $record_based]
			set data [random_data $data_avg 0 0]
			set data [chop_data $method $data]
			set ret [eval {$db put} $txn $pflags \
			    {-nooverwrite $k $data}]
			set cerr [catch {error_check_good put $ret 0} cret]
			if {$cerr != 0} {
				puts $cret
				return
			}
			newpair $k [pad_data $method $data]
		}
		add01 {
			incr bad_adds
			set k [random_key]
			set data [random_data $data_avg 0 0]
			set data [chop_data $method $data]
			set ret [eval {$db put} $txn $pflags \
			    {-nooverwrite $k $data}]
			set cerr [catch {error_check_good put $ret 0} cret]
			if {$cerr != 0} {
				puts $cret
				return
			}
			# Error case so no change to data state
		}
		add10 {
			incr adds
			set dbcinfo [random_cursor $curslist]
			set dbc [lindex $dbcinfo 0]
			if { [berkdb random_int 1 2] == 1 } {
				# Add a new key
				set k [random_data $key_avg 1 a_keys \
				    $record_based]
				set data [random_data $data_avg 0 0]
				set data [chop_data $method $data]
				set ret [eval {$dbc put} $txn \
				    {-keyfirst $k $data}]
				newpair $k [pad_data $method $data]
			} else {
				# Add a new duplicate
				set dbc [lindex $dbcinfo 0]
				set k [lindex $dbcinfo 1]
				set data [random_data $data_avg 0 0]

				set op [pick_cursput]
				set data [chop_data $method $data]
				set ret [eval {$dbc put} $txn {$op $k $data}]
				adddup $k [lindex $dbcinfo 2] $data
			}
		}
		add11 {
			# TODO
			incr bad_adds
			set ret 1
		}
		put00 {
			incr puts
			set k [random_key]
			set data [random_data $data_avg 0 0]
			set data [chop_data $method $data]
			set ret [eval {$db put} $txn {$k $data}]
			changepair $k [pad_data $method $data]
		}
		put01 {
			incr bad_puts
			set k [random_key]
			set data [random_data $data_avg 0 0]
			set data [chop_data $method $data]
			set ret [eval {$db put} $txn $pflags \
			    {-nooverwrite $k $data}]
			set cerr [catch {error_check_good put $ret 0} cret]
			if {$cerr != 0} {
				puts $cret
				return
			}
			# Error case so no change to data state
		}
		put10 {
			incr puts
			set dbcinfo [random_cursor $curslist]
			set dbc [lindex $dbcinfo 0]
			set k [lindex $dbcinfo 1]
			set data [random_data $data_avg 0 0]
			set data [chop_data $method $data]

			set ret [eval {$dbc put} $txn {-current $data}]
			changedup $k [lindex $dbcinfo 2] $data
		}
		put11 {
			incr bad_puts
			set k [random_key]
			set data [random_data $data_avg 0 0]
			set data [chop_data $method $data]
			set dbc [$db cursor]
			set ret [eval {$dbc put} $txn {-current $data}]
			set cerr [catch {error_check_good curs_close \
			    [$dbc close] 0} cret]
			if {$cerr != 0} {
				puts $cret
				return
			}
			# Error case so no change to data state
		}
		get00 {
			incr gets
			set k [random_key]
			set val [eval {$db get} $txn {$k}]
			set data [pad_data $method [lindex [lindex $val 0] 1]]
			if { $data == $a_keys($k) } {
				set ret 0
			} else {
				set ret "FAIL: Error got |$data| expected |$a_keys($k)|"
			}
			# Get command requires no state change
		}
		get01 {
			incr bad_gets
			set k [random_data $key_avg 1 a_keys $record_based]
			set ret [eval {$db get} $txn {$k}]
			# Error case so no change to data state
		}
		get10 {
			incr gets
			set dbcinfo [random_cursor $curslist]
			if { [llength $dbcinfo] == 3 } {
				set ret 0
			else
				set ret 0
			}
			# Get command requires no state change
		}
		get11 {
			incr bad_gets
			set k [random_key]
			set dbc [$db cursor]
			if { [berkdb random_int 1 2] == 1 } {
				set dir -next
			} else {
				set dir -prev
			}
			set ret [eval {$dbc get} $txn {-next $k}]
			set cerr [catch {error_check_good curs_close \
			    [$dbc close] 0} cret]
			if {$cerr != 0} {
				puts $cret
				return
			}
			# Error and get case so no change to data state
		}
		del00 {
			incr dels
			set k [random_key]
			set ret [eval {$db del} $txn {$k}]
			rempair $k
		}
		del01 {
			incr bad_dels
			set k [random_data $key_avg 1 a_keys $record_based]
			set ret [eval {$db del} $txn {$k}]
			# Error case so no change to data state
		}
		del10 {
			incr dels
			set dbcinfo [random_cursor $curslist]
			set dbc [lindex $dbcinfo 0]
			set ret [eval {$dbc del} $txn]
			remdup [lindex dbcinfo 1] [lindex dbcinfo 2]
		}
		del11 {
			incr bad_dels
			set c [$db cursor]
			set ret [eval {$c del} $txn]
			set cerr [catch {error_check_good curs_close \
			    [$c close] 0} cret]
			if {$cerr != 0} {
				puts $cret
				return
			}
			# Error case so no change to data state
		}
	}
	if { $err == 1 } {
		# Verify failure.
		set cerr [catch {error_check_good $op$dups$err:$k \
		    [is_substr Error $ret] 1} cret]
		if {$cerr != 0} {
			puts $cret
			return
		}
	} else {
		# Verify success
		set cerr [catch {error_check_good $op$dups$err:$k $ret 0} cret]
		if {$cerr != 0} {
			puts $cret
			return
		}
	}

	flush stdout
}

# Close cursors and file
foreach i $curslist {
	set r [$i close]
	set cerr [catch {error_check_good cursor_close:$i $r 0} cret]
	if {$cerr != 0} {
		puts $cret
		return
	}
}

set r [$db close]
set cerr [catch {error_check_good db_close:$db $r 0} cret]
if {$cerr != 0} {
	puts $cret
	return
}

puts "[timestamp] [pid] Complete"
puts "Successful ops: $adds adds $gets gets $puts puts $dels dels"
puts "Error ops: $bad_adds adds $bad_gets gets $bad_puts puts $bad_dels dels"
flush stdout

eval filecheck $file {$txn} $args

exit