util.tcl 7.7 KB

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