1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1996,2008 Oracle.  All rights reserved.
4#
5# $Id: sysscript.tcl,v 12.7 2008/01/08 20:58:53 bostic Exp $
6#
7# System integration test script.
8# This script runs a single process that tests the full functionality of
9# the system.  The database under test contains nfiles files.  Each process
10# randomly generates a key and some data.  Both keys and data are bimodally
11# distributed between small keys (1-10 characters) and large keys (the avg
12# length is indicated via the command line parameter.
13# The process then decides on a replication factor between 1 and nfiles.
14# It writes the key and data to that many files and tacks on the file ids
15# of the files it writes to the data string.  For example, let's say that
16# I randomly generate the key dog and data cat.  Then I pick a replication
17# factor of 3.  I pick 3 files from the set of n (say 1, 3, and 5).  I then
18# rewrite the data as 1:3:5:cat.  I begin a transaction, add the key/data
19# pair to each file and then commit.  Notice that I may generate replication
20# of the form 1:3:3:cat in which case I simply add a duplicate to file 3.
21#
22# Usage: sysscript dir nfiles key_avg data_avg
23#
24# dir: DB_HOME directory
25# nfiles: number of files in the set
26# key_avg: average big key size
27# data_avg: average big data size
28
29source ./include.tcl
30source $test_path/test.tcl
31source $test_path/testutils.tcl
32
33set mypid [pid]
34
35set usage "sysscript dir nfiles key_avg data_avg method"
36
37# Verify usage
38if { $argc != 5 } {
39	puts stderr "FAIL:[timestamp] Usage: $usage"
40	exit
41}
42
43puts [concat "Argc: " $argc " Argv: " $argv]
44
45# Initialize arguments
46set dir [lindex $argv 0]
47set nfiles [ lindex $argv 1 ]
48set key_avg [ lindex $argv 2 ]
49set data_avg [ lindex $argv 3 ]
50set method [ lindex $argv 4 ]
51
52# Initialize seed
53global rand_init
54berkdb srand $rand_init
55
56puts "Beginning execution for $mypid"
57puts "$dir DB_HOME"
58puts "$nfiles files"
59puts "$key_avg average key length"
60puts "$data_avg average data length"
61
62flush stdout
63
64# Create local environment
65set dbenv [berkdb_env -txn -home $dir]
66set err [catch {error_check_good $mypid:dbenv [is_substr $dbenv env] 1} ret]
67if {$err != 0} {
68	puts $ret
69	return
70}
71
72# Now open the files
73for { set i 0 } { $i < $nfiles } { incr i } {
74	set file test044.$i.db
75	set db_set($i) [berkdb open -auto_commit -env $dbenv $method $file]
76	set err [catch {error_check_bad $mypid:dbopen $db_set($i) NULL} ret]
77	if {$err != 0} {
78		puts $ret
79		return
80	}
81	set err [catch {error_check_bad $mypid:dbopen [is_substr $db_set($i) \
82	    error] 1} ret]
83	if {$err != 0} {
84		puts $ret
85		return
86	}
87}
88
89set record_based [is_record_based $method]
90while { 1 } {
91	# Decide if we're going to create a big key or a small key
92	# We give small keys a 70% chance.
93	if { [berkdb random_int 1 10] < 8 } {
94		set k [random_data 5 0 0 $record_based]
95	} else {
96		set k [random_data $key_avg 0 0 $record_based]
97	}
98	set data [chop_data $method [random_data $data_avg 0 0]]
99
100	set txn [$dbenv txn]
101	set err [catch {error_check_good $mypid:txn_begin [is_substr $txn \
102	    $dbenv.txn] 1} ret]
103	if {$err != 0} {
104		puts $ret
105		return
106	}
107
108	# Open cursors
109	for { set f 0 } {$f < $nfiles} {incr f} {
110		set cursors($f) [$db_set($f) cursor -txn $txn]
111		set err [catch {error_check_good $mypid:cursor_open \
112		    [is_substr $cursors($f) $db_set($f)] 1} ret]
113		if {$err != 0} {
114			puts $ret
115			return
116		}
117	}
118	set aborted 0
119
120	# Check to see if key is already in database
121	set found 0
122	for { set i 0 } { $i < $nfiles } { incr i } {
123		set r [$db_set($i) get -txn $txn $k]
124		set r [$db_set($i) get -txn $txn $k]
125		if { $r == "-1" } {
126			for {set f 0 } {$f < $nfiles} {incr f} {
127				set err [catch {error_check_good \
128				    $mypid:cursor_close \
129				    [$cursors($f) close] 0} ret]
130				if {$err != 0} {
131					puts $ret
132					return
133				}
134			}
135			set err [catch {error_check_good $mypid:txn_abort \
136			    [$txn abort] 0} ret]
137			if {$err != 0} {
138				puts $ret
139				return
140			}
141			set aborted 1
142			set found 2
143			break
144		} elseif { $r != "Key $k not found." } {
145			set found 1
146			break
147		}
148	}
149	switch $found {
150	2 {
151		# Transaction aborted, no need to do anything.
152	}
153	0 {
154		# Key was not found, decide how much to replicate
155		# and then create a list of that many file IDs.
156		set repl [berkdb random_int 1 $nfiles]
157		set fset ""
158		for { set i 0 } { $i < $repl } {incr i} {
159			set f [berkdb random_int 0 [expr $nfiles - 1]]
160			lappend fset $f
161			set data [chop_data $method $f:$data]
162		}
163
164		foreach i $fset {
165			set r [$db_set($i) put -txn $txn $k $data]
166			if {$r == "-1"} {
167				for {set f 0 } {$f < $nfiles} {incr f} {
168					set err [catch {error_check_good \
169					    $mypid:cursor_close \
170					    [$cursors($f) close] 0} ret]
171					if {$err != 0} {
172						puts $ret
173						return
174					}
175				}
176				set err [catch {error_check_good \
177				    $mypid:txn_abort [$txn abort] 0} ret]
178				if {$err != 0} {
179					puts $ret
180					return
181				}
182				set aborted 1
183				break
184			}
185		}
186	}
187	1 {
188		# Key was found.  Make sure that all the data values
189		# look good.
190		set f [zero_list $nfiles]
191		set data $r
192		while { [set ndx [string first : $r]] != -1 } {
193			set fnum [string range $r 0 [expr $ndx - 1]]
194			if { [lindex $f $fnum] == 0 } {
195				#set flag -set
196				set full [record $cursors($fnum) get -set $k]
197			} else {
198				#set flag -next
199				set full [record $cursors($fnum) get -next]
200			}
201			if {[llength $full] == 0} {
202				for {set f 0 } {$f < $nfiles} {incr f} {
203					set err [catch {error_check_good \
204					    $mypid:cursor_close \
205					    [$cursors($f) close] 0} ret]
206					if {$err != 0} {
207						puts $ret
208						return
209					}
210				}
211				set err [catch {error_check_good \
212				    $mypid:txn_abort [$txn abort] 0} ret]
213				if {$err != 0} {
214					puts $ret
215					return
216				}
217				set aborted 1
218				break
219			}
220			set err [catch {error_check_bad \
221			    $mypid:curs_get($k,$data,$fnum,$flag) \
222			    [string length $full] 0} ret]
223			if {$err != 0} {
224				puts $ret
225				return
226			}
227			set key [lindex [lindex $full 0] 0]
228			set rec [pad_data $method [lindex [lindex $full 0] 1]]
229			set err [catch {error_check_good \
230			    $mypid:dbget_$fnum:key $key $k} ret]
231			if {$err != 0} {
232				puts $ret
233				return
234			}
235			set err [catch {error_check_good \
236			    $mypid:dbget_$fnum:data($k) $rec $data} ret]
237			if {$err != 0} {
238				puts $ret
239				return
240			}
241			set f [lreplace $f $fnum $fnum 1]
242			incr ndx
243			set r [string range $r $ndx end]
244		}
245	}
246	}
247	if { $aborted == 0 } {
248		for {set f 0 } {$f < $nfiles} {incr f} {
249			set err [catch {error_check_good $mypid:cursor_close \
250			    [$cursors($f) close] 0} ret]
251			if {$err != 0} {
252				puts $ret
253				return
254			}
255		}
256		set err [catch {error_check_good $mypid:commit [$txn commit] \
257		    0} ret]
258		if {$err != 0} {
259			puts $ret
260			return
261		}
262	}
263}
264
265# Close files
266for { set i 0 } { $i < $nfiles} { incr i } {
267	set r [$db_set($i) close]
268	set err [catch {error_check_good $mypid:db_close:$i $r 0} ret]
269	if {$err != 0} {
270		puts $ret
271		return
272	}
273}
274
275# Close tm and environment
276$dbenv close
277
278puts "[timestamp] [pid] Complete"
279flush stdout
280
281filecheck $file 0
282