Commit 819d291b authored by Oran Agra's avatar Oran Agra
Browse files

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

parents a51eb05b 936cfa46
...@@ -404,13 +404,14 @@ start_server {tags {"other external:skip"}} { ...@@ -404,13 +404,14 @@ start_server {tags {"other external:skip"}} {
assert_match "*/redis-server" [lindex $cmdline 1] assert_match "*/redis-server" [lindex $cmdline 1]
if {$::tls} { if {$::tls} {
set expect_port 0 set expect_port [srv 0 pport]
set expect_tls_port [srv 0 port] set expect_tls_port [srv 0 port]
set port [srv 0 pport]
} else { } else {
set expect_port [srv 0 port] set expect_port [srv 0 port]
set expect_tls_port 0 set expect_tls_port 0
}
set port [srv 0 port] set port [srv 0 port]
}
assert_equal "$::host:$port" [lindex $cmdline 2] assert_equal "$::host:$port" [lindex $cmdline 2]
assert_equal $expect_port [lindex $cmdline 3] assert_equal $expect_port [lindex $cmdline 3]
......
...@@ -188,7 +188,7 @@ start_server {tags {"pubsub network"}} { ...@@ -188,7 +188,7 @@ start_server {tags {"pubsub network"}} {
assert_equal {0} [punsubscribe $rd ch*] assert_equal {0} [punsubscribe $rd ch*]
$rd close $rd close
} } {0} {resp3}
test "PUNSUBSCRIBE from non-subscribed channels" { test "PUNSUBSCRIBE from non-subscribed channels" {
set rd1 [redis_deferring_client] set rd1 [redis_deferring_client]
...@@ -451,4 +451,56 @@ start_server {tags {"pubsub network"}} { ...@@ -451,4 +451,56 @@ start_server {tags {"pubsub network"}} {
assert_equal "pmessage * __keyevent@${db}__:new bar" [$rd1 read] assert_equal "pmessage * __keyevent@${db}__:new bar" [$rd1 read]
$rd1 close $rd1 close
} }
test "publish to self inside multi" {
r hello 3
r subscribe foo
r multi
r ping abc
r publish foo bar
r publish foo vaz
r ping def
assert_equal [r exec] {abc 1 1 def}
assert_equal [r read] {message foo bar}
assert_equal [r read] {message foo vaz}
} {} {resp3}
test "publish to self inside script" {
r hello 3
r subscribe foo
set res [r eval {
redis.call("ping","abc")
redis.call("publish","foo","bar")
redis.call("publish","foo","vaz")
redis.call("ping","def")
return "bla"} 0]
assert_equal $res {bla}
assert_equal [r read] {message foo bar}
assert_equal [r read] {message foo vaz}
} {} {resp3}
test "unsubscribe inside multi, and publish to self" {
r hello 3
# Note: SUBSCRIBE and UNSUBSCRIBE with multiple channels in the same command,
# breaks the multi response, see https://github.com/redis/redis/issues/12207
# this is just a temporary sanity test to detect unintended breakage.
# subscribe for 3 channels actually emits 3 "responses"
assert_equal "subscribe foo 1" [r subscribe foo bar baz]
assert_equal "subscribe bar 2" [r read]
assert_equal "subscribe baz 3" [r read]
r multi
r ping abc
r unsubscribe bar
r unsubscribe baz
r ping def
assert_equal [r exec] {abc {unsubscribe bar 2} {unsubscribe baz 1} def}
# published message comes after the publish command's response.
assert_equal [r publish foo vaz] {1}
assert_equal [r read] {message foo vaz}
} {} {resp3}
} }
start_server {tags {"quit"}} { start_server {tags {"quit"}} {
proc format_command {args} {
set cmd "*[llength $args]\r\n"
foreach a $args {
append cmd "$[string length $a]\r\n$a\r\n"
}
set _ $cmd
}
test "QUIT returns OK" { test "QUIT returns OK" {
reconnect reconnect
......
...@@ -98,6 +98,108 @@ start_server {tags {"scan network"}} { ...@@ -98,6 +98,108 @@ start_server {tags {"scan network"}} {
assert_equal 1000 [llength $keys] assert_equal 1000 [llength $keys]
} }
test "SCAN unknown type" {
r flushdb
# make sure that passive expiration is triggered by the scan
r debug set-active-expire 0
populate 1000
r hset hash f v
r pexpire hash 1
after 2
# TODO: remove this in redis 8.0
set cur 0
set keys {}
while 1 {
set res [r scan $cur type "string1"]
set cur [lindex $res 0]
set k [lindex $res 1]
lappend keys {*}$k
if {$cur == 0} break
}
assert_equal 0 [llength $keys]
# make sure that expired key have been removed by scan command
assert_equal 1000 [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d]
# TODO: uncomment in redis 8.0
#assert_error "*unknown type name*" {r scan 0 type "string1"}
# expired key will be no touched by scan command
#assert_equal 1001 [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d]
r debug set-active-expire 1
} {OK} {needs:debug}
test "SCAN with expired keys" {
r flushdb
# make sure that passive expiration is triggered by the scan
r debug set-active-expire 0
populate 1000
r set foo bar
r pexpire foo 1
# add a hash type key
r hset hash f v
r pexpire hash 1
after 2
set cur 0
set keys {}
while 1 {
set res [r scan $cur count 10]
set cur [lindex $res 0]
set k [lindex $res 1]
lappend keys {*}$k
if {$cur == 0} break
}
assert_equal 1000 [llength $keys]
# make sure that expired key have been removed by scan command
assert_equal 1000 [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d]
r debug set-active-expire 1
} {OK} {needs:debug}
test "SCAN with expired keys with TYPE filter" {
r flushdb
# make sure that passive expiration is triggered by the scan
r debug set-active-expire 0
populate 1000
r set foo bar
r pexpire foo 1
# add a hash type key
r hset hash f v
r pexpire hash 1
after 2
set cur 0
set keys {}
while 1 {
set res [r scan $cur type "string" count 10]
set cur [lindex $res 0]
set k [lindex $res 1]
lappend keys {*}$k
if {$cur == 0} break
}
assert_equal 1000 [llength $keys]
# make sure that expired key have been removed by scan command
assert_equal 1000 [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d]
# TODO: uncomment in redis 8.0
# make sure that only the expired key in the type match will been removed by scan command
#assert_equal 1001 [scan [regexp -inline {keys\=([\d]*)} [r info keyspace]] keys=%d]
r debug set-active-expire 1
} {OK} {needs:debug}
foreach enc {intset listpack hashtable} { foreach enc {intset listpack hashtable} {
test "SSCAN with encoding $enc" { test "SSCAN with encoding $enc" {
# Create the Set # Create the Set
......
...@@ -324,6 +324,66 @@ start_server {tags {"scripting"}} { ...@@ -324,6 +324,66 @@ start_server {tags {"scripting"}} {
} 0 } 0
} {a b} } {a b}
test {EVAL - JSON smoke test} {
run_script {
local some_map = {
s1="Some string",
n1=100,
a1={"Some","String","Array"},
nil1=nil,
b1=true,
b2=false}
local encoded = cjson.encode(some_map)
local decoded = cjson.decode(encoded)
assert(table.concat(some_map) == table.concat(decoded))
cjson.encode_keep_buffer(false)
encoded = cjson.encode(some_map)
decoded = cjson.decode(encoded)
assert(table.concat(some_map) == table.concat(decoded))
-- Table with numeric keys
local table1 = {one="one", [1]="one"}
encoded = cjson.encode(table1)
decoded = cjson.decode(encoded)
assert(decoded["one"] == table1["one"])
assert(decoded["1"] == table1[1])
-- Array
local array1 = {[1]="one", [2]="two"}
encoded = cjson.encode(array1)
decoded = cjson.decode(encoded)
assert(table.concat(array1) == table.concat(decoded))
-- Invalid keys
local invalid_map = {}
invalid_map[false] = "false"
local ok, encoded = pcall(cjson.encode, invalid_map)
assert(ok == false)
-- Max depth
cjson.encode_max_depth(1)
ok, encoded = pcall(cjson.encode, some_map)
assert(ok == false)
cjson.decode_max_depth(1)
ok, decoded = pcall(cjson.decode, '{"obj": {"array": [1,2,3,4]}}')
assert(ok == false)
-- Invalid numbers
ok, encoded = pcall(cjson.encode, {num1=0/0})
assert(ok == false)
cjson.encode_invalid_numbers(true)
ok, encoded = pcall(cjson.encode, {num1=0/0})
assert(ok == true)
-- Restore defaults
cjson.decode_max_depth(1000)
cjson.encode_max_depth(1000)
cjson.encode_invalid_numbers(false)
} 0
}
test {EVAL - cmsgpack can pack double?} { test {EVAL - cmsgpack can pack double?} {
run_script {local encoded = cmsgpack.pack(0.1) run_script {local encoded = cmsgpack.pack(0.1)
local h = "" local h = ""
...@@ -344,6 +404,68 @@ start_server {tags {"scripting"}} { ...@@ -344,6 +404,68 @@ start_server {tags {"scripting"}} {
} 0 } 0
} {d3ffffff0000000000} } {d3ffffff0000000000}
test {EVAL - cmsgpack pack/unpack smoke test} {
run_script {
local str_lt_32 = string.rep("x", 30)
local str_lt_255 = string.rep("x", 250)
local str_lt_65535 = string.rep("x", 65530)
local str_long = string.rep("x", 100000)
local array_lt_15 = {1, 2, 3, 4, 5}
local array_lt_65535 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
local array_big = {}
for i=1, 100000 do
array_big[i] = i
end
local map_lt_15 = {a=1, b=2}
local map_big = {}
for i=1, 100000 do
map_big[tostring(i)] = i
end
local some_map = {
s1=str_lt_32,
s2=str_lt_255,
s3=str_lt_65535,
s4=str_long,
d1=0.1,
i1=1,
i2=250,
i3=65530,
i4=100000,
i5=2^40,
i6=-1,
i7=-120,
i8=-32000,
i9=-100000,
i10=-3147483648,
a1=array_lt_15,
a2=array_lt_65535,
a3=array_big,
m1=map_lt_15,
m2=map_big,
b1=false,
b2=true,
n=nil
}
local encoded = cmsgpack.pack(some_map)
local decoded = cmsgpack.unpack(encoded)
assert(table.concat(some_map) == table.concat(decoded))
local offset, decoded_one = cmsgpack.unpack_one(encoded, 0)
assert(table.concat(some_map) == table.concat(decoded_one))
assert(offset == -1)
local encoded_multiple = cmsgpack.pack(str_lt_32, str_lt_255, str_lt_65535, str_long)
local offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, 0)
assert(obj == str_lt_32)
offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, offset)
assert(obj == str_lt_255)
offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, offset)
assert(obj == str_lt_65535)
offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, offset)
assert(obj == str_long)
assert(offset == -1)
} 0
}
test {EVAL - cmsgpack can pack and unpack circular references?} { test {EVAL - cmsgpack can pack and unpack circular references?} {
run_script {local a = {x=nil,y=5} run_script {local a = {x=nil,y=5}
local b = {x=a} local b = {x=a}
...@@ -525,6 +647,7 @@ start_server {tags {"scripting"}} { ...@@ -525,6 +647,7 @@ start_server {tags {"scripting"}} {
} ;# is_eval } ;# is_eval
test {EVAL does not leak in the Lua stack} { test {EVAL does not leak in the Lua stack} {
r script flush ;# reset Lua VM
r set x 0 r set x 0
# Use a non blocking client to speedup the loop. # Use a non blocking client to speedup the loop.
set rd [redis_deferring_client] set rd [redis_deferring_client]
......
...@@ -350,7 +350,7 @@ start_server {tags {"hash"}} { ...@@ -350,7 +350,7 @@ start_server {tags {"hash"}} {
set _ $rv set _ $rv
} {{{} {}} {{} {}} {{} {}}} } {{{} {}} {{} {}} {{} {}}}
test {HMGET HRANDFIELD HGET HGETALL HDEL HINCRBY HINCRBYFLOAT HSTRLEN against wrong type} { test {Hash commands against wrong type} {
r set wrongtype somevalue r set wrongtype somevalue
assert_error "WRONGTYPE Operation against a key*" {r hmget wrongtype field1 field2} assert_error "WRONGTYPE Operation against a key*" {r hmget wrongtype field1 field2}
assert_error "WRONGTYPE Operation against a key*" {r hrandfield wrongtype} assert_error "WRONGTYPE Operation against a key*" {r hrandfield wrongtype}
...@@ -360,6 +360,9 @@ start_server {tags {"hash"}} { ...@@ -360,6 +360,9 @@ start_server {tags {"hash"}} {
assert_error "WRONGTYPE Operation against a key*" {r hincrby wrongtype field1 2} assert_error "WRONGTYPE Operation against a key*" {r hincrby wrongtype field1 2}
assert_error "WRONGTYPE Operation against a key*" {r hincrbyfloat wrongtype field1 2.5} assert_error "WRONGTYPE Operation against a key*" {r hincrbyfloat wrongtype field1 2.5}
assert_error "WRONGTYPE Operation against a key*" {r hstrlen wrongtype field1} assert_error "WRONGTYPE Operation against a key*" {r hstrlen wrongtype field1}
assert_error "WRONGTYPE Operation against a key*" {r hvals wrongtype}
assert_error "WRONGTYPE Operation against a key*" {r hkeys wrongtype}
assert_error "WRONGTYPE Operation against a key*" {r hexists wrongtype field1}
} }
test {HMGET - small hash} { test {HMGET - small hash} {
......
...@@ -2312,4 +2312,52 @@ foreach {pop} {BLPOP BLMPOP_RIGHT} { ...@@ -2312,4 +2312,52 @@ foreach {pop} {BLPOP BLMPOP_RIGHT} {
$rd close $rd close
} }
test {Command being unblocked cause another command to get unblocked execution order test} {
r del src{t} dst{t} key1{t} key2{t} key3{t}
set repl [attach_to_replication_stream]
set rd1 [redis_deferring_client]
set rd2 [redis_deferring_client]
set rd3 [redis_deferring_client]
$rd1 blmove src{t} dst{t} left right 0
wait_for_blocked_clients_count 1
$rd2 blmove dst{t} src{t} right left 0
wait_for_blocked_clients_count 2
# Create a pipeline of commands that will be processed in one socket read.
# Insert two set commands before and after lpush to observe the execution order.
set buf ""
append buf "set key1{t} value1\r\n"
append buf "lpush src{t} dummy\r\n"
append buf "set key2{t} value2\r\n"
$rd3 write $buf
$rd3 flush
wait_for_blocked_clients_count 0
r set key3{t} value3
# If a command being unblocked causes another command to get unblocked, like a BLMOVE would do,
# then the new unblocked command will get processed right away rather than wait for later.
# If the set command occurs between two lmove commands, the results are not as expected.
assert_replication_stream $repl {
{select *}
{set key1{t} value1}
{lpush src{t} dummy}
{lmove src{t} dst{t} left right}
{lmove dst{t} src{t} right left}
{set key2{t} value2}
{set key3{t} value3}
}
$rd1 close
$rd2 close
$rd3 close
close_replication_stream $repl
} {} {needs:repl}
} ;# stop servers } ;# stop servers
...@@ -53,14 +53,18 @@ start_server { ...@@ -53,14 +53,18 @@ start_server {
assert_equal {16 17} [lsort [r smembers myset]] assert_equal {16 17} [lsort [r smembers myset]]
} }
test {SMISMEMBER against non set} { test {SMISMEMBER SMEMBERS SCARD against non set} {
r lpush mylist foo r lpush mylist foo
assert_error WRONGTYPE* {r smismember mylist bar} assert_error WRONGTYPE* {r smismember mylist bar}
assert_error WRONGTYPE* {r smembers mylist}
assert_error WRONGTYPE* {r scard mylist}
} }
test {SMISMEMBER non existing key} { test {SMISMEMBER SMEMBERS SCARD against non existing key} {
assert_equal {0} [r smismember myset1 foo] assert_equal {0} [r smismember myset1 foo]
assert_equal {0 0} [r smismember myset1 foo bar] assert_equal {0 0} [r smismember myset1 foo bar]
assert_equal {} [r smembers myset1]
assert_equal {0} [r scard myset1]
} }
test {SMISMEMBER requires one or more members} { test {SMISMEMBER requires one or more members} {
...@@ -109,14 +113,61 @@ start_server { ...@@ -109,14 +113,61 @@ start_server {
assert_equal {1} [r smismember myset 213244124402402314402033402] assert_equal {1} [r smismember myset 213244124402402314402033402]
} }
test "SADD overflows the maximum allowed integers in an intset" { foreach type {single multiple single_multiple} {
test "SADD overflows the maximum allowed integers in an intset - $type" {
r del myset r del myset
if {$type == "single"} {
# All are single sadd commands.
for {set i 0} {$i < 512} {incr i} { r sadd myset $i } for {set i 0} {$i < 512} {incr i} { r sadd myset $i }
} elseif {$type == "multiple"} {
# One sadd command to add all elements.
set args {}
for {set i 0} {$i < 512} {incr i} { lappend args $i }
r sadd myset {*}$args
} elseif {$type == "single_multiple"} {
# First one sadd adds an element (creates a key) and then one sadd adds all elements.
r sadd myset 1
set args {}
for {set i 0} {$i < 512} {incr i} { lappend args $i }
r sadd myset {*}$args
}
assert_encoding intset myset assert_encoding intset myset
assert_equal 512 [r scard myset]
assert_equal 1 [r sadd myset 512] assert_equal 1 [r sadd myset 512]
assert_encoding hashtable myset assert_encoding hashtable myset
} }
test "SADD overflows the maximum allowed elements in a listpack - $type" {
r del myset
if {$type == "single"} {
# All are single sadd commands.
r sadd myset a
for {set i 0} {$i < 127} {incr i} { r sadd myset $i }
} elseif {$type == "multiple"} {
# One sadd command to add all elements.
set args {}
lappend args a
for {set i 0} {$i < 127} {incr i} { lappend args $i }
r sadd myset {*}$args
} elseif {$type == "single_multiple"} {
# First one sadd adds an element (creates a key) and then one sadd adds all elements.
r sadd myset a
set args {}
lappend args a
for {set i 0} {$i < 127} {incr i} { lappend args $i }
r sadd myset {*}$args
}
assert_encoding listpack myset
assert_equal 128 [r scard myset]
assert_equal 1 [r sadd myset b]
assert_encoding hashtable myset
}
}
test {Variadic SADD} { test {Variadic SADD} {
r del myset r del myset
assert_equal 3 [r sadd myset a b c] assert_equal 3 [r sadd myset a b c]
...@@ -714,6 +765,7 @@ start_server { ...@@ -714,6 +765,7 @@ start_server {
assert_encoding $type myset assert_encoding $type myset
set res [r spop myset 30] set res [r spop myset 30]
assert {[lsort $content] eq [lsort $res]} assert {[lsort $content] eq [lsort $res]}
assert_equal {0} [r exists myset]
} }
test "SPOP new implementation: code path #2 $type" { test "SPOP new implementation: code path #2 $type" {
...@@ -737,6 +789,29 @@ start_server { ...@@ -737,6 +789,29 @@ start_server {
} }
} }
test "SPOP new implementation: code path #1 propagate as DEL or UNLINK" {
r del myset1{t} myset2{t}
r sadd myset1{t} 1 2 3 4 5
r sadd myset2{t} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
set repl [attach_to_replication_stream]
r config set lazyfree-lazy-server-del no
r spop myset1{t} [r scard myset1{t}]
r config set lazyfree-lazy-server-del yes
r spop myset2{t} [r scard myset2{t}]
assert_equal {0} [r exists myset1{t} myset2{t}]
# Verify the propagate of DEL and UNLINK.
assert_replication_stream $repl {
{select *}
{del myset1{t}}
{unlink myset2{t}}
}
close_replication_stream $repl
} {} {needs:repl}
test "SRANDMEMBER count of 0 is handled correctly" { test "SRANDMEMBER count of 0 is handled correctly" {
r srandmember myset 0 r srandmember myset 0
} {} } {}
...@@ -927,6 +1002,129 @@ start_server { ...@@ -927,6 +1002,129 @@ start_server {
} }
} }
proc is_rehashing {myset} {
set htstats [r debug HTSTATS-KEY $myset]
return [string match {*rehashing target*} $htstats]
}
proc rem_hash_set_top_N {myset n} {
set cursor 0
set members {}
set enough 0
while 1 {
set res [r sscan $myset $cursor]
set cursor [lindex $res 0]
set k [lindex $res 1]
foreach m $k {
lappend members $m
if {[llength $members] >= $n} {
set enough 1
break
}
}
if {$enough || $cursor == 0} {
break
}
}
r srem $myset {*}$members
}
test "SRANDMEMBER with a dict containing long chain" {
set origin_save [config_get_set save ""]
set origin_max_lp [config_get_set set-max-listpack-entries 0]
set origin_save_delay [config_get_set rdb-key-save-delay 2147483647]
# 1) Create a hash set with 100000 members.
set members {}
for {set i 0} {$i < 100000} {incr i} {
lappend members [format "m:%d" $i]
}
create_set myset $members
# 2) Wait for the hash set rehashing to finish.
while {[is_rehashing myset]} {
r srandmember myset 100
}
# 3) Turn off the rehashing of this set, and remove the members to 500.
r bgsave
rem_hash_set_top_N myset [expr {[r scard myset] - 500}]
assert_equal [r scard myset] 500
# 4) Kill RDB child process to restart rehashing.
set pid1 [get_child_pid 0]
catch {exec kill -9 $pid1}
waitForBgsave r
# 5) Let the set hash to start rehashing
r spop myset 1
assert [is_rehashing myset]
# 6) Verify that when rdb saving is in progress, rehashing will still be performed (because
# the ratio is extreme) by waiting for it to finish during an active bgsave.
r bgsave
while {[is_rehashing myset]} {
r srandmember myset 1
}
if {$::verbose} {
puts [r debug HTSTATS-KEY myset full]
}
set pid1 [get_child_pid 0]
catch {exec kill -9 $pid1}
waitForBgsave r
# 7) Check that eventually, SRANDMEMBER returns all elements.
array set allmyset {}
foreach ele [r smembers myset] {
set allmyset($ele) 1
}
unset -nocomplain auxset
set iterations 1000
while {$iterations != 0} {
incr iterations -1
set res [r srandmember myset -10]
foreach ele $res {
set auxset($ele) 1
}
if {[lsort [array names allmyset]] eq
[lsort [array names auxset]]} {
break;
}
}
assert {$iterations != 0}
# 8) Remove the members to 30 in order to calculate the value of Chi-Square Distribution,
# otherwise we would need more iterations.
rem_hash_set_top_N myset [expr {[r scard myset] - 30}]
assert_equal [r scard myset] 30
assert {[is_rehashing myset]}
# Now that we have a hash set with only one long chain bucket.
set htstats [r debug HTSTATS-KEY myset full]
assert {[regexp {different slots: ([0-9]+)} $htstats - different_slots]}
assert {[regexp {max chain length: ([0-9]+)} $htstats - max_chain_length]}
assert {$different_slots == 1 && $max_chain_length == 30}
# 9) Use positive count (PATH 4) to get 10 elements (out of 30) each time.
unset -nocomplain allkey
set iterations 1000
while {$iterations != 0} {
incr iterations -1
set res [r srandmember myset 10]
foreach ele $res {
lappend allkey $ele
}
}
# validate even distribution of random sampling (df = 29, 73 means 0.00001 probability)
assert_lessthan [chi_square_value $allkey] 73
r config set save $origin_save
r config set set-max-listpack-entries $origin_max_lp
r config set rdb-key-save-delay $origin_save_delay
} {OK} {needs:debug slow}
proc setup_move {} { proc setup_move {} {
r del myset3{t} myset4{t} r del myset3{t} myset4{t}
create_set myset1{t} {1 a b} create_set myset1{t} {1 a b}
......
...@@ -314,6 +314,14 @@ start_server { ...@@ -314,6 +314,14 @@ start_server {
$rd close $rd close
} {0} {external:skip} } {0} {external:skip}
test {XREAD and XREADGROUP against wrong parameter} {
r DEL mystream
r XADD mystream 666 f v
r XGROUP CREATE mystream mygroup $
assert_error "ERR Unbalanced 'xreadgroup' list of streams: for each stream key an ID or '>' must be specified." {r XREADGROUP GROUP mygroup Alice COUNT 1 STREAMS mystream }
assert_error "ERR Unbalanced 'xread' list of streams: for each stream key an ID or '$' must be specified." {r XREAD COUNT 1 STREAMS mystream }
}
test {Blocking XREAD: key deleted} { test {Blocking XREAD: key deleted} {
r DEL mystream r DEL mystream
r XADD mystream 666 f v r XADD mystream 666 f v
...@@ -467,6 +475,29 @@ start_server { ...@@ -467,6 +475,29 @@ start_server {
$rd close $rd close
} }
test {Blocking XREADGROUP for stream key that has clients blocked on list - avoid endless loop} {
r DEL mystream
r XGROUP CREATE mystream mygroup $ MKSTREAM
set rd1 [redis_deferring_client]
set rd2 [redis_deferring_client]
set rd3 [redis_deferring_client]
$rd1 xreadgroup GROUP mygroup myuser COUNT 10 BLOCK 10000 STREAMS mystream >
$rd2 xreadgroup GROUP mygroup myuser COUNT 10 BLOCK 10000 STREAMS mystream >
$rd3 xreadgroup GROUP mygroup myuser COUNT 10 BLOCK 10000 STREAMS mystream >
wait_for_blocked_clients_count 3
r xadd mystream MAXLEN 5000 * field1 value1 field2 value2 field3 value3
$rd1 close
$rd2 close
$rd3 close
assert_equal [r ping] {PONG}
}
test {XGROUP DESTROY should unblock XREADGROUP with -NOGROUP} { test {XGROUP DESTROY should unblock XREADGROUP with -NOGROUP} {
r config resetstat r config resetstat
r del mystream r del mystream
......
...@@ -234,6 +234,11 @@ start_server {tags {"string"}} { ...@@ -234,6 +234,11 @@ start_server {tags {"string"}} {
assert_error {*wrong number of arguments for 'msetnx' command} {r msetnx x{t} 20 y{t} "foo bar" z{t}} assert_error {*wrong number of arguments for 'msetnx' command} {r msetnx x{t} 20 y{t} "foo bar" z{t}}
} }
test {MSET with already existing - same key twice} {
r set x{t} x
list [r mset x{t} xxx x{t} yyy] [r get x{t}]
} {OK yyy}
test {MSETNX with already existent key} { test {MSETNX with already existent key} {
list [r msetnx x1{t} xxx y2{t} yyy x{t} 20] [r exists x1{t}] [r exists y2{t}] list [r msetnx x1{t} xxx y2{t} yyy x{t} 20] [r exists x1{t}] [r exists y2{t}]
} {0 0 0} } {0 0 0}
......
...@@ -132,7 +132,7 @@ start_server {tags {"zset"}} { ...@@ -132,7 +132,7 @@ start_server {tags {"zset"}} {
} }
test "ZSET element can't be set to NaN with ZINCRBY - $encoding" { test "ZSET element can't be set to NaN with ZINCRBY - $encoding" {
assert_error "*not*float*" {r zadd myzset nan abc} assert_error "*not*float*" {r zincrby myzset nan abc}
} }
test "ZADD with options syntax error with incomplete pair - $encoding" { test "ZADD with options syntax error with incomplete pair - $encoding" {
...@@ -450,7 +450,7 @@ start_server {tags {"zset"}} { ...@@ -450,7 +450,7 @@ start_server {tags {"zset"}} {
assert_equal $nullres [r zrevrank zranktmp foo] assert_equal $nullres [r zrevrank zranktmp foo]
r readraw 0 r readraw 0
# withscores # withscore
set nullres {*-1} set nullres {*-1}
if {$::force_resp3} { if {$::force_resp3} {
set nullres {_} set nullres {_}
...@@ -2285,7 +2285,9 @@ start_server {tags {"zset"}} { ...@@ -2285,7 +2285,9 @@ start_server {tags {"zset"}} {
r config set zset-max-listpack-entries 0 r config set zset-max-listpack-entries 0
r del z1{t} z2{t} r del z1{t} z2{t}
r zadd z1{t} 1 a r zadd z1{t} 1 a
assert_encoding skiplist z1{t}
assert_equal 1 [r zrangestore z2{t} z1{t} 0 -1] assert_equal 1 [r zrangestore z2{t} z1{t} 0 -1]
assert_encoding skiplist z2{t}
r config set zset-max-listpack-entries $original_max r config set zset-max-listpack-entries $original_max
} }
...@@ -2616,4 +2618,37 @@ start_server {tags {"zset"}} { ...@@ -2616,4 +2618,37 @@ start_server {tags {"zset"}} {
r config set set-max-listpack-entries 128 r config set set-max-listpack-entries 128
r config set zset-max-listpack-entries 128 r config set zset-max-listpack-entries 128
} }
foreach type {single multiple single_multiple} {
test "ZADD overflows the maximum allowed elements in a listpack - $type" {
r del myzset
set max_entries 64
set original_max [lindex [r config get zset-max-listpack-entries] 1]
r config set zset-max-listpack-entries $max_entries
if {$type == "single"} {
# All are single zadd commands.
for {set i 0} {$i < $max_entries} {incr i} { r zadd myzset $i $i }
} elseif {$type == "multiple"} {
# One zadd command to add all elements.
set args {}
for {set i 0} {$i < $max_entries * 2} {incr i} { lappend args $i }
r zadd myzset {*}$args
} elseif {$type == "single_multiple"} {
# First one zadd adds an element (creates a key) and then one zadd adds all elements.
r zadd myzset 1 1
set args {}
for {set i 0} {$i < $max_entries * 2} {incr i} { lappend args $i }
r zadd myzset {*}$args
}
assert_encoding listpack myzset
assert_equal $max_entries [r zcard myzset]
assert_equal 1 [r zadd myzset 1 b]
assert_encoding skiplist myzset
r config set zset-max-listpack-entries $original_max
}
}
} }
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