Commit d7971f96 authored by Oran Agra's avatar Oran Agra
Browse files

Merge remote-tracking branch 'origin/unstable' into 7.0

parents d2b5a579 acfb4f7a
......@@ -86,6 +86,14 @@ start_server {tags {"pause network"}} {
$rd close
}
test "Test may-replicate commands are rejected in ro script by pause RO" {
r client PAUSE 60000 WRITE
assert_error {ERR May-replicate commands are not allowed when client pause write*} {
r EVAL_RO "return redis.call('publish','ch','msg')" 0
}
r client unpause
}
test "Test multiple clients can be queued up and unblocked" {
r client PAUSE 60000 WRITE
set clients [list [redis_deferring_client] [redis_deferring_client] [redis_deferring_client]]
......
......@@ -3,7 +3,7 @@ proc get_reply_buffer_size {cname} {
set clients [split [string trim [r client list]] "\r\n"]
set c [lsearch -inline $clients *name=$cname*]
if {![regexp rbs=(\[a-zA-Z0-9-\]+) $c - rbufsize]} {
error "field rbus not found in $c"
error "field rbs not found in $c"
}
return $rbufsize
}
......@@ -12,7 +12,7 @@ start_server {tags {"replybufsize"}} {
test {verify reply buffer limits} {
# In order to reduce test time we can set the peak reset time very low
r debug replybuffer-peak-reset-time 100
r debug replybuffer peak-reset-time 100
# Create a simple idle test client
variable tc [redis_client]
......@@ -29,7 +29,7 @@ start_server {tags {"replybufsize"}} {
r set bigval [string repeat x 32768]
# In order to reduce test time we can set the peak reset time very low
r debug replybuffer-peak-reset-time never
r debug replybuffer peak-reset-time never
wait_for_condition 10 100 {
[$tc get bigval ; get_reply_buffer_size test_client] >= 16384 && [get_reply_buffer_size test_client] < 32768
......@@ -39,7 +39,7 @@ start_server {tags {"replybufsize"}} {
}
# Restore the peak reset time to default
r debug replybuffer-peak-reset-time reset
r debug replybuffer peak-reset-time reset
$tc close
} {0} {needs:debug}
......
......@@ -15,17 +15,25 @@ if {$is_eval == 1} {
}
} else {
proc run_script {args} {
r function load LUA test replace [format "redis.register_function('test', function(KEYS, ARGV)\n %s \nend)" [lindex $args 0]]
r function load replace [format "#!lua name=test\nredis.register_function('test', function(KEYS, ARGV)\n %s \nend)" [lindex $args 0]]
if {[r readingraw] eq 1} {
# read name
assert_equal {test} [r read]
}
r fcall test {*}[lrange $args 1 end]
}
proc run_script_ro {args} {
r function load LUA test replace [format "redis.register_function{function_name='test', callback=function(KEYS, ARGV)\n %s \nend, flags={'no-writes'}}" [lindex $args 0]]
r function load replace [format "#!lua name=test\nredis.register_function{function_name='test', callback=function(KEYS, ARGV)\n %s \nend, flags={'no-writes'}}" [lindex $args 0]]
if {[r readingraw] eq 1} {
# read name
assert_equal {test} [r read]
}
r fcall_ro test {*}[lrange $args 1 end]
}
proc run_script_on_connection {args} {
set rd [lindex $args 0]
$rd function load LUA test replace [format "redis.register_function('test', function(KEYS, ARGV)\n %s \nend)" [lindex $args 1]]
# read the ok reply of function create
$rd function load replace [format "#!lua name=test\nredis.register_function('test', function(KEYS, ARGV)\n %s \nend)" [lindex $args 1]]
# read name
$rd read
$rd fcall test {*}[lrange $args 2 end]
}
......@@ -784,7 +792,7 @@ start_server {tags {"scripting"}} {
set buf "*3\r\n\$4\r\neval\r\n\$33\r\nwhile 1 do redis.call('ping') end\r\n\$1\r\n0\r\n"
append buf "*1\r\n\$4\r\nping\r\n"
} else {
set buf "*6\r\n\$8\r\nfunction\r\n\$4\r\nload\r\n\$3\r\nlua\r\n\$4\r\ntest\r\n\$7\r\nreplace\r\n\$81\r\nredis.register_function('test', function() while 1 do redis.call('ping') end end)\r\n"
set buf "*4\r\n\$8\r\nfunction\r\n\$4\r\nload\r\n\$7\r\nreplace\r\n\$97\r\n#!lua name=test\nredis.register_function('test', function() while 1 do redis.call('ping') end end)\r\n"
append buf "*3\r\n\$5\r\nfcall\r\n\$4\r\ntest\r\n\$1\r\n0\r\n"
append buf "*1\r\n\$4\r\nping\r\n"
}
......@@ -808,8 +816,8 @@ start_server {tags {"scripting"}} {
assert_equal [r ping] "PONG"
if {$is_eval == 0} {
# read the ok reply of function create
assert_match {OK} [$rd read]
# read the function name
assert_match {test} [$rd read]
}
catch {$rd read} res
......@@ -1399,6 +1407,19 @@ start_server {tags {"scripting"}} {
r config set replica-serve-stale-data yes
set _ {}
} {} {external:skip}
test "reject script do not cause a Lua stack leak" {
r config set maxmemory 1
for {set i 0} {$i < 50} {incr i} {
assert_error {OOM allow-oom flag is not set on the script, can not run it when used memory > 'maxmemory'} {r eval {#!lua
return 1
} 0}
}
r config set maxmemory 0
assert_equal [r eval {#!lua
return 1
} 0] 1
}
}
# Additional eval only tests
......
......@@ -66,3 +66,39 @@ start_server {tags {"shutdown external:skip"}} {
}
}
}
start_server {tags {"shutdown external:skip"}} {
set pid [s process_id]
set dump_rdb [file join [lindex [r config get dir] 1] dump.rdb]
test {RDB save will be failed in shutdown} {
for {set i 0} {$i < 20} {incr i} {
r set $i $i
}
# create a folder called 'dump.rdb' to trigger temp-rdb rename failure
# and it will cause rdb save to fail eventually.
if {[file exists $dump_rdb]} {
exec rm -f $dump_rdb
}
exec mkdir -p $dump_rdb
}
test {SHUTDOWN will abort if rdb save failed on signal} {
# trigger a shutdown which will save an rdb
exec kill -SIGINT $pid
wait_for_log_messages 0 {"*Error trying to save the DB, can't exit*"} 0 100 10
}
test {SHUTDOWN will abort if rdb save failed on shutdown command} {
catch {[r shutdown]} err
assert_match {*Errors trying to SHUTDOWN*} $err
# make sure the server is still alive
assert_equal [r ping] {PONG}
}
test {SHUTDOWN can proceed if shutdown command was with nosave} {
catch {[r shutdown nosave]}
wait_for_log_messages 0 {"*ready to exit, bye bye*"} 0 100 10
}
test {Clean up rdb same named folder} {
exec rm -r $dump_rdb
}
}
......@@ -205,6 +205,113 @@ start_server {
$rd close
}
test {Blocking XREADGROUP: key deleted} {
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
set rd [redis_deferring_client]
$rd XREADGROUP GROUP mygroup Alice BLOCK 0 STREAMS mystream ">"
r DEL mystream
assert_error "*no longer exists*" {$rd read}
$rd close
}
test {Blocking XREADGROUP: key type changed with SET} {
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
set rd [redis_deferring_client]
$rd XREADGROUP GROUP mygroup Alice BLOCK 0 STREAMS mystream ">"
r SET mystream val1
assert_error "*no longer exists*" {$rd read}
$rd close
}
test {Blocking XREADGROUP: key type changed with transaction} {
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
set rd [redis_deferring_client]
$rd XREADGROUP GROUP mygroup Alice BLOCK 0 STREAMS mystream ">"
r MULTI
r DEL mystream
r SADD mystream e1
r EXEC
assert_error "*no longer exists*" {$rd read}
$rd close
}
test {Blocking XREADGROUP: flushed DB} {
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
set rd [redis_deferring_client]
$rd XREADGROUP GROUP mygroup Alice BLOCK 0 STREAMS mystream ">"
r FLUSHALL
assert_error "*no longer exists*" {$rd read}
$rd close
}
test {Blocking XREADGROUP: swapped DB, key doesn't exist} {
r SELECT 4
r FLUSHDB
r SELECT 9
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
set rd [redis_deferring_client]
$rd SELECT 9
$rd read
$rd XREADGROUP GROUP mygroup Alice BLOCK 0 STREAMS mystream ">"
r SWAPDB 4 9
assert_error "*no longer exists*" {$rd read}
$rd close
} {0} {external:skip}
test {Blocking XREADGROUP: swapped DB, key is not a stream} {
r SELECT 4
r FLUSHDB
r LPUSH mystream e1
r SELECT 9
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
set rd [redis_deferring_client]
$rd SELECT 9
$rd read
$rd XREADGROUP GROUP mygroup Alice BLOCK 0 STREAMS mystream ">"
r SWAPDB 4 9
assert_error "*no longer exists*" {$rd read}
$rd close
} {0} {external:skip}
test {Blocking XREAD: key deleted} {
r DEL mystream
r XADD mystream 666 f v
set rd [redis_deferring_client]
$rd XREAD BLOCK 0 STREAMS mystream "$"
r DEL mystream
r XADD mystream 667 f v
set res [$rd read]
assert_equal [lindex $res 0 1 0] {667-0 {f v}}
$rd close
}
test {Blocking XREAD: key type changed with SET} {
r DEL mystream
r XADD mystream 666 f v
set rd [redis_deferring_client]
$rd XREAD BLOCK 0 STREAMS mystream "$"
r SET mystream val1
r DEL mystream
r XADD mystream 667 f v
set res [$rd read]
assert_equal [lindex $res 0 1 0] {667-0 {f v}}
$rd close
}
test {Blocking XREADGROUP for stream that ran dry (issue #5299)} {
set rd [redis_deferring_client]
......
......@@ -2399,4 +2399,12 @@ start_server {tags {"zset"}} {
r config set zset-max-ziplist-value $original_max_value
}
test {zset score double range} {
set dblmax 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000000000000
r del zz
r zadd zz $dblmax dblmax
assert_encoding listpack zz
r zscore zz dblmax
} {1.7976931348623157e+308}
}
......@@ -3,3 +3,4 @@ config.sh
*.aof
*.conf
*.log
appendonlydir-*
Hash table implementation related utilities.
rehashing.c
---
Visually show buckets in the two hash tables between rehashings. Also stress
test getRandomKeys() implementation, that may actually disappear from
Redis soon, However the visualization code is reusable in new bugs
investigation.
Compile with:
cc -I ../../src/ rehashing.c ../../src/zmalloc.c ../../src/dict.c -o rehashing_test
#include "redis.h"
#include "dict.h"
void _redisAssert(char *x, char *y, int l) {
printf("ASSERT: %s %s %d\n",x,y,l);
exit(1);
}
unsigned int dictKeyHash(const void *keyp) {
unsigned long key = (unsigned long)keyp;
key = dictGenHashFunction(&key,sizeof(key));
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
int dictKeyCompare(void *privdata, const void *key1, const void *key2) {
unsigned long k1 = (unsigned long)key1;
unsigned long k2 = (unsigned long)key2;
return k1 == k2;
}
dictType dictTypeTest = {
dictKeyHash, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
dictKeyCompare, /* key compare */
NULL, /* key destructor */
NULL, /* val destructor */
NULL /* allow to expand */
};
void showBuckets(dictht ht) {
if (ht.table == NULL) {
printf("NULL\n");
} else {
int j;
for (j = 0; j < ht.size; j++) {
printf("%c", ht.table[j] ? '1' : '0');
}
printf("\n");
}
}
void show(dict *d) {
int j;
if (d->rehashidx != -1) {
printf("rhidx: ");
for (j = 0; j < d->rehashidx; j++)
printf(".");
printf("|\n");
}
printf("ht[0]: ");
showBuckets(d->ht[0]);
printf("ht[1]: ");
showBuckets(d->ht[1]);
printf("\n");
}
int sortPointers(const void *a, const void *b) {
unsigned long la, lb;
la = (long) (*((dictEntry**)a));
lb = (long) (*((dictEntry**)b));
return la-lb;
}
void stressGetKeys(dict *d, int times, int *perfect_run, int *approx_run) {
int j;
dictEntry **des = zmalloc(sizeof(dictEntry*)*dictSize(d));
for (j = 0; j < times; j++) {
int requested = rand() % (dictSize(d)+1);
int returned = dictGetSomeKeys(d, des, requested);
int dup = 0;
qsort(des,returned,sizeof(dictEntry*),sortPointers);
if (returned > 1) {
int i;
for (i = 0; i < returned-1; i++) {
if (des[i] == des[i+1]) dup++;
}
}
if (requested == returned && dup == 0) {
(*perfect_run)++;
} else {
(*approx_run)++;
printf("Requested, returned, duplicated: %d %d %d\n",
requested, returned, dup);
}
}
zfree(des);
}
#define MAX1 120
#define MAX2 1000
int main(void) {
dict *d = dictCreate(&dictTypeTest,NULL);
unsigned long i;
srand(time(NULL));
for (i = 0; i < MAX1; i++) {
dictAdd(d,(void*)i,NULL);
show(d);
}
printf("Size: %d\n", (int)dictSize(d));
for (i = 0; i < MAX1; i++) {
dictDelete(d,(void*)i);
dictResize(d);
show(d);
}
dictRelease(d);
d = dictCreate(&dictTypeTest,NULL);
printf("Stress testing dictGetSomeKeys\n");
int perfect_run = 0, approx_run = 0;
for (i = 0; i < MAX2; i++) {
dictAdd(d,(void*)i,NULL);
stressGetKeys(d,100,&perfect_run,&approx_run);
}
for (i = 0; i < MAX2; i++) {
dictDelete(d,(void*)i);
dictResize(d);
stressGetKeys(d,100,&perfect_run,&approx_run);
}
printf("dictGetSomeKey, %d perfect runs, %d approximated runs\n",
perfect_run, approx_run);
dictRelease(d);
printf("TEST PASSED!\n");
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment