1proc randstring {min max {type binary}} { 2 set len [expr {$min+int(rand()*($max-$min+1))}] 3 set output {} 4 if {$type eq {binary}} { 5 set minval 0 6 set maxval 255 7 } elseif {$type eq {alpha}} { 8 set minval 48 9 set maxval 122 10 } elseif {$type eq {compr}} { 11 set minval 48 12 set maxval 52 13 } 14 while {$len} { 15 append output [format "%c" [expr {$minval+int(rand()*($maxval-$minval+1))}]] 16 incr len -1 17 } 18 return $output 19} 20 21# Useful for some test 22proc zlistAlikeSort {a b} { 23 if {[lindex $a 0] > [lindex $b 0]} {return 1} 24 if {[lindex $a 0] < [lindex $b 0]} {return -1} 25 string compare [lindex $a 1] [lindex $b 1] 26} 27 28# Return all log lines starting with the first line that contains a warning. 29# Generally, this will be an assertion error with a stack trace. 30proc warnings_from_file {filename} { 31 set lines [split [exec cat $filename] "\n"] 32 set matched 0 33 set logall 0 34 set result {} 35 foreach line $lines { 36 if {[string match {*REDIS BUG REPORT START*} $line]} { 37 set logall 1 38 } 39 if {[regexp {^\[\d+\]\s+\d+\s+\w+\s+\d{2}:\d{2}:\d{2} \#} $line]} { 40 set matched 1 41 } 42 if {$logall || $matched} { 43 lappend result $line 44 } 45 } 46 join $result "\n" 47} 48 49# Return value for INFO property 50proc status {r property} { 51 if {[regexp "\r\n$property:(.*?)\r\n" [{*}$r info] _ value]} { 52 set _ $value 53 } 54} 55 56proc waitForBgsave r { 57 while 1 { 58 if {[status r rdb_bgsave_in_progress] eq 1} { 59 if {$::verbose} { 60 puts -nonewline "\nWaiting for background save to finish... " 61 flush stdout 62 } 63 after 1000 64 } else { 65 break 66 } 67 } 68} 69 70proc waitForBgrewriteaof r { 71 while 1 { 72 if {[status r aof_rewrite_in_progress] eq 1} { 73 if {$::verbose} { 74 puts -nonewline "\nWaiting for background AOF rewrite to finish... " 75 flush stdout 76 } 77 after 1000 78 } else { 79 break 80 } 81 } 82} 83 84proc wait_for_sync r { 85 while 1 { 86 if {[status $r master_link_status] eq "down"} { 87 after 10 88 } else { 89 break 90 } 91 } 92} 93 94proc randomInt {max} { 95 expr {int(rand()*$max)} 96} 97 98proc randomSignedInt {max} { 99 set i [randomInt $max] 100 if {rand() > 0.5} { 101 set i -$i 102 } 103 return $i 104} 105 106proc randpath args { 107 set path [expr {int(rand()*[llength $args])}] 108 uplevel 1 [lindex $args $path] 109} 110 111proc randomValue {} { 112 randpath { 113 # Small enough to likely collide 114 randomSignedInt 1000 115 } { 116 # 32 bit compressible signed/unsigned 117 randpath {randomSignedInt 2000000000} {randomSignedInt 4000000000} 118 } { 119 # 64 bit 120 randpath {randomSignedInt 1000000000000} 121 } { 122 # Random string 123 randpath {randstring 0 256 alpha} \ 124 {randstring 0 256 compr} \ 125 {randstring 0 256 binary} 126 } 127} 128 129proc randomKey {} { 130 randpath { 131 # Small enough to likely collide 132 randomInt 1000 133 } { 134 # 32 bit compressible signed/unsigned 135 randpath {randomInt 2000000000} {randomInt 4000000000} 136 } { 137 # 64 bit 138 randpath {randomInt 1000000000000} 139 } { 140 # Random string 141 randpath {randstring 1 256 alpha} \ 142 {randstring 1 256 compr} 143 } 144} 145 146proc findKeyWithType {r type} { 147 for {set j 0} {$j < 20} {incr j} { 148 set k [{*}$r randomkey] 149 if {$k eq {}} { 150 return {} 151 } 152 if {[{*}$r type $k] eq $type} { 153 return $k 154 } 155 } 156 return {} 157} 158 159proc createComplexDataset {r ops {opt {}}} { 160 for {set j 0} {$j < $ops} {incr j} { 161 set k [randomKey] 162 set k2 [randomKey] 163 set f [randomValue] 164 set v [randomValue] 165 166 if {[lsearch -exact $opt useexpire] != -1} { 167 if {rand() < 0.1} { 168 {*}$r expire [randomKey] [randomInt 2] 169 } 170 } 171 172 randpath { 173 set d [expr {rand()}] 174 } { 175 set d [expr {rand()}] 176 } { 177 set d [expr {rand()}] 178 } { 179 set d [expr {rand()}] 180 } { 181 set d [expr {rand()}] 182 } { 183 randpath {set d +inf} {set d -inf} 184 } 185 set t [{*}$r type $k] 186 187 if {$t eq {none}} { 188 randpath { 189 {*}$r set $k $v 190 } { 191 {*}$r lpush $k $v 192 } { 193 {*}$r sadd $k $v 194 } { 195 {*}$r zadd $k $d $v 196 } { 197 {*}$r hset $k $f $v 198 } { 199 {*}$r del $k 200 } 201 set t [{*}$r type $k] 202 } 203 204 switch $t { 205 {string} { 206 # Nothing to do 207 } 208 {list} { 209 randpath {{*}$r lpush $k $v} \ 210 {{*}$r rpush $k $v} \ 211 {{*}$r lrem $k 0 $v} \ 212 {{*}$r rpop $k} \ 213 {{*}$r lpop $k} 214 } 215 {set} { 216 randpath {{*}$r sadd $k $v} \ 217 {{*}$r srem $k $v} \ 218 { 219 set otherset [findKeyWithType {*}$r set] 220 if {$otherset ne {}} { 221 randpath { 222 {*}$r sunionstore $k2 $k $otherset 223 } { 224 {*}$r sinterstore $k2 $k $otherset 225 } { 226 {*}$r sdiffstore $k2 $k $otherset 227 } 228 } 229 } 230 } 231 {zset} { 232 randpath {{*}$r zadd $k $d $v} \ 233 {{*}$r zrem $k $v} \ 234 { 235 set otherzset [findKeyWithType {*}$r zset] 236 if {$otherzset ne {}} { 237 randpath { 238 {*}$r zunionstore $k2 2 $k $otherzset 239 } { 240 {*}$r zinterstore $k2 2 $k $otherzset 241 } 242 } 243 } 244 } 245 {hash} { 246 randpath {{*}$r hset $k $f $v} \ 247 {{*}$r hdel $k $f} 248 } 249 } 250 } 251} 252 253proc formatCommand {args} { 254 set cmd "*[llength $args]\r\n" 255 foreach a $args { 256 append cmd "$[string length $a]\r\n$a\r\n" 257 } 258 set _ $cmd 259} 260 261proc csvdump r { 262 set o {} 263 foreach k [lsort [{*}$r keys *]] { 264 set type [{*}$r type $k] 265 append o [csvstring $k] , [csvstring $type] , 266 switch $type { 267 string { 268 append o [csvstring [{*}$r get $k]] "\n" 269 } 270 list { 271 foreach e [{*}$r lrange $k 0 -1] { 272 append o [csvstring $e] , 273 } 274 append o "\n" 275 } 276 set { 277 foreach e [lsort [{*}$r smembers $k]] { 278 append o [csvstring $e] , 279 } 280 append o "\n" 281 } 282 zset { 283 foreach e [{*}$r zrange $k 0 -1 withscores] { 284 append o [csvstring $e] , 285 } 286 append o "\n" 287 } 288 hash { 289 set fields [{*}$r hgetall $k] 290 set newfields {} 291 foreach {k v} $fields { 292 lappend newfields [list $k $v] 293 } 294 set fields [lsort -index 0 $newfields] 295 foreach kv $fields { 296 append o [csvstring [lindex $kv 0]] , 297 append o [csvstring [lindex $kv 1]] , 298 } 299 append o "\n" 300 } 301 } 302 } 303 return $o 304} 305 306proc csvstring s { 307 return "\"$s\"" 308} 309 310proc roundFloat f { 311 format "%.10g" $f 312} 313