1# See the file LICENSE for redistribution information. 2# 3# Copyright (c) 2003-2009 Oracle. All rights reserved. 4# 5# $Id$ 6# 7# TEST test119 8# TEST Test behavior when Berkeley DB returns DB_BUFFER_SMALL on a cursor. 9# TEST 10# TEST If the user-supplied buffer is not large enough to contain 11# TEST the returned value, DB returns BUFFER_SMALL. If it does, 12# TEST check that the cursor does not move -- if it moves, it will 13# TEST skip items. [#13815] 14 15proc test119 { method {tnum "119"} args} { 16 source ./include.tcl 17 global alphabet 18 global errorCode 19 20 set args [convert_args $method $args] 21 set omethod [convert_method $method] 22 puts "Test$tnum: $method ($args) Test of DB_BUFFER_SMALL." 23 24 # Skip for queue; it has fixed-length records, so overflowing 25 # the buffer isn't possible with an ordinary get. 26 if { [is_queue $method] == 1 } { 27 puts "Skipping test$tnum for method $method" 28 return 29 } 30 31 # If we are using an env, then testfile should just be the db name. 32 # Otherwise it is the test directory and the name. 33 set txnenv 0 34 set txn "" 35 set eindex [lsearch -exact $args "-env"] 36 if { $eindex == -1 } { 37 set testfile $testdir/test$tnum.db 38 set env NULL 39 } else { 40 set testfile test$tnum.db 41 incr eindex 42 set env [lindex $args $eindex] 43 set txnenv [is_txnenv $env] 44 if { $txnenv == 1 } { 45 append args " -auto_commit " 46 } 47 set testdir [get_home $env] 48 } 49 50 cleanup $testdir $env 51 52 puts "\tTest$tnum.a: Set up database." 53 set db [eval \ 54 {berkdb_open_noerr -create -mode 0644} $args $omethod $testfile] 55 error_check_good dbopen [is_valid_db $db] TRUE 56 57 # Test -data_buf_size with db->get. 58 puts "\tTest$tnum.b: Test db get with -data_buf_size." 59 set datalength 20 60 set data [repeat "a" $datalength] 61 set key 1 62 63 if { $txnenv == 1 } { 64 set t [$env txn] 65 error_check_good txn [is_valid_txn $t $env] TRUE 66 set txn "-txn $t" 67 } 68 69 error_check_good db_put \ 70 [eval {$db put} $txn {$key [chop_data $method $data]}] 0 71 72 # A get with data_buf_size equal to the data size should work. 73 set ret [eval {$db get} $txn -data_buf_size $datalength $key] 74 error_check_good db_get_key [lindex [lindex $ret 0] 0] $key 75 error_check_good db_get_data [lindex [lindex $ret 0] 1] $data 76 77 # A get with a data_buf_size decreased by one should fail. 78 catch {eval {$db get}\ 79 $txn -data_buf_size [expr $datalength - 1] $key} res 80 error_check_good buffer_small_error [is_substr $res DB_BUFFER_SMALL] 1 81 82 # Delete the item so it won't get in the way of the cursor test. 83 error_check_good db_del [eval {$db del} $txn $key] 0 84 if { $txnenv == 1 } { 85 error_check_good txn_commit [$t commit] 0 86 } 87 88 # Test -data_buf_size and -key_buf_size with dbc->get. 89 # 90 # Set up a database that includes large and small keys and 91 # large and small data in various combinations. 92 # 93 # Create small buffer equal to the largest page size. This will 94 # get DB_BUFFER_SMALL errors. 95 # Create big buffer large enough to never get DB_BUFFER_SMALL 96 # errors with this data set. 97 98 puts "\tTest$tnum.c:\ 99 Test cursor get with -data_buf_size and -key_buf_size." 100 set key $alphabet 101 set data $alphabet 102 set nentries 100 103 set start 100 104 set bigkey [repeat $key 8192] 105 set bigdata [repeat $data 8192] 106 set buffer [expr 64 * 1024] 107 set bigbuf [expr $buffer * 8] 108 109 puts "\tTest$tnum.c1: Populate database." 110 if { $txnenv == 1 } { 111 set t [$env txn] 112 error_check_good txn [is_valid_txn $t $env] TRUE 113 set txn "-txn $t" 114 } 115 116 # Put in a big key every X data items, and big data every 117 # Y data items. X and Y should be small enough that we 118 # hit the case where both X and Y are big. 119 set x 5 120 set y 7 121 for { set i $start } { $i < [expr $nentries + $start] } { incr i } { 122 # If we have a record-based method, we can't have big keys. 123 # Just use the count. 124 if { [is_record_based $method] == 1 } { 125 set k $i 126 } else { 127 if { [expr $i % $x] == 1 } { 128 set k $i.$bigkey 129 } else { 130 set k $i.$key 131 } 132 } 133 134 # We can have big data on any method. 135 if { [expr $i % $y] == 1 } { 136 set d $i.$bigdata 137 } else { 138 set d $i.$data 139 } 140 error_check_good db_put \ 141 [eval {$db put} $txn {$k [chop_data $method $d]}] 0 142 } 143 if { $txnenv == 1 } { 144 error_check_good txn_commit [$t commit] 0 145 } 146 147 # Walk the database with a cursor. When we hit DB_BUFFER_SMALL, 148 # make sure DB returns the appropriate key/data pair. 149 puts "\tTest$tnum.c2: Walk the database with a cursor." 150 if { $txnenv == 1 } { 151 set t [$env txn] 152 error_check_good txn [is_valid_txn $t $env] TRUE 153 set txn "-txn $t" 154 } 155 set curs [eval {$db cursor} $txn] 156 error_check_good cursor [is_valid_cursor $curs $db] TRUE 157 158 # Since hash is not sorted, we'll test that no items are 159 # skipped by keeping a list of all items retrieved, and 160 # making sure it is complete and that each item is unique 161 # at the end of the test. 162 set hashitems {} 163 164 set count $start 165 for { set kd [catch {eval $curs get \ 166 -key_buf_size $buffer -data_buf_size $buffer -first} res] } \ 167 { $count < [expr $nentries + $start] } \ 168 { set kd [catch {eval $curs get \ 169 -key_buf_size $buffer -data_buf_size $buffer -next} res] } { 170 if { $kd == 1 } { 171 # Make sure we have the expected error. 172 error_check_good buffer_small_error \ 173 [is_substr $errorCode DB_BUFFER_SMALL] 1 174 175 # Adjust the buffer sizes to fit the big key or data. 176 if { [expr $count % $x] == 1 } { 177 set key_buf $bigbuf 178 } else { 179 set key_buf $buffer 180 } 181 if { [expr $count % $y] == 1 } { 182 set data_buf $bigbuf 183 } else { 184 set data_buf $buffer 185 } 186 187 # Hash is not sorted, so just make sure we can get 188 # the item with a large buffer and check it later. 189 # Likewise for partition callback. 190 if { [is_hash $method] == 1 || \ 191 [is_partition_callback $args] == 1} { 192 set data_buf $bigbuf 193 set key_buf $bigbuf 194 } 195 196 # Retrieve with big buffer; there should be no error. 197 # This also walks the cursor forward. 198 set nextbig [catch {eval $curs get -key_buf_size \ 199 $key_buf -data_buf_size $data_buf -next} res] 200 error_check_good data_big_buffer_get $nextbig 0 201 202 # Extract the item number. 203 set key [lindex [lindex $res 0] 0] 204 set data [lindex [lindex $res 0] 1] 205 if { [string first . $key] != -1 } { 206 set keyindex [string first . $key] 207 set keynumber \ 208 [string range $key 0 [expr $keyindex - 1]] 209 } else { 210 set keynumber $key 211 } 212 set dataindex [string first . $data] 213 set datanumber \ 214 [string range $data 0 [expr $dataindex - 1]] 215 216 # If not hash, check that item number is correct. 217 # If hash, save the number for later verification. 218 if { [is_hash $method] == 0 \ 219 && [is_partition_callback $args] == 0 } { 220 error_check_good key_number $keynumber $count 221 error_check_good data_number $datanumber $count 222 } else { 223 lappend hashitems $keynumber 224 } 225 } else { 226 # For hash, save the item numbers of all items 227 # retrieved, not just those returning DB_BUFFER_SMALL. 228 if { [is_hash $method] == 1 || \ 229 [is_partition_callback $args] == 1} { 230 set key [lindex [lindex $res 0] 0] 231 set keyindex [string first . $key] 232 set keynumber \ 233 [string range $key 0 [expr $keyindex - 1]] 234 lappend hashitems $keynumber 235 } 236 } 237 incr count 238 set errorCode NONE 239 } 240 error_check_good curs_close [$curs close] 0 241 if { $txnenv == 1 } { 242 error_check_good txn [$t commit] 0 243 } 244 245 # Now check the list of items retrieved from hash. 246 if { [is_hash $method] == 1 || \ 247 [is_partition_callback $args] == 1} { 248 set sortedhashitems [lsort $hashitems] 249 for { set i $start } \ 250 { $i < [expr $nentries + $start] } { incr i } { 251 set hashitem \ 252 [lindex $sortedhashitems [expr $i - $start]] 253 error_check_good hash_check $hashitem $i 254 } 255 } 256 error_check_good db_close [$db close] 0 257} 258 259