]>
Commit | Line | Data |
---|---|---|
ed9b544e | 1 | # TODO # test pipelining |
2 | ||
3 | set ::passed 0 | |
4 | set ::failed 0 | |
5 | ||
6 | proc test {name code okpattern} { | |
7 | puts -nonewline [format "%-70s " $name] | |
8 | flush stdout | |
9 | set retval [uplevel 1 $code] | |
10 | if {$okpattern eq $retval || [string match $okpattern $retval]} { | |
11 | puts "PASSED" | |
12 | incr ::passed | |
13 | } else { | |
14 | puts "!! ERROR expected\n'$okpattern'\nbut got\n'$retval'" | |
15 | incr ::failed | |
16 | } | |
17 | } | |
18 | ||
19 | proc main {server port} { | |
20 | set fd [redis_connect $server $port] | |
21 | ||
22 | test {DEL all keys to start with a clean DB} { | |
23 | foreach key [redis_keys $fd *] { | |
24 | redis_del $fd $key | |
25 | } | |
26 | redis_dbsize $fd | |
27 | } {0} | |
28 | ||
29 | test {SET and GET an item} { | |
30 | redis_set $fd x foobar | |
31 | redis_get $fd x | |
32 | } {foobar} | |
33 | ||
34 | test {DEL against a single item} { | |
35 | redis_del $fd x | |
36 | redis_get $fd x | |
37 | } {} | |
38 | ||
39 | test {KEYS with pattern} { | |
40 | foreach key {key_x key_y key_z foo_a foo_b foo_c} { | |
41 | redis_set $fd $key hello | |
42 | } | |
43 | lsort [redis_keys $fd foo*] | |
44 | } {foo_a foo_b foo_c} | |
45 | ||
46 | test {KEYS to get all keys} { | |
47 | lsort [redis_keys $fd *] | |
48 | } {foo_a foo_b foo_c key_x key_y key_z} | |
49 | ||
50 | test {DBSIZE} { | |
51 | redis_dbsize $fd | |
52 | } {6} | |
53 | ||
54 | test {DEL all keys} { | |
55 | foreach key [redis_keys $fd *] { | |
56 | redis_del $fd $key | |
57 | } | |
58 | redis_dbsize $fd | |
59 | } {0} | |
60 | ||
61 | test {Very big payload in GET/SET} { | |
62 | set buf [string repeat "abcd" 1000000] | |
63 | redis_set $fd foo $buf | |
64 | redis_get $fd foo | |
65 | } [string repeat "abcd" 1000000] | |
66 | ||
67 | test {SET 10000 numeric keys and access all them in reverse order} { | |
68 | for {set x 0} {$x < 10000} {incr x} { | |
69 | redis_set $fd $x $x | |
70 | } | |
71 | set sum 0 | |
72 | for {set x 9999} {$x >= 0} {incr x -1} { | |
73 | incr sum [redis_get $fd $x] | |
74 | } | |
75 | format $sum | |
76 | } {49995000} | |
77 | ||
78 | test {DBSIZE should be 10001 now} { | |
79 | redis_dbsize $fd | |
80 | } {10001} | |
81 | ||
82 | test {INCR against non existing key} { | |
83 | set res {} | |
84 | append res [redis_incr $fd novar] | |
85 | append res [redis_get $fd novar] | |
86 | } {11} | |
87 | ||
88 | test {INCR against key created by incr itself} { | |
89 | redis_incr $fd novar | |
90 | } {2} | |
91 | ||
92 | test {INCR against key originally set with SET} { | |
93 | redis_set $fd novar 100 | |
94 | redis_incr $fd novar | |
95 | } {101} | |
96 | ||
97 | test {SETNX target key missing} { | |
98 | redis_setnx $fd novar2 foobared | |
99 | redis_get $fd novar2 | |
100 | } {foobared} | |
101 | ||
102 | test {SETNX target key exists} { | |
103 | redis_setnx $fd novar2 blabla | |
104 | redis_get $fd novar2 | |
105 | } {foobared} | |
106 | ||
107 | test {EXISTS} { | |
108 | set res {} | |
109 | redis_set $fd newkey test | |
110 | append res [redis_exists $fd newkey] | |
111 | redis_del $fd newkey | |
112 | append res [redis_exists $fd newkey] | |
113 | } {10} | |
114 | ||
115 | test {Zero length value in key. SET/GET/EXISTS} { | |
116 | redis_set $fd emptykey {} | |
117 | set res [redis_get $fd emptykey] | |
118 | append res [redis_exists $fd emptykey] | |
119 | redis_del $fd emptykey | |
120 | append res [redis_exists $fd emptykey] | |
121 | } {10} | |
122 | ||
123 | test {Commands pipelining} { | |
124 | puts -nonewline $fd "SET k1 4\r\nxyzk\r\nGET k1\r\nPING\r\n" | |
125 | flush $fd | |
126 | set res {} | |
127 | append res [string match +OK* [redis_read_retcode $fd]] | |
128 | append res [redis_bulk_read $fd] | |
129 | append res [string match +PONG* [redis_read_retcode $fd]] | |
130 | format $res | |
131 | } {1xyzk1} | |
132 | ||
133 | test {Non existing command} { | |
134 | puts -nonewline $fd "foo\r\n" | |
135 | flush $fd | |
136 | string match -ERR* [redis_read_retcode $fd] | |
137 | } {1} | |
138 | ||
139 | test {Basic LPUSH, RPUSH, LLENGTH, LINDEX} { | |
140 | redis_lpush $fd mylist a | |
141 | redis_lpush $fd mylist b | |
142 | redis_rpush $fd mylist c | |
143 | set res [redis_llen $fd mylist] | |
144 | append res [redis_lindex $fd mylist 0] | |
145 | append res [redis_lindex $fd mylist 1] | |
146 | append res [redis_lindex $fd mylist 2] | |
147 | } {3bac} | |
148 | ||
149 | test {DEL a list} { | |
150 | redis_del $fd mylist | |
151 | redis_exists $fd mylist | |
152 | } {0} | |
153 | ||
154 | test {Create a long list and check every single element with LINDEX} { | |
155 | set ok 0 | |
156 | for {set i 0} {$i < 1000} {incr i} { | |
157 | redis_rpush $fd mylist $i | |
158 | } | |
159 | for {set i 0} {$i < 1000} {incr i} { | |
160 | if {[redis_lindex $fd mylist $i] eq $i} {incr ok} | |
161 | if {[redis_lindex $fd mylist [expr (-$i)-1]] eq [expr 999-$i]} { | |
162 | incr ok | |
163 | } | |
164 | } | |
165 | format $ok | |
166 | } {2000} | |
167 | ||
168 | test {Test elements with LINDEX in random access} { | |
169 | set ok 0 | |
170 | for {set i 0} {$i < 1000} {incr i} { | |
171 | set r [expr int(rand()*1000)] | |
172 | if {[redis_lindex $fd mylist $r] eq $r} {incr ok} | |
173 | if {[redis_lindex $fd mylist [expr (-$r)-1]] eq [expr 999-$r]} { | |
174 | incr ok | |
175 | } | |
176 | } | |
177 | format $ok | |
178 | } {2000} | |
179 | ||
180 | test {LLEN against non-list value error} { | |
181 | redis_del $fd mylist | |
182 | redis_set $fd mylist foobar | |
183 | redis_llen $fd mylist | |
184 | } {-2} | |
185 | ||
186 | test {LINDEX against non-list value error} { | |
187 | redis_lindex $fd mylist 0 | |
188 | } {*ERROR*} | |
189 | ||
190 | test {LPUSH against non-list value error} { | |
191 | redis_lpush $fd mylist 0 | |
192 | } {-ERR*} | |
193 | ||
194 | test {RPUSH against non-list value error} { | |
195 | redis_rpush $fd mylist 0 | |
196 | } {-ERR*} | |
197 | ||
198 | test {RENAME basic usage} { | |
199 | redis_set $fd mykey hello | |
200 | redis_rename $fd mykey mykey1 | |
201 | redis_rename $fd mykey1 mykey2 | |
202 | redis_get $fd mykey2 | |
203 | } {hello} | |
204 | ||
205 | test {RENAME source key should no longer exist} { | |
206 | redis_exists $fd mykey | |
207 | } {0} | |
208 | ||
209 | test {RENAME against already existing key} { | |
210 | redis_set $fd mykey a | |
211 | redis_set $fd mykey2 b | |
212 | redis_rename $fd mykey2 mykey | |
213 | set res [redis_get $fd mykey] | |
214 | append res [redis_exists $fd mykey2] | |
215 | } {b0} | |
216 | ||
217 | test {RENAMENX basic usage} { | |
218 | redis_del $fd mykey | |
219 | redis_del $fd mykey2 | |
220 | redis_set $fd mykey foobar | |
221 | redis_renamenx $fd mykey mykey2 | |
222 | set res [redis_get $fd mykey2] | |
223 | append res [redis_exists $fd mykey] | |
224 | } {foobar0} | |
225 | ||
226 | test {RENAMENX against already existing key} { | |
227 | redis_set $fd mykey foo | |
228 | redis_set $fd mykey2 bar | |
229 | redis_renamenx $fd mykey mykey2 | |
230 | } {0} | |
231 | ||
232 | test {RENAMENX against already existing key (2)} { | |
233 | set res [redis_get $fd mykey] | |
234 | append res [redis_get $fd mykey2] | |
235 | } {foobar} | |
236 | ||
237 | test {RENAME against non existing source key} { | |
238 | redis_rename $fd nokey foobar | |
239 | } {-ERR*} | |
240 | ||
241 | test {RENAME where source and dest key is the same} { | |
242 | redis_rename $fd mykey mykey | |
243 | } {-ERR*} | |
244 | ||
245 | test {DEL all keys again (DB 0)} { | |
246 | foreach key [redis_keys $fd *] { | |
247 | redis_del $fd $key | |
248 | } | |
249 | redis_dbsize $fd | |
250 | } {0} | |
251 | ||
252 | test {DEL all keys again (DB 1)} { | |
253 | redis_select $fd 1 | |
254 | foreach key [redis_keys $fd *] { | |
255 | redis_del $fd $key | |
256 | } | |
257 | set res [redis_dbsize $fd] | |
258 | redis_select $fd 0 | |
259 | format $res | |
260 | } {0} | |
261 | ||
262 | test {MOVE basic usage} { | |
263 | redis_set $fd mykey foobar | |
264 | redis_move $fd mykey 1 | |
265 | set res {} | |
266 | lappend res [redis_exists $fd mykey] | |
267 | lappend res [redis_dbsize $fd] | |
268 | redis_select $fd 1 | |
269 | lappend res [redis_get $fd mykey] | |
270 | lappend res [redis_dbsize $fd] | |
271 | redis_select $fd 0 | |
272 | format $res | |
273 | } [list 0 0 foobar 1] | |
274 | ||
275 | test {MOVE against key existing in the target DB} { | |
276 | redis_set $fd mykey hello | |
277 | redis_move $fd mykey 1 | |
278 | } {0} | |
279 | ||
280 | test {SET/GET keys in different DBs} { | |
281 | redis_set $fd a hello | |
282 | redis_set $fd b world | |
283 | redis_select $fd 1 | |
284 | redis_set $fd a foo | |
285 | redis_set $fd b bared | |
286 | redis_select $fd 0 | |
287 | set res {} | |
288 | lappend res [redis_get $fd a] | |
289 | lappend res [redis_get $fd b] | |
290 | redis_select $fd 1 | |
291 | lappend res [redis_get $fd a] | |
292 | lappend res [redis_get $fd b] | |
293 | redis_select $fd 0 | |
294 | format $res | |
295 | } {hello world foo bared} | |
296 | ||
297 | test {Basic LPOP/RPOP} { | |
298 | redis_del $fd mylist | |
299 | redis_rpush $fd mylist 1 | |
300 | redis_rpush $fd mylist 2 | |
301 | redis_lpush $fd mylist 0 | |
302 | list [redis_lpop $fd mylist] [redis_rpop $fd mylist] [redis_lpop $fd mylist] [redis_llen $fd mylist] | |
303 | } [list 0 2 1 0] | |
304 | ||
305 | test {LPOP/RPOP against empty list} { | |
306 | redis_lpop $fd mylist | |
307 | } {} | |
308 | ||
309 | test {LPOP against non list value} { | |
310 | redis_set $fd notalist foo | |
311 | redis_lpop $fd notalist | |
312 | } {*ERROR*against*} | |
313 | ||
314 | test {Mass LPUSH/LPOP} { | |
315 | set sum 0 | |
316 | for {set i 0} {$i < 1000} {incr i} { | |
317 | redis_lpush $fd mylist $i | |
318 | incr sum $i | |
319 | } | |
320 | set sum2 0 | |
321 | for {set i 0} {$i < 500} {incr i} { | |
322 | incr sum2 [redis_lpop $fd mylist] | |
323 | incr sum2 [redis_rpop $fd mylist] | |
324 | } | |
325 | expr $sum == $sum2 | |
326 | } {1} | |
327 | ||
328 | test {LRANGE basics} { | |
329 | for {set i 0} {$i < 10} {incr i} { | |
330 | redis_rpush $fd mylist $i | |
331 | } | |
332 | list [redis_lrange $fd mylist 1 -2] \ | |
333 | [redis_lrange $fd mylist -3 -1] \ | |
334 | [redis_lrange $fd mylist 4 4] | |
335 | } {{1 2 3 4 5 6 7 8} {7 8 9} 4} | |
336 | ||
337 | test {LRANGE inverted indexes} { | |
338 | redis_lrange $fd mylist 6 2 | |
339 | } {} | |
340 | ||
341 | test {LRANGE out of range indexes including the full list} { | |
342 | redis_lrange $fd mylist -1000 1000 | |
343 | } {0 1 2 3 4 5 6 7 8 9} | |
344 | ||
345 | test {LRANGE against non existing key} { | |
346 | redis_lrange $fd nosuchkey 0 1 | |
347 | } {} | |
348 | ||
349 | test {LTRIM basics} { | |
350 | redis_del $fd mylist | |
351 | for {set i 0} {$i < 100} {incr i} { | |
352 | redis_lpush $fd mylist $i | |
353 | redis_ltrim $fd mylist 0 4 | |
354 | } | |
355 | redis_lrange $fd mylist 0 -1 | |
356 | } {99 98 97 96 95} | |
357 | ||
358 | test {LSET} { | |
359 | redis_lset $fd mylist 1 foo | |
360 | redis_lset $fd mylist -1 bar | |
361 | redis_lrange $fd mylist 0 -1 | |
362 | } {99 foo 97 96 bar} | |
363 | ||
364 | test {LSET out of range index} { | |
365 | redis_lset $fd mylist 10 foo | |
366 | } {-ERR*range*} | |
367 | ||
368 | test {LSET against non existing key} { | |
369 | redis_lset $fd nosuchkey 10 foo | |
370 | } {-ERR*key*} | |
371 | ||
372 | test {LSET against non list value} { | |
373 | redis_set $fd nolist foobar | |
374 | redis_lset $fd nolist 0 foo | |
375 | } {-ERR*value*} | |
376 | ||
377 | test {SADD, SCARD, SISMEMBER, SMEMBERS basics} { | |
378 | redis_sadd $fd myset foo | |
379 | redis_sadd $fd myset bar | |
380 | list [redis_scard $fd myset] [redis_sismember $fd myset foo] \ | |
381 | [redis_sismember $fd myset bar] [redis_sismember $fd myset bla] \ | |
382 | [lsort [redis_smembers $fd myset]] | |
383 | } {2 1 1 0 {bar foo}} | |
384 | ||
385 | test {SADD adding the same element multiple times} { | |
386 | redis_sadd $fd myset foo | |
387 | redis_sadd $fd myset foo | |
388 | redis_sadd $fd myset foo | |
389 | redis_scard $fd myset | |
390 | } {2} | |
391 | ||
392 | test {SADD against non set} { | |
393 | redis_sadd $fd mylist foo | |
394 | } {-2} | |
395 | ||
396 | test {SREM basics} { | |
397 | redis_sadd $fd myset ciao | |
398 | redis_srem $fd myset foo | |
399 | lsort [redis_smembers $fd myset] | |
400 | } {bar ciao} | |
401 | ||
402 | test {Mass SADD and SINTER with two sets} { | |
403 | for {set i 0} {$i < 1000} {incr i} { | |
404 | redis_sadd $fd set1 $i | |
405 | redis_sadd $fd set2 [expr $i+995] | |
406 | } | |
407 | lsort [redis_sinter $fd set1 set2] | |
408 | } {995 996 997 998 999} | |
409 | ||
410 | test {SINTERSTORE with two sets} { | |
411 | redis_sinterstore $fd setres set1 set2 | |
412 | lsort [redis_smembers $fd setres] | |
413 | } {995 996 997 998 999} | |
414 | ||
415 | test {SINTER against three sets} { | |
416 | redis_sadd $fd set3 999 | |
417 | redis_sadd $fd set3 995 | |
418 | redis_sadd $fd set3 1000 | |
419 | redis_sadd $fd set3 2000 | |
420 | lsort [redis_sinter $fd set1 set2 set3] | |
421 | } {995 999} | |
422 | ||
423 | test {SINTERSTORE with three sets} { | |
424 | redis_sinterstore $fd setres set1 set2 set3 | |
425 | lsort [redis_smembers $fd setres] | |
426 | } {995 999} | |
427 | ||
428 | test {SAVE - make sure there are all the types as values} { | |
429 | redis_lpush $fd mysavelist hello | |
430 | redis_lpush $fd mysavelist world | |
431 | redis_set $fd myemptykey {} | |
432 | redis_set $fd mynormalkey {blablablba} | |
433 | redis_save $fd | |
434 | } {+OK} | |
435 | ||
436 | test {Create a random list} { | |
437 | set tosort {} | |
438 | array set seenrand {} | |
439 | for {set i 0} {$i < 10000} {incr i} { | |
440 | while 1 { | |
441 | # Make sure all the weights are different because | |
442 | # Redis does not use a stable sort but Tcl does. | |
443 | set r [expr int(rand()*1000000)] | |
444 | if {![info exists seenrand($r)]} break | |
445 | } | |
446 | set seenrand($r) x | |
447 | redis_lpush $fd tosort $i | |
448 | redis_set $fd weight_$i $r | |
449 | lappend tosort [list $i $r] | |
450 | } | |
451 | set sorted [lsort -index 1 -real $tosort] | |
452 | set res {} | |
453 | for {set i 0} {$i < 10000} {incr i} { | |
454 | lappend res [lindex $sorted $i 0] | |
455 | } | |
456 | format {} | |
457 | } {} | |
458 | ||
459 | test {SORT with BY against the newly created list} { | |
460 | redis_sort $fd tosort {BY weight_*} | |
461 | } $res | |
462 | ||
463 | test {SORT direct, numeric, against the newly created list} { | |
464 | redis_sort $fd tosort | |
465 | } [lsort -integer $res] | |
466 | ||
467 | test {SORT decreasing sort} { | |
468 | redis_sort $fd tosort {DESC} | |
469 | } [lsort -decreasing -integer $res] | |
470 | ||
471 | test {SORT speed, sorting 10000 elements list using BY, 100 times} { | |
472 | set start [clock clicks -milliseconds] | |
473 | for {set i 0} {$i < 100} {incr i} { | |
474 | set sorted [redis_sort $fd tosort {BY weight_* LIMIT 0 10}] | |
475 | } | |
476 | set elapsed [expr [clock clicks -milliseconds]-$start] | |
477 | puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds " | |
478 | flush stdout | |
479 | format {} | |
480 | } {} | |
481 | ||
482 | test {SORT speed, sorting 10000 elements list directly, 100 times} { | |
483 | set start [clock clicks -milliseconds] | |
484 | for {set i 0} {$i < 100} {incr i} { | |
485 | set sorted [redis_sort $fd tosort {LIMIT 0 10}] | |
486 | } | |
487 | set elapsed [expr [clock clicks -milliseconds]-$start] | |
488 | puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds " | |
489 | flush stdout | |
490 | format {} | |
491 | } {} | |
492 | ||
493 | test {SORT speed, pseudo-sorting 10000 elements list, BY <const>, 100 times} { | |
494 | set start [clock clicks -milliseconds] | |
495 | for {set i 0} {$i < 100} {incr i} { | |
496 | set sorted [redis_sort $fd tosort {BY nokey LIMIT 0 10}] | |
497 | } | |
498 | set elapsed [expr [clock clicks -milliseconds]-$start] | |
499 | puts -nonewline "\n Average time to sort: [expr double($elapsed)/100] milliseconds " | |
500 | flush stdout | |
501 | format {} | |
502 | } {} | |
503 | ||
504 | test {SORT regression for issue #19, sorting floats} { | |
505 | redis_flushdb $fd | |
506 | foreach x {1.1 5.10 3.10 7.44 2.1 5.75 6.12 0.25 1.15} { | |
507 | redis_lpush $fd mylist $x | |
508 | } | |
509 | redis_sort $fd mylist | |
510 | } [lsort -real {1.1 5.10 3.10 7.44 2.1 5.75 6.12 0.25 1.15}] | |
511 | ||
512 | test {LREM, remove all the occurrences} { | |
513 | redis_flushall $fd | |
514 | redis_rpush $fd mylist foo | |
515 | redis_rpush $fd mylist bar | |
516 | redis_rpush $fd mylist foobar | |
517 | redis_rpush $fd mylist foobared | |
518 | redis_rpush $fd mylist zap | |
519 | redis_rpush $fd mylist bar | |
520 | redis_rpush $fd mylist test | |
521 | redis_rpush $fd mylist foo | |
522 | set res [redis_lrem $fd mylist 0 bar] | |
523 | list [redis_lrange $fd mylist 0 -1] $res | |
524 | } {{foo foobar foobared zap test foo} 2} | |
525 | ||
526 | test {LREM, remove the first occurrence} { | |
527 | set res [redis_lrem $fd mylist 1 foo] | |
528 | list [redis_lrange $fd mylist 0 -1] $res | |
529 | } {{foobar foobared zap test foo} 1} | |
530 | ||
531 | test {LREM, remove non existing element} { | |
532 | set res [redis_lrem $fd mylist 1 nosuchelement] | |
533 | list [redis_lrange $fd mylist 0 -1] $res | |
534 | } {{foobar foobared zap test foo} 0} | |
535 | ||
536 | test {LREM, starting from tail with negative count} { | |
537 | redis_flushall $fd | |
538 | redis_rpush $fd mylist foo | |
539 | redis_rpush $fd mylist bar | |
540 | redis_rpush $fd mylist foobar | |
541 | redis_rpush $fd mylist foobared | |
542 | redis_rpush $fd mylist zap | |
543 | redis_rpush $fd mylist bar | |
544 | redis_rpush $fd mylist test | |
545 | redis_rpush $fd mylist foo | |
546 | redis_rpush $fd mylist foo | |
547 | set res [redis_lrem $fd mylist -1 bar] | |
548 | list [redis_lrange $fd mylist 0 -1] $res | |
549 | } {{foo bar foobar foobared zap test foo foo} 1} | |
550 | ||
551 | test {LREM, starting from tail with negative count (2)} { | |
552 | set res [redis_lrem $fd mylist -2 foo] | |
553 | list [redis_lrange $fd mylist 0 -1] $res | |
554 | } {{foo bar foobar foobared zap test} 2} | |
555 | ||
5b19bd72 | 556 | test {MGET} { |
557 | redis_flushall $fd | |
558 | redis_set $fd foo BAR | |
559 | redis_set $fd bar FOO | |
560 | redis_mget $fd foo bar | |
561 | } {BAR FOO} | |
562 | ||
563 | test {MGET against non existing key} { | |
564 | redis_mget $fd foo baazz bar | |
565 | } {BAR {} FOO} | |
566 | ||
567 | test {MGET against non-string key} { | |
568 | redis_sadd $fd myset ciao | |
569 | redis_sadd $fd myset bau | |
570 | redis_mget $fd foo baazz bar myset | |
571 | } {BAR {} FOO {}} | |
572 | ||
ed9b544e | 573 | # Leave the user with a clean DB before to exit |
574 | test {FLUSHALL} { | |
575 | redis_flushall $fd | |
576 | redis_dbsize $fd | |
577 | } {0} | |
578 | ||
579 | puts "\n[expr $::passed+$::failed] tests, $::passed passed, $::failed failed" | |
580 | if {$::failed > 0} { | |
581 | puts "\n*** WARNING!!! $::failed FAILED TESTS ***\n" | |
582 | } | |
583 | close $fd | |
584 | } | |
585 | ||
586 | proc redis_connect {server port} { | |
587 | set fd [socket $server $port] | |
588 | fconfigure $fd -translation binary | |
589 | return $fd | |
590 | } | |
591 | ||
592 | proc redis_write {fd buf} { | |
593 | puts -nonewline $fd $buf | |
594 | } | |
595 | ||
596 | proc redis_writenl {fd buf} { | |
597 | # puts "C: $buf" | |
598 | redis_write $fd $buf | |
599 | redis_write $fd "\r\n" | |
600 | flush $fd | |
601 | } | |
602 | ||
603 | proc redis_readnl {fd len} { | |
604 | set buf [read $fd $len] | |
605 | read $fd 2 ; # discard CR LF | |
606 | return $buf | |
607 | } | |
608 | ||
5b19bd72 | 609 | proc redis_bulk_read {fd {multi 0}} { |
ed9b544e | 610 | set count [redis_read_integer $fd] |
611 | if {$count eq {nil}} return {} | |
5b19bd72 | 612 | if {$multi && $count == -1} return {} |
ed9b544e | 613 | set len [expr {abs($count)}] |
614 | set buf [redis_readnl $fd $len] | |
615 | if {$count < 0} {return "***ERROR*** $buf"} | |
616 | return $buf | |
617 | } | |
618 | ||
619 | proc redis_multi_bulk_read fd { | |
620 | set count [redis_read_integer $fd] | |
621 | if {$count eq {nil}} return {} | |
622 | if {$count < 0} { | |
623 | set len [expr {abs($count)}] | |
624 | set buf [redis_readnl $fd $len] | |
625 | return "***ERROR*** $buf" | |
626 | } | |
627 | set l {} | |
628 | for {set i 0} {$i < $count} {incr i} { | |
5b19bd72 | 629 | lappend l [redis_bulk_read $fd 1] |
ed9b544e | 630 | } |
631 | return $l | |
632 | } | |
633 | ||
634 | proc redis_read_retcode fd { | |
635 | set retcode [string trim [gets $fd]] | |
636 | # puts "S: $retcode" | |
637 | return $retcode | |
638 | } | |
639 | ||
640 | proc redis_read_integer fd { | |
641 | string trim [gets $fd] | |
642 | } | |
643 | ||
644 | ### Actual API ### | |
645 | ||
646 | proc redis_set {fd key val} { | |
647 | redis_writenl $fd "set $key [string length $val]\r\n$val" | |
648 | redis_read_retcode $fd | |
649 | } | |
650 | ||
651 | proc redis_setnx {fd key val} { | |
652 | redis_writenl $fd "setnx $key [string length $val]\r\n$val" | |
653 | redis_read_integer $fd | |
654 | } | |
655 | ||
656 | proc redis_get {fd key} { | |
657 | redis_writenl $fd "get $key" | |
658 | redis_bulk_read $fd | |
659 | } | |
660 | ||
661 | proc redis_select {fd id} { | |
662 | redis_writenl $fd "select $id" | |
663 | redis_read_retcode $fd | |
664 | } | |
665 | ||
666 | proc redis_move {fd key id} { | |
667 | redis_writenl $fd "move $key $id" | |
668 | redis_read_integer $fd | |
669 | } | |
670 | ||
671 | proc redis_del {fd key} { | |
672 | redis_writenl $fd "del $key" | |
673 | redis_read_integer $fd | |
674 | } | |
675 | ||
676 | proc redis_keys {fd pattern} { | |
677 | redis_writenl $fd "keys $pattern" | |
678 | split [redis_bulk_read $fd] | |
679 | } | |
680 | ||
681 | proc redis_dbsize {fd} { | |
682 | redis_writenl $fd "dbsize" | |
683 | redis_read_integer $fd | |
684 | } | |
685 | ||
686 | proc redis_incr {fd key} { | |
687 | redis_writenl $fd "incr $key" | |
688 | redis_read_integer $fd | |
689 | } | |
690 | ||
691 | proc redis_decr {fd key} { | |
692 | redis_writenl $fd "decr $key" | |
693 | redis_read_integer $fd | |
694 | } | |
695 | ||
696 | proc redis_exists {fd key} { | |
697 | redis_writenl $fd "exists $key" | |
698 | redis_read_integer $fd | |
699 | } | |
700 | ||
701 | proc redis_lpush {fd key val} { | |
702 | redis_writenl $fd "lpush $key [string length $val]\r\n$val" | |
703 | redis_read_retcode $fd | |
704 | } | |
705 | ||
706 | proc redis_rpush {fd key val} { | |
707 | redis_writenl $fd "rpush $key [string length $val]\r\n$val" | |
708 | redis_read_retcode $fd | |
709 | } | |
710 | ||
711 | proc redis_llen {fd key} { | |
712 | redis_writenl $fd "llen $key" | |
713 | redis_read_integer $fd | |
714 | } | |
715 | ||
716 | proc redis_scard {fd key} { | |
717 | redis_writenl $fd "scard $key" | |
718 | redis_read_integer $fd | |
719 | } | |
720 | ||
721 | proc redis_lindex {fd key index} { | |
722 | redis_writenl $fd "lindex $key $index" | |
723 | redis_bulk_read $fd | |
724 | } | |
725 | ||
726 | proc redis_lrange {fd key first last} { | |
727 | redis_writenl $fd "lrange $key $first $last" | |
728 | redis_multi_bulk_read $fd | |
729 | } | |
730 | ||
5b19bd72 | 731 | proc redis_mget {fd args} { |
732 | redis_writenl $fd "mget [join $args]" | |
733 | redis_multi_bulk_read $fd | |
734 | } | |
735 | ||
ed9b544e | 736 | proc redis_sort {fd key {params {}}} { |
737 | redis_writenl $fd "sort $key $params" | |
738 | redis_multi_bulk_read $fd | |
739 | } | |
740 | ||
741 | proc redis_ltrim {fd key first last} { | |
742 | redis_writenl $fd "ltrim $key $first $last" | |
743 | redis_read_retcode $fd | |
744 | } | |
745 | ||
746 | proc redis_rename {fd key1 key2} { | |
747 | redis_writenl $fd "rename $key1 $key2" | |
748 | redis_read_retcode $fd | |
749 | } | |
750 | ||
751 | proc redis_renamenx {fd key1 key2} { | |
752 | redis_writenl $fd "renamenx $key1 $key2" | |
753 | redis_read_integer $fd | |
754 | } | |
755 | ||
756 | proc redis_lpop {fd key} { | |
757 | redis_writenl $fd "lpop $key" | |
758 | redis_bulk_read $fd | |
759 | } | |
760 | ||
761 | proc redis_rpop {fd key} { | |
762 | redis_writenl $fd "rpop $key" | |
763 | redis_bulk_read $fd | |
764 | } | |
765 | ||
766 | proc redis_lset {fd key index val} { | |
767 | redis_writenl $fd "lset $key $index [string length $val]\r\n$val" | |
768 | redis_read_retcode $fd | |
769 | } | |
770 | ||
771 | proc redis_sadd {fd key val} { | |
772 | redis_writenl $fd "sadd $key [string length $val]\r\n$val" | |
773 | redis_read_integer $fd | |
774 | } | |
775 | ||
776 | proc redis_srem {fd key val} { | |
777 | redis_writenl $fd "srem $key [string length $val]\r\n$val" | |
778 | redis_read_integer $fd | |
779 | } | |
780 | ||
781 | proc redis_sismember {fd key val} { | |
782 | redis_writenl $fd "sismember $key [string length $val]\r\n$val" | |
783 | redis_read_integer $fd | |
784 | } | |
785 | ||
786 | proc redis_sinter {fd args} { | |
5a6948fb | 787 | redis_writenl $fd "sinter [join $args]" |
ed9b544e | 788 | redis_multi_bulk_read $fd |
789 | } | |
790 | ||
791 | proc redis_sinterstore {fd args} { | |
5a6948fb | 792 | redis_writenl $fd "sinterstore [join $args]" |
ed9b544e | 793 | redis_read_retcode $fd |
794 | } | |
795 | ||
796 | proc redis_smembers {fd key} { | |
5a6948fb | 797 | redis_writenl $fd "smembers $key" |
ed9b544e | 798 | redis_multi_bulk_read $fd |
799 | } | |
800 | ||
801 | proc redis_echo {fd str} { | |
5a6948fb | 802 | redis_writenl $fd "echo [string length $str]\r\n$str" |
803 | redis_writenl $fd "smembers $key" | |
ed9b544e | 804 | } |
805 | ||
806 | proc redis_save {fd} { | |
5a6948fb | 807 | redis_writenl $fd "save" |
ed9b544e | 808 | redis_read_retcode $fd |
809 | } | |
810 | ||
811 | proc redis_flushall {fd} { | |
5a6948fb | 812 | redis_writenl $fd "flushall" |
ed9b544e | 813 | redis_read_retcode $fd |
814 | } | |
815 | ||
816 | proc redis_flushdb {fd} { | |
5a6948fb | 817 | redis_writenl $fd "flushdb" |
ed9b544e | 818 | redis_read_retcode $fd |
819 | } | |
820 | ||
821 | proc redis_lrem {fd key count val} { | |
822 | redis_writenl $fd "lrem $key $count [string length $val]\r\n$val" | |
823 | redis_read_integer $fd | |
824 | } | |
825 | ||
5a6948fb | 826 | proc stress {} { |
827 | set fd [socket 127.0.0.1 6379] | |
828 | fconfigure $fd -translation binary | |
829 | redis_flushall $fd | |
830 | while 1 { | |
831 | set randkey [expr int(rand()*10000)] | |
832 | set randval [expr int(rand()*10000)] | |
833 | set randidx0 [expr int(rand()*10)] | |
834 | set randidx1 [expr int(rand()*10)] | |
835 | set cmd [expr int(rand()*10)] | |
836 | if {$cmd == 0} {redis_set $fd $randkey $randval} | |
837 | if {$cmd == 1} {redis_get $fd $randkey} | |
838 | if {$cmd == 2} {redis_incr $fd $randkey} | |
839 | if {$cmd == 3} {redis_lpush $fd $randkey $randval} | |
840 | if {$cmd == 4} {redis_rpop $fd $randkey} | |
841 | if {$cmd == 5} {redis_del $fd $randkey} | |
842 | if {$cmd == 6} {redis_lrange $fd $randkey $randidx0 $randidx1} | |
843 | if {$cmd == 7} {redis_ltrim $fd $randkey $randidx0 $randidx1} | |
844 | if {$cmd == 8} {redis_lindex $fd $randkey $randidx0} | |
845 | if {$cmd == 9} {redis_lset $fd $randkey $randidx0 $randval} | |
846 | flush stdout | |
847 | } | |
848 | close $fd | |
849 | } | |
850 | ||
ed9b544e | 851 | if {[llength $argv] == 0} { |
852 | main 127.0.0.1 6379 | |
5a6948fb | 853 | } elseif {[llength $argv] == 1 && [lindex $argv 0] eq {stress}} { |
854 | stress | |
ed9b544e | 855 | } else { |
856 | main [lindex $argv 0] [lindex $argv 1] | |
857 | } |