networking.c/writeToClient: handle WSAEWOULDBLOCK
- fixed writeToClient() after failed tests - adjusted tests to match antirez/redis@4.0.2
This commit is contained in:
+11
-3
@@ -939,6 +939,14 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
server.el, c, c->buf, NULL);
|
||||
if (result == SOCKET_ERROR && errno != WSA_IO_PENDING) {
|
||||
nwritten = -1;
|
||||
|
||||
//[tporadowski/#11] we might be bursting data too fast, so turn it into another try that will put back the client
|
||||
// in the sending queue
|
||||
if (errno == WSAEWOULDBLOCK) {
|
||||
serverLog(LL_DEBUG, "writeToClient: will try again (EAGAIN) due to WSAEWOULDBLOCK");
|
||||
errno = EAGAIN;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#else
|
||||
@@ -1002,7 +1010,7 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
if (listLength(c->reply) == 0)
|
||||
serverAssert(c->reply_bytes == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Note that we avoid to send more than NET_MAX_WRITES_PER_EVENT
|
||||
* bytes, in a single threaded server it's a good idea to serve
|
||||
* other clients as well, even if a very large request comes from
|
||||
@@ -1014,7 +1022,7 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
if (totwritten > NET_MAX_WRITES_PER_EVENT &&
|
||||
(server.maxmemory == 0 ||
|
||||
zmalloc_used_memory() < server.maxmemory)) break;
|
||||
}
|
||||
}
|
||||
server.stat_net_output_bytes += totwritten;
|
||||
if (nwritten == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
@@ -1070,7 +1078,7 @@ int writeToClient(int fd, client *c, int handler_installed) {
|
||||
}
|
||||
#endif
|
||||
return C_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write event handler. Just send data to the client. */
|
||||
void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Redis configuration for testing.
|
||||
|
||||
#always-show-logo yes
|
||||
notify-keyspace-events KEA
|
||||
daemonize no
|
||||
pidfile /var/run/redis.pid
|
||||
|
||||
@@ -59,6 +59,7 @@ array set content {}
|
||||
set tribpid {}
|
||||
|
||||
test "Cluster consistency during live resharding" {
|
||||
set ele 0
|
||||
for {set j 0} {$j < $numops} {incr j} {
|
||||
# Trigger the resharding once we execute half the ops.
|
||||
if {$tribpid ne {} &&
|
||||
@@ -87,7 +88,7 @@ test "Cluster consistency during live resharding" {
|
||||
# Write random data to random list.
|
||||
set listid [randomInt $numkeys]
|
||||
set key "key:$listid"
|
||||
set ele [randomValue]
|
||||
incr ele
|
||||
# We write both with Lua scripts and with plain commands.
|
||||
# This way we are able to stress Lua -> Redis command invocation
|
||||
# as well, that has tests to prevent Lua to write into wrong
|
||||
@@ -116,7 +117,9 @@ test "Cluster consistency during live resharding" {
|
||||
test "Verify $numkeys keys for consistency with logical content" {
|
||||
# Check that the Redis Cluster content matches our logical content.
|
||||
foreach {key value} [array get content] {
|
||||
assert {[$cluster lrange $key 0 -1] eq $value}
|
||||
if {[$cluster lrange $key 0 -1] ne $value} {
|
||||
fail "Key $key expected to hold '$value' but actual content is [$cluster lrange $key 0 -1]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +137,9 @@ test "Cluster should eventually be up again" {
|
||||
test "Verify $numkeys keys after the crash & restart" {
|
||||
# Check that the Redis Cluster content matches our logical content.
|
||||
foreach {key value} [array get content] {
|
||||
assert {[$cluster lrange $key 0 -1] eq $value}
|
||||
if {[$cluster lrange $key 0 -1] ne $value} {
|
||||
fail "Key $key expected to hold '$value' but actual content is [$cluster lrange $key 0 -1]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,10 +69,9 @@ tags {"aof"} {
|
||||
assert_equal 1 [is_alive $srv]
|
||||
}
|
||||
|
||||
test "Truncated AOF loaded: we expect foo to be equal to 6 now" {
|
||||
assert_equal 1 [is_alive $srv]
|
||||
set client [redis [dict get $srv host] [dict get $srv port]]
|
||||
|
||||
set client [redis [dict get $srv host] [dict get $srv port]]
|
||||
test "Truncated AOF loaded: we expect foo to be equal to 6 now" {
|
||||
assert {[$client get foo] eq "6"}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# Issue 3899 regression test.
|
||||
# We create a chain of three instances: master -> slave -> slave2
|
||||
# and continuously break the link while traffic is generated by
|
||||
# redis-benchmark. At the end we check that the data is the same
|
||||
# everywhere.
|
||||
|
||||
start_server {tags {"psync2"}} {
|
||||
start_server {} {
|
||||
start_server {} {
|
||||
# Config
|
||||
set debug_msg 0 ; # Enable additional debug messages
|
||||
|
||||
set no_exit 0 ; # Do not exit at end of the test
|
||||
|
||||
set duration 20 ; # Total test seconds
|
||||
|
||||
for {set j 0} {$j < 3} {incr j} {
|
||||
set R($j) [srv [expr 0-$j] client]
|
||||
set R_host($j) [srv [expr 0-$j] host]
|
||||
set R_port($j) [srv [expr 0-$j] port]
|
||||
if {$debug_msg} {puts "Log file: [srv [expr 0-$j] stdout]"}
|
||||
}
|
||||
|
||||
# Setup the replication and backlog parameters
|
||||
test "PSYNC2 #3899 regression: setup" {
|
||||
$R(1) slaveof $R_host(0) $R_port(0)
|
||||
$R(2) slaveof $R_host(0) $R_port(0)
|
||||
$R(0) set foo bar
|
||||
wait_for_condition 50 1000 {
|
||||
[$R(1) dbsize] == 1 && [$R(2) dbsize] == 1
|
||||
} else {
|
||||
fail "Slaves not replicating from master"
|
||||
}
|
||||
$R(0) config set repl-backlog-size 10mb
|
||||
$R(1) config set repl-backlog-size 10mb
|
||||
}
|
||||
|
||||
set cycle_start_time [clock milliseconds]
|
||||
set bench_pid [exec src/redis-benchmark -p $R_port(0) -n 10000000 -r 1000 incr __rand_int__ > /dev/null &]
|
||||
while 1 {
|
||||
set elapsed [expr {[clock milliseconds]-$cycle_start_time}]
|
||||
if {$elapsed > $duration*1000} break
|
||||
if {rand() < .05} {
|
||||
test "PSYNC2 #3899 regression: kill first slave" {
|
||||
$R(1) client kill type master
|
||||
}
|
||||
}
|
||||
if {rand() < .05} {
|
||||
test "PSYNC2 #3899 regression: kill chained slave" {
|
||||
$R(2) client kill type master
|
||||
}
|
||||
}
|
||||
after 100
|
||||
}
|
||||
exec kill -9 $bench_pid
|
||||
|
||||
if {$debug_msg} {
|
||||
for {set j 0} {$j < 100} {incr j} {
|
||||
if {
|
||||
[$R(0) debug digest] == [$R(1) debug digest] &&
|
||||
[$R(1) debug digest] == [$R(2) debug digest]
|
||||
} break
|
||||
puts [$R(0) debug digest]
|
||||
puts [$R(1) debug digest]
|
||||
puts [$R(2) debug digest]
|
||||
after 1000
|
||||
}
|
||||
}
|
||||
|
||||
test "PSYNC2 #3899 regression: verify consistency" {
|
||||
wait_for_condition 50 1000 {
|
||||
([$R(0) debug digest] eq [$R(1) debug digest]) &&
|
||||
([$R(1) debug digest] eq [$R(2) debug digest])
|
||||
} else {
|
||||
fail "The three instances have different data sets"
|
||||
}
|
||||
}
|
||||
}}}
|
||||
@@ -0,0 +1,182 @@
|
||||
start_server {tags {"psync2"}} {
|
||||
start_server {} {
|
||||
start_server {} {
|
||||
start_server {} {
|
||||
start_server {} {
|
||||
set master_id 0 ; # Current master
|
||||
set start_time [clock seconds] ; # Test start time
|
||||
set counter_value 0 ; # Current value of the Redis counter "x"
|
||||
|
||||
# Config
|
||||
set debug_msg 0 ; # Enable additional debug messages
|
||||
|
||||
set no_exit 0; ; # Do not exit at end of the test
|
||||
|
||||
set duration 20 ; # Total test seconds
|
||||
|
||||
set genload 1 ; # Load master with writes at every cycle
|
||||
|
||||
set genload_time 5000 ; # Writes duration time in ms
|
||||
|
||||
set disconnect 1 ; # Break replication link between random
|
||||
# master and slave instances while the
|
||||
# master is loaded with writes.
|
||||
|
||||
set disconnect_period 1000 ; # Disconnect repl link every N ms.
|
||||
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
set R($j) [srv [expr 0-$j] client]
|
||||
set R_host($j) [srv [expr 0-$j] host]
|
||||
set R_port($j) [srv [expr 0-$j] port]
|
||||
if {$debug_msg} {puts "Log file: [srv [expr 0-$j] stdout]"}
|
||||
}
|
||||
|
||||
set cycle 1
|
||||
while {([clock seconds]-$start_time) < $duration} {
|
||||
test "PSYNC2: --- CYCLE $cycle ---" {
|
||||
incr cycle
|
||||
}
|
||||
|
||||
# Create a random replication layout.
|
||||
# Start with switching master (this simulates a failover).
|
||||
|
||||
# 1) Select the new master.
|
||||
set master_id [randomInt 5]
|
||||
set used [list $master_id]
|
||||
test "PSYNC2: \[NEW LAYOUT\] Set #$master_id as master" {
|
||||
$R($master_id) slaveof no one
|
||||
if {$counter_value == 0} {
|
||||
$R($master_id) set x $counter_value
|
||||
}
|
||||
}
|
||||
|
||||
# 2) Attach all the slaves to a random instance
|
||||
while {[llength $used] != 5} {
|
||||
while 1 {
|
||||
set slave_id [randomInt 5]
|
||||
if {[lsearch -exact $used $slave_id] == -1} break
|
||||
}
|
||||
set rand [randomInt [llength $used]]
|
||||
set mid [lindex $used $rand]
|
||||
set master_host $R_host($mid)
|
||||
set master_port $R_port($mid)
|
||||
|
||||
test "PSYNC2: Set #$slave_id to replicate from #$mid" {
|
||||
$R($slave_id) slaveof $master_host $master_port
|
||||
}
|
||||
lappend used $slave_id
|
||||
}
|
||||
|
||||
# 3) Increment the counter and wait for all the instances
|
||||
# to converge.
|
||||
test "PSYNC2: cluster is consistent after failover" {
|
||||
$R($master_id) incr x; incr counter_value
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
wait_for_condition 50 1000 {
|
||||
[$R($j) get x] == $counter_value
|
||||
} else {
|
||||
fail "Instance #$j x variable is inconsistent"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 4) Generate load while breaking the connection of random
|
||||
# slave-master pairs.
|
||||
test "PSYNC2: generate load while killing replication links" {
|
||||
set t [clock milliseconds]
|
||||
set next_break [expr {$t+$disconnect_period}]
|
||||
while {[clock milliseconds]-$t < $genload_time} {
|
||||
if {$genload} {
|
||||
$R($master_id) incr x; incr counter_value
|
||||
}
|
||||
if {[clock milliseconds] == $next_break} {
|
||||
set next_break \
|
||||
[expr {[clock milliseconds]+$disconnect_period}]
|
||||
set slave_id [randomInt 5]
|
||||
if {$disconnect} {
|
||||
$R($slave_id) client kill type master
|
||||
if {$debug_msg} {
|
||||
puts "+++ Breaking link for slave #$slave_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 5) Increment the counter and wait for all the instances
|
||||
set x [$R($master_id) get x]
|
||||
test "PSYNC2: cluster is consistent after load (x = $x)" {
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
wait_for_condition 50 1000 {
|
||||
[$R($j) get x] == $counter_value
|
||||
} else {
|
||||
fail "Instance #$j x variable is inconsistent"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Put down the old master so that it cannot generate more
|
||||
# replication stream, this way in the next master switch, the time at
|
||||
# which we move slaves away is not important, each will have full
|
||||
# history (otherwise PINGs will make certain slaves have more history),
|
||||
# and sometimes a full resync will be needed.
|
||||
$R($master_id) slaveof 127.0.0.1 0 ;# We use port zero to make it fail.
|
||||
|
||||
if {$debug_msg} {
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
puts "$j: sync_full: [status $R($j) sync_full]"
|
||||
puts "$j: id1 : [status $R($j) master_replid]:[status $R($j) master_repl_offset]"
|
||||
puts "$j: id2 : [status $R($j) master_replid2]:[status $R($j) second_repl_offset]"
|
||||
puts "$j: backlog : firstbyte=[status $R($j) repl_backlog_first_byte_offset] len=[status $R($j) repl_backlog_histlen]"
|
||||
puts "---"
|
||||
}
|
||||
}
|
||||
|
||||
test "PSYNC2: total sum of full synchronizations is exactly 4" {
|
||||
set sum 0
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
incr sum [status $R($j) sync_full]
|
||||
}
|
||||
assert {$sum == 4}
|
||||
}
|
||||
}
|
||||
|
||||
test "PSYNC2: Bring the master back again for next test" {
|
||||
$R($master_id) slaveof no one
|
||||
set master_host $R_host($master_id)
|
||||
set master_port $R_port($master_id)
|
||||
for {set j 0} {$j < 5} {incr j} {
|
||||
if {$j == $master_id} continue
|
||||
$R($j) slaveof $master_host $master_port
|
||||
}
|
||||
|
||||
# Wait for slaves to sync
|
||||
wait_for_condition 50 1000 {
|
||||
[status $R($master_id) connected_slaves] == 4
|
||||
} else {
|
||||
fail "Slave not reconnecting"
|
||||
}
|
||||
}
|
||||
|
||||
test "PSYNC2: Partial resync after restart using RDB aux fields" {
|
||||
# Pick a random slave
|
||||
set slave_id [expr {($master_id+1)%5}]
|
||||
set sync_count [status $R($master_id) sync_full]
|
||||
catch {
|
||||
$R($slave_id) config rewrite
|
||||
$R($slave_id) debug restart
|
||||
}
|
||||
wait_for_condition 50 1000 {
|
||||
[status $R($master_id) connected_slaves] == 4
|
||||
} else {
|
||||
fail "Slave not reconnecting"
|
||||
}
|
||||
set new_sync_count [status $R($master_id) sync_full]
|
||||
assert {$sync_count == $new_sync_count}
|
||||
}
|
||||
|
||||
if {$no_exit} {
|
||||
while 1 { puts -nonewline .; flush stdout; after 1000}
|
||||
}
|
||||
|
||||
}}}}}
|
||||
@@ -50,7 +50,6 @@ proc start_server_and_kill_it {overrides code} {
|
||||
kill_server $srv
|
||||
}
|
||||
|
||||
if { $::tcl_platform(platform) != "windows" } {
|
||||
# Make the RDB file unreadable
|
||||
file attributes [file join $server_path dump.rdb] -permissions 0222
|
||||
|
||||
@@ -67,7 +66,7 @@ if {!$isroot} {
|
||||
test {Server should not start if RDB file can't be open} {
|
||||
wait_for_condition 50 100 {
|
||||
[string match {*Fatal error loading*} \
|
||||
[exec tail -n1 < [dict get $srv stdout]]]
|
||||
[exec tail -1 < [dict get $srv stdout]]]
|
||||
} else {
|
||||
fail "Server started even if RDB was unreadable!"
|
||||
}
|
||||
@@ -90,11 +89,10 @@ close $fd
|
||||
start_server_and_kill_it [list "dir" $server_path] {
|
||||
test {Server should not start if RDB is corrupted} {
|
||||
wait_for_condition 50 100 {
|
||||
[string match {*RDB checksum*} \
|
||||
[exec tail -n10 < [dict get $srv stdout]]]
|
||||
[string match {*CRC error*} \
|
||||
[exec tail -10 < [dict get $srv stdout]]]
|
||||
} else {
|
||||
fail "Server started even if RDB was corrupted!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@ start_server {tags {"repl"}} {
|
||||
start_server {} {
|
||||
test {First server should have role slave after SLAVEOF} {
|
||||
r -1 slaveof [srv 0 host] [srv 0 port]
|
||||
if { $::tcl_platform(platform) == "windows" } {
|
||||
after 2000
|
||||
} else {
|
||||
after 1000
|
||||
}
|
||||
after 1000
|
||||
s -1 role
|
||||
} {slave}
|
||||
|
||||
@@ -14,9 +10,7 @@ start_server {tags {"repl"}} {
|
||||
r config set min-slaves-to-write 1
|
||||
r config set min-slaves-max-lag 10
|
||||
r set foo 12345
|
||||
|
||||
#WIN_PORT_FIX 'wait_for_condition 50 100' -> 'wait_for_condition 50 250'
|
||||
wait_for_condition 50 250 {
|
||||
wait_for_condition 50 100 {
|
||||
[r -1 get foo] eq {12345}
|
||||
} else {
|
||||
fail "Write did not reached slave"
|
||||
@@ -75,9 +69,6 @@ start_server {tags {"repl"}} {
|
||||
test {MASTER and SLAVE dataset should be identical after complex ops} {
|
||||
createComplexDataset r 10000
|
||||
after 500
|
||||
wait_for_condition 50 100 {
|
||||
[r debug digest] eq [r -1 debug digest]
|
||||
} else {
|
||||
if {[r debug digest] ne [r -1 debug digest]} {
|
||||
set csv1 [csvdump r]
|
||||
set csv2 [csvdump {r -1}]
|
||||
@@ -90,7 +81,6 @@ start_server {tags {"repl"}} {
|
||||
puts "Master - Slave inconsistency"
|
||||
puts "Run diff -u against /tmp/repldump*.txt for more info"
|
||||
}
|
||||
}
|
||||
assert_equal [r debug digest] [r -1 debug digest]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@ start_server {tags {"repl"}} {
|
||||
after 4000 ;# Make sure everything expired before taking the digest
|
||||
r keys * ;# Force DEL syntesizing to slave
|
||||
after 1000 ;# Wait another second. Now everything should be fine.
|
||||
wait_for_condition 50 100 {
|
||||
[r debug digest] eq [r -1 debug digest]
|
||||
} else {
|
||||
if {[r debug digest] ne [r -1 debug digest]} {
|
||||
set csv1 [csvdump r]
|
||||
set csv2 [csvdump {r -1}]
|
||||
@@ -31,9 +28,20 @@ start_server {tags {"repl"}} {
|
||||
puts "Master - Slave inconsistency"
|
||||
puts "Run diff -u against /tmp/repldump*.txt for more info"
|
||||
}
|
||||
}
|
||||
assert_equal [r debug digest] [r -1 debug digest]
|
||||
}
|
||||
|
||||
test {Slave is able to evict keys created in writable slaves} {
|
||||
r -1 select 5
|
||||
assert {[r -1 dbsize] == 0}
|
||||
r -1 config set slave-read-only no
|
||||
r -1 set key1 1 ex 5
|
||||
r -1 set key2 2 ex 5
|
||||
r -1 set key3 3 ex 5
|
||||
assert {[r -1 dbsize] == 3}
|
||||
after 6000
|
||||
r -1 dbsize
|
||||
} {0}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ proc test_psync {descr duration backlog_size backlog_ttl delay cond diskless rec
|
||||
|
||||
# Check that the background clients are actually writing.
|
||||
test {Detect write load to master} {
|
||||
wait_for_condition 50 100 {
|
||||
wait_for_condition 50 1000 {
|
||||
[$master dbsize] > 100
|
||||
} else {
|
||||
fail "Can't detect write load from background clients."
|
||||
@@ -90,6 +90,7 @@ proc test_psync {descr duration backlog_size backlog_ttl delay cond diskless rec
|
||||
incr retry -1
|
||||
}
|
||||
assert {[$master dbsize] > 0}
|
||||
|
||||
if {[$master debug digest] ne [$slave debug digest]} {
|
||||
set csv1 [csvdump r]
|
||||
set csv2 [csvdump {r -1}]
|
||||
@@ -127,7 +128,7 @@ foreach diskless {no yes} {
|
||||
test_psync {no reconnection, just sync} 6 1000000 3600 0 {
|
||||
} $diskless 0
|
||||
|
||||
test_psync {ok psync} 6 1000000 3600 0 {
|
||||
test_psync {ok psync} 6 100000000 3600 0 {
|
||||
assert {[s -1 sync_partial_ok] > 0}
|
||||
} $diskless 1
|
||||
|
||||
|
||||
@@ -243,9 +243,7 @@ foreach dl {no yes} {
|
||||
|
||||
# Make sure that slaves and master have same
|
||||
# number of keys
|
||||
|
||||
#WIN_PORT_FIX 'wait_for_condition 500 100' -> 'wait_for_condition 200 250'
|
||||
wait_for_condition 200 250 {
|
||||
wait_for_condition 500 100 {
|
||||
[$master dbsize] == [[lindex $slaves 0] dbsize] &&
|
||||
[$master dbsize] == [[lindex $slaves 1] dbsize] &&
|
||||
[$master dbsize] == [[lindex $slaves 2] dbsize]
|
||||
@@ -255,24 +253,13 @@ foreach dl {no yes} {
|
||||
|
||||
# Check digests
|
||||
set digest [$master debug digest]
|
||||
set digest0 [[lindex $slaves 0] debug digest]
|
||||
set digest1 [[lindex $slaves 1] debug digest]
|
||||
set digest2 [[lindex $slaves 2] debug digest]
|
||||
assert {$digest ne 0000000000000000000000000000000000000000}
|
||||
|
||||
if { $::tcl_platform(platform) == "windows" } {
|
||||
wait_for_condition 200 250 {
|
||||
$digest eq [[lindex $slaves 0] debug digest] &&
|
||||
$digest eq [[lindex $slaves 1] debug digest] &&
|
||||
$digest eq [[lindex $slaves 2] debug digest]
|
||||
} else {
|
||||
fail "slave digest not equal to master digest"
|
||||
}
|
||||
} else {
|
||||
set digest0 [[lindex $slaves 0] debug digest]
|
||||
set digest1 [[lindex $slaves 1] debug digest]
|
||||
set digest2 [[lindex $slaves 2] debug digest]
|
||||
assert {$digest eq $digest0}
|
||||
assert {$digest eq $digest1}
|
||||
assert {$digest eq $digest2}
|
||||
}
|
||||
assert {$digest eq $digest0}
|
||||
assert {$digest eq $digest1}
|
||||
assert {$digest eq $digest2}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Test conditions where an instance is considered to be down
|
||||
|
||||
source "../tests/includes/init-tests.tcl"
|
||||
|
||||
proc ensure_master_up {} {
|
||||
wait_for_condition 1000 50 {
|
||||
[dict get [S 4 sentinel master mymaster] flags] eq "master"
|
||||
} else {
|
||||
fail "Master flags are not just 'master'"
|
||||
}
|
||||
}
|
||||
|
||||
proc ensure_master_down {} {
|
||||
wait_for_condition 1000 50 {
|
||||
[string match *down* \
|
||||
[dict get [S 4 sentinel master mymaster] flags]]
|
||||
} else {
|
||||
fail "Master is not flagged SDOWN"
|
||||
}
|
||||
}
|
||||
|
||||
test "Crash the majority of Sentinels to prevent failovers for this unit" {
|
||||
for {set id 0} {$id < $quorum} {incr id} {
|
||||
kill_instance sentinel $id
|
||||
}
|
||||
}
|
||||
|
||||
test "SDOWN is triggered by non-responding but not crashed instance" {
|
||||
lassign [S 4 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] host port
|
||||
ensure_master_up
|
||||
exec ../../../src/redis-cli -h $host -p $port debug sleep 10 > /dev/null &
|
||||
ensure_master_down
|
||||
ensure_master_up
|
||||
}
|
||||
|
||||
test "SDOWN is triggered by crashed instance" {
|
||||
lassign [S 4 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] host port
|
||||
ensure_master_up
|
||||
kill_instance redis 0
|
||||
ensure_master_down
|
||||
restart_instance redis 0
|
||||
ensure_master_up
|
||||
}
|
||||
|
||||
test "SDOWN is triggered by masters advertising as slaves" {
|
||||
ensure_master_up
|
||||
R 0 slaveof 127.0.0.1 34567
|
||||
ensure_master_down
|
||||
R 0 slaveof no one
|
||||
ensure_master_up
|
||||
}
|
||||
|
||||
test "SDOWN is triggered by misconfigured instance repling with errors" {
|
||||
ensure_master_up
|
||||
set orig_dir [lindex [R 0 config get dir] 1]
|
||||
set orig_save [lindex [R 0 config get save] 1]
|
||||
# Set dir to / and filename to "tmp" to make sure it will fail.
|
||||
R 0 config set dir /
|
||||
R 0 config set dbfilename tmp
|
||||
R 0 config set save "1000000 1000000"
|
||||
R 0 bgsave
|
||||
ensure_master_down
|
||||
R 0 config set save $orig_save
|
||||
R 0 config set dir $orig_dir
|
||||
R 0 config set dbfilename dump.rdb
|
||||
R 0 bgsave
|
||||
ensure_master_up
|
||||
}
|
||||
@@ -58,7 +58,8 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
|
||||
set idx 0; # Index of the node that will respond.
|
||||
set errmsg {}
|
||||
foreach start_node $::redis_cluster::startup_nodes($id) {
|
||||
lassign [split $start_node :] start_host start_port
|
||||
set ip_port [lindex [split $start_node @] 0]
|
||||
lassign [split $ip_port :] start_host start_port
|
||||
if {[catch {
|
||||
set r {}
|
||||
set r [redis $start_host $start_port]
|
||||
@@ -68,7 +69,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
|
||||
if {$r ne {}} {catch {$r close}}
|
||||
incr idx
|
||||
if {[string length $errmsg] < 200} {
|
||||
append errmsg " $start_node: $e"
|
||||
append errmsg " $ip_port: $e"
|
||||
}
|
||||
continue ; # Try next.
|
||||
} else {
|
||||
@@ -98,6 +99,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
|
||||
set args [split $line " "]
|
||||
lassign $args nodeid addr flags slaveof pingsent pongrecv configepoch linkstate
|
||||
set slots [lrange $args 8 end]
|
||||
set addr [lindex [split $addr @] 0]
|
||||
if {$addr eq {:0}} {
|
||||
set addr $start_host:$start_port
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ proc start_server {options {code undefined}} {
|
||||
|
||||
while 1 {
|
||||
# check that the server actually started and is ready for connections
|
||||
if {[exec grep -i "ready to accept" | wc -l < $stdout] > 0} {
|
||||
if {[exec grep -i "Ready to accept" | wc -l < $stdout] > 0} {
|
||||
break
|
||||
}
|
||||
after 10
|
||||
|
||||
@@ -42,6 +42,8 @@ set ::all_tests {
|
||||
integration/rdb
|
||||
integration/convert-zipmap-hash-on-load
|
||||
integration/logging
|
||||
integration/psync2
|
||||
integration/psync2-reg
|
||||
unit/pubsub
|
||||
unit/slowlog
|
||||
unit/scripting
|
||||
@@ -55,6 +57,8 @@ set ::all_tests {
|
||||
unit/geo
|
||||
unit/memefficiency
|
||||
unit/hyperloglog
|
||||
unit/lazyfree
|
||||
unit/wait
|
||||
}
|
||||
# Index to the next test to run in the ::all_tests list.
|
||||
set ::next_test 0
|
||||
@@ -63,6 +67,7 @@ set ::host 127.0.0.1
|
||||
set ::port 21111
|
||||
set ::traceleaks 0
|
||||
set ::valgrind 0
|
||||
set ::stack_logging 0
|
||||
set ::verbose 0
|
||||
set ::quiet 0
|
||||
set ::denytags {}
|
||||
@@ -395,6 +400,7 @@ proc send_data_packet {fd status data} {
|
||||
proc print_help_screen {} {
|
||||
puts [join {
|
||||
"--valgrind Run the test over valgrind."
|
||||
"--stack-logging Enable OSX leaks/malloc stack logging."
|
||||
"--accurate Run slow randomized tests for more iterations."
|
||||
"--quiet Don't show individual tests."
|
||||
"--single <unit> Just execute the specified unit (see next option)."
|
||||
@@ -421,6 +427,10 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
|
||||
incr j
|
||||
} elseif {$opt eq {--valgrind}} {
|
||||
set ::valgrind 1
|
||||
} elseif {$opt eq {--stack-logging}} {
|
||||
if {[string match {*Darwin*} [exec uname -a]]} {
|
||||
set ::stack_logging 1
|
||||
}
|
||||
} elseif {$opt eq {--quiet}} {
|
||||
set ::quiet 1
|
||||
} elseif {$opt eq {--host}} {
|
||||
|
||||
+55
-55
@@ -4,62 +4,63 @@ start_server {tags {"aofrw"}} {
|
||||
r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
|
||||
waitForBgrewriteaof r
|
||||
|
||||
test {AOF rewrite during write load} {
|
||||
# Start a write load for 10 seconds
|
||||
set master [srv 0 client]
|
||||
set master_host [srv 0 host]
|
||||
set master_port [srv 0 port]
|
||||
set load_handle0 [start_write_load $master_host $master_port 10]
|
||||
set load_handle1 [start_write_load $master_host $master_port 10]
|
||||
set load_handle2 [start_write_load $master_host $master_port 10]
|
||||
set load_handle3 [start_write_load $master_host $master_port 10]
|
||||
set load_handle4 [start_write_load $master_host $master_port 10]
|
||||
foreach rdbpre {yes no} {
|
||||
r config set aof-use-rdb-preamble $rdbpre
|
||||
test "AOF rewrite during write load: RDB preamble=$rdbpre" {
|
||||
# Start a write load for 10 seconds
|
||||
set master [srv 0 client]
|
||||
set master_host [srv 0 host]
|
||||
set master_port [srv 0 port]
|
||||
set load_handle0 [start_write_load $master_host $master_port 10]
|
||||
set load_handle1 [start_write_load $master_host $master_port 10]
|
||||
set load_handle2 [start_write_load $master_host $master_port 10]
|
||||
set load_handle3 [start_write_load $master_host $master_port 10]
|
||||
set load_handle4 [start_write_load $master_host $master_port 10]
|
||||
|
||||
# Make sure the instance is really receiving data
|
||||
wait_for_condition 50 100 {
|
||||
[r dbsize] > 0
|
||||
} else {
|
||||
fail "No write load detected."
|
||||
# Make sure the instance is really receiving data
|
||||
wait_for_condition 50 100 {
|
||||
[r dbsize] > 0
|
||||
} else {
|
||||
fail "No write load detected."
|
||||
}
|
||||
|
||||
# After 3 seconds, start a rewrite, while the write load is still
|
||||
# active.
|
||||
after 3000
|
||||
r bgrewriteaof
|
||||
waitForBgrewriteaof r
|
||||
|
||||
# Let it run a bit more so that we'll append some data to the new
|
||||
# AOF.
|
||||
after 1000
|
||||
|
||||
# Stop the processes generating the load if they are still active
|
||||
stop_write_load $load_handle0
|
||||
stop_write_load $load_handle1
|
||||
stop_write_load $load_handle2
|
||||
stop_write_load $load_handle3
|
||||
stop_write_load $load_handle4
|
||||
|
||||
# Make sure that we remain the only connected client.
|
||||
# This step is needed to make sure there are no pending writes
|
||||
# that will be processed between the two "debug digest" calls.
|
||||
wait_for_condition 50 100 {
|
||||
[llength [split [string trim [r client list]] "\n"]] == 1
|
||||
} else {
|
||||
puts [r client list]
|
||||
fail "Clients generating loads are not disconnecting"
|
||||
}
|
||||
|
||||
# Get the data set digest
|
||||
set d1 [r debug digest]
|
||||
|
||||
# Load the AOF
|
||||
r debug loadaof
|
||||
set d2 [r debug digest]
|
||||
|
||||
# Make sure they are the same
|
||||
assert {$d1 eq $d2}
|
||||
}
|
||||
|
||||
# After 3 seconds, start a rewrite, while the write load is still
|
||||
# active.
|
||||
after 3000
|
||||
r bgrewriteaof
|
||||
waitForBgrewriteaof r
|
||||
|
||||
# Let it run a bit more so that we'll append some data to the new
|
||||
# AOF.
|
||||
after 1000
|
||||
|
||||
# Stop the processes generating the load if they are still active
|
||||
stop_write_load $load_handle0
|
||||
stop_write_load $load_handle1
|
||||
stop_write_load $load_handle2
|
||||
stop_write_load $load_handle3
|
||||
stop_write_load $load_handle4
|
||||
|
||||
# Make sure that we remain the only connected client.
|
||||
# This step is needed to make sure there are no pending writes
|
||||
# that will be processed between the two "debug digest" calls.
|
||||
|
||||
#WIN_PORT_FIX 'wait_for_condition 50 100' -> 'wait_for_condition 50 250'
|
||||
wait_for_condition 50 250 {
|
||||
[llength [split [string trim [r client list]] "\n"]] == 1
|
||||
} else {
|
||||
puts [r client list]
|
||||
fail "Clients generating loads are not disconnecting"
|
||||
}
|
||||
|
||||
# Get the data set digest
|
||||
set d1 [r debug digest]
|
||||
|
||||
# Load the AOF
|
||||
r debug loadaof
|
||||
set d2 [r debug digest]
|
||||
|
||||
# Make sure they are the same
|
||||
assert {$d1 eq $d2}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +72,6 @@ start_server {tags {"aofrw"}} {
|
||||
r bgrewriteaof
|
||||
r config set appendonly no
|
||||
r exec
|
||||
#WIN_PORT_FIX 'tail -n5' -> 'tail -5'
|
||||
wait_for_condition 50 100 {
|
||||
[string match {*Killing*AOF*child*} [exec tail -5 < [srv 0 stdout]]]
|
||||
} else {
|
||||
|
||||
@@ -189,4 +189,13 @@ start_server {tags {"bitops"}} {
|
||||
r set bits 1
|
||||
r bitfield bits get u1 0
|
||||
} {0}
|
||||
|
||||
test {BITFIELD regression for #3564} {
|
||||
for {set j 0} {$j < 10} {incr j} {
|
||||
r del mystring
|
||||
set res [r BITFIELD mystring SET i8 0 10 SET i8 64 10 INCRBY i8 10 99900]
|
||||
assert {$res eq {0 0 60}}
|
||||
}
|
||||
r del mystring
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,4 +198,25 @@ start_server {tags {"expire"}} {
|
||||
r set foo b
|
||||
lsort [r keys *]
|
||||
} {a e foo s t}
|
||||
|
||||
test {EXPIRE with empty string as TTL should report an error} {
|
||||
r set foo bar
|
||||
catch {r expire foo ""} e
|
||||
set e
|
||||
} {*not an integer*}
|
||||
|
||||
test {SET - use EX/PX option, TTL should not be reseted after loadaof} {
|
||||
r config set appendonly yes
|
||||
r set foo bar EX 100
|
||||
after 2000
|
||||
r debug loadaof
|
||||
set ttl [r ttl foo]
|
||||
assert {$ttl <= 98 && $ttl > 90}
|
||||
|
||||
r set foo bar PX 100000
|
||||
after 2000
|
||||
r debug loadaof
|
||||
set ttl [r ttl foo]
|
||||
assert {$ttl <= 98 && $ttl > 90}
|
||||
}
|
||||
}
|
||||
|
||||
+95
-6
@@ -1,4 +1,4 @@
|
||||
# Helper functins to simulate search-in-radius in the Tcl side in order to
|
||||
# Helper functions to simulate search-in-radius in the Tcl side in order to
|
||||
# verify the Redis implementation with a fuzzy test.
|
||||
proc geo_degrad deg {expr {$deg*atan(1)*8/360}}
|
||||
|
||||
@@ -23,6 +23,47 @@ proc geo_random_point {lonvar latvar} {
|
||||
set lat [expr {-70 + rand()*140}]
|
||||
}
|
||||
|
||||
# Return elements non common to both the lists.
|
||||
# This code is from http://wiki.tcl.tk/15489
|
||||
proc compare_lists {List1 List2} {
|
||||
set DiffList {}
|
||||
foreach Item $List1 {
|
||||
if {[lsearch -exact $List2 $Item] == -1} {
|
||||
lappend DiffList $Item
|
||||
}
|
||||
}
|
||||
foreach Item $List2 {
|
||||
if {[lsearch -exact $List1 $Item] == -1} {
|
||||
if {[lsearch -exact $DiffList $Item] == -1} {
|
||||
lappend DiffList $Item
|
||||
}
|
||||
}
|
||||
}
|
||||
return $DiffList
|
||||
}
|
||||
|
||||
# The following list represents sets of random seed, search position
|
||||
# and radius that caused bugs in the past. It is used by the randomized
|
||||
# test later as a starting point. When the regression vectors are scanned
|
||||
# the code reverts to using random data.
|
||||
#
|
||||
# The format is: seed km lon lat
|
||||
set regression_vectors {
|
||||
{1482225976969 7083 81.634948934258375 30.561509253718668}
|
||||
{1482340074151 5416 -70.863281847379767 -46.347003465679947}
|
||||
{1499014685896 6064 -89.818768962202014 -40.463868561416803}
|
||||
{1412 156 149.29737817929004 15.95807862745508}
|
||||
{441574 143 59.235461856813856 66.269555127373678}
|
||||
{160645 187 -101.88575239939883 49.061997951502917}
|
||||
{750269 154 -90.187939661642517 66.615930412251487}
|
||||
{342880 145 163.03472387745728 64.012747720821181}
|
||||
{729955 143 137.86663517256579 63.986745399416776}
|
||||
{939895 151 59.149620271823181 65.204186651485145}
|
||||
{1412 156 149.29737817929004 15.95807862745508}
|
||||
{564862 149 84.062063109158544 -65.685403922426232}
|
||||
}
|
||||
set rv_idx 0
|
||||
|
||||
start_server {tags {"geo"}} {
|
||||
test {GEOADD create} {
|
||||
r geoadd nyc -73.9454966 40.747533 "lic market"
|
||||
@@ -183,35 +224,83 @@ start_server {tags {"geo"}} {
|
||||
}
|
||||
|
||||
test {GEOADD + GEORANGE randomized test} {
|
||||
set attempt 10
|
||||
set attempt 30
|
||||
while {[incr attempt -1]} {
|
||||
set rv [lindex $regression_vectors $rv_idx]
|
||||
incr rv_idx
|
||||
|
||||
unset -nocomplain debuginfo
|
||||
set srand_seed [randomInt 1000000]
|
||||
set srand_seed [clock milliseconds]
|
||||
if {$rv ne {}} {set srand_seed [lindex $rv 0]}
|
||||
lappend debuginfo "srand_seed is $srand_seed"
|
||||
expr {srand($srand_seed)} ; # If you need a reproducible run
|
||||
r del mypoints
|
||||
set radius_km [expr {[randomInt 200]+10}]
|
||||
|
||||
if {[randomInt 10] == 0} {
|
||||
# From time to time use very big radiuses
|
||||
set radius_km [expr {[randomInt 50000]+10}]
|
||||
} else {
|
||||
# Normally use a few - ~200km radiuses to stress
|
||||
# test the code the most in edge cases.
|
||||
set radius_km [expr {[randomInt 200]+10}]
|
||||
}
|
||||
if {$rv ne {}} {set radius_km [lindex $rv 1]}
|
||||
set radius_m [expr {$radius_km*1000}]
|
||||
geo_random_point search_lon search_lat
|
||||
if {$rv ne {}} {
|
||||
set search_lon [lindex $rv 2]
|
||||
set search_lat [lindex $rv 3]
|
||||
}
|
||||
lappend debuginfo "Search area: $search_lon,$search_lat $radius_km km"
|
||||
set tcl_result {}
|
||||
set argv {}
|
||||
for {set j 0} {$j < 20000} {incr j} {
|
||||
geo_random_point lon lat
|
||||
lappend argv $lon $lat "place:$j"
|
||||
if {[geo_distance $lon $lat $search_lon $search_lat] < $radius_m} {
|
||||
set distance [geo_distance $lon $lat $search_lon $search_lat]
|
||||
if {$distance < $radius_m} {
|
||||
lappend tcl_result "place:$j"
|
||||
lappend debuginfo "place:$j $lon $lat [expr {[geo_distance $lon $lat $search_lon $search_lat]/1000}] km"
|
||||
}
|
||||
lappend debuginfo "place:$j $lon $lat [expr {$distance/1000}] km"
|
||||
}
|
||||
r geoadd mypoints {*}$argv
|
||||
set res [lsort [r georadius mypoints $search_lon $search_lat $radius_km km]]
|
||||
set res2 [lsort $tcl_result]
|
||||
set test_result OK
|
||||
|
||||
if {$res != $res2} {
|
||||
set rounding_errors 0
|
||||
set diff [compare_lists $res $res2]
|
||||
foreach place $diff {
|
||||
set mydist [geo_distance $lon $lat $search_lon $search_lat]
|
||||
set mydist [expr $mydist/1000]
|
||||
if {($mydist / $radius_km) > 0.999} {incr rounding_errors}
|
||||
}
|
||||
# Make sure this is a real error and not a rounidng issue.
|
||||
if {[llength $diff] == $rounding_errors} {
|
||||
set res $res2; # Error silenced
|
||||
}
|
||||
}
|
||||
|
||||
if {$res != $res2} {
|
||||
set diff [compare_lists $res $res2]
|
||||
puts "*** Possible problem in GEO radius query ***"
|
||||
puts "Redis: $res"
|
||||
puts "Tcl : $res2"
|
||||
puts "Diff : $diff"
|
||||
puts [join $debuginfo "\n"]
|
||||
foreach place $diff {
|
||||
if {[lsearch -exact $res2 $place] != -1} {
|
||||
set where "(only in Tcl)"
|
||||
} else {
|
||||
set where "(only in Redis)"
|
||||
}
|
||||
lassign [lindex [r geopos mypoints $place] 0] lon lat
|
||||
set mydist [geo_distance $lon $lat $search_lon $search_lat]
|
||||
set mydist [expr $mydist/1000]
|
||||
puts "$place -> [r geopos mypoints $place] $mydist $where"
|
||||
if {($mydist / $radius_km) > 0.999} {incr rounding_errors}
|
||||
}
|
||||
set test_result FAIL
|
||||
}
|
||||
unset -nocomplain debuginfo
|
||||
|
||||
@@ -6,16 +6,17 @@ start_server {tags {"introspection"}} {
|
||||
test {MONITOR can log executed commands} {
|
||||
set rd [redis_deferring_client]
|
||||
$rd monitor
|
||||
assert_match {*OK*} [$rd read]
|
||||
r set foo bar
|
||||
r get foo
|
||||
list [$rd read] [$rd read] [$rd read]
|
||||
} {*OK*"set" "foo"*"get" "foo"*}
|
||||
list [$rd read] [$rd read]
|
||||
} {*"set" "foo"*"get" "foo"*}
|
||||
|
||||
test {MONITOR can log commands issued by the scripting engine} {
|
||||
set rd [redis_deferring_client]
|
||||
$rd monitor
|
||||
r eval {redis.call('set',KEYS[1],ARGV[1])} 1 foo bar
|
||||
$rd read ;# Discard the OK
|
||||
r eval {redis.call('set',KEYS[1],ARGV[1])} 1 foo bar
|
||||
assert_match {*eval*} [$rd read]
|
||||
assert_match {*lua*"set"*"foo"*"bar"*} [$rd read]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
start_server {tags {"lazyfree"}} {
|
||||
test "UNLINK can reclaim memory in background" {
|
||||
set orig_mem [s used_memory]
|
||||
set args {}
|
||||
for {set i 0} {$i < 100000} {incr i} {
|
||||
lappend args $i
|
||||
}
|
||||
r sadd myset {*}$args
|
||||
assert {[r scard myset] == 100000}
|
||||
set peak_mem [s used_memory]
|
||||
assert {[r unlink myset] == 1}
|
||||
assert {$peak_mem > $orig_mem+1000000}
|
||||
wait_for_condition 50 100 {
|
||||
[s used_memory] < $peak_mem &&
|
||||
[s used_memory] < $orig_mem*2
|
||||
} else {
|
||||
fail "Memory is not reclaimed by UNLINK"
|
||||
}
|
||||
}
|
||||
|
||||
test "FLUSHDB ASYNC can reclaim memory in background" {
|
||||
set orig_mem [s used_memory]
|
||||
set args {}
|
||||
for {set i 0} {$i < 100000} {incr i} {
|
||||
lappend args $i
|
||||
}
|
||||
r sadd myset {*}$args
|
||||
assert {[r scard myset] == 100000}
|
||||
set peak_mem [s used_memory]
|
||||
r flushdb async
|
||||
assert {$peak_mem > $orig_mem+1000000}
|
||||
wait_for_condition 50 100 {
|
||||
[s used_memory] < $peak_mem &&
|
||||
[s used_memory] < $orig_mem*2
|
||||
} else {
|
||||
fail "Memory is not reclaimed by FLUSHDB ASYNC"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ start_server {tags {"maxmemory"}} {
|
||||
}
|
||||
|
||||
foreach policy {
|
||||
allkeys-random allkeys-lru volatile-lru volatile-random volatile-ttl
|
||||
allkeys-random allkeys-lru allkeys-lfu volatile-lru volatile-lfu volatile-random volatile-ttl
|
||||
} {
|
||||
test "maxmemory - is the memory limit honoured? (policy $policy)" {
|
||||
# make sure to start with a blank instance
|
||||
@@ -98,7 +98,7 @@ start_server {tags {"maxmemory"}} {
|
||||
}
|
||||
|
||||
foreach policy {
|
||||
volatile-lru volatile-random volatile-ttl
|
||||
volatile-lru volatile-lfu volatile-random volatile-ttl
|
||||
} {
|
||||
test "maxmemory - policy $policy should only remove volatile keys." {
|
||||
# make sure to start with a blank instance
|
||||
|
||||
@@ -35,3 +35,51 @@ start_server {tags {"memefficiency"}} {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 0 {
|
||||
start_server {tags {"defrag"}} {
|
||||
if {[string match {*jemalloc*} [s mem_allocator]]} {
|
||||
test "Active defrag" {
|
||||
r config set activedefrag no
|
||||
r config set active-defrag-threshold-lower 5
|
||||
r config set active-defrag-ignore-bytes 2mb
|
||||
r config set maxmemory 100mb
|
||||
r config set maxmemory-policy allkeys-lru
|
||||
r debug populate 700000 asdf 150
|
||||
r debug populate 170000 asdf 300
|
||||
set frag [s mem_fragmentation_ratio]
|
||||
assert {$frag >= 1.7}
|
||||
r config set activedefrag yes
|
||||
after 1500 ;# active defrag tests the status once a second.
|
||||
set hits [s active_defrag_hits]
|
||||
|
||||
# wait for the active defrag to stop working
|
||||
set tries 0
|
||||
while { True } {
|
||||
incr tries
|
||||
after 500
|
||||
set prev_hits $hits
|
||||
set hits [s active_defrag_hits]
|
||||
if {$hits == $prev_hits} {
|
||||
break
|
||||
}
|
||||
assert {$tries < 100}
|
||||
}
|
||||
|
||||
# TODO: we need to expose more accurate fragmentation info
|
||||
# i.e. the allocator used and active pages
|
||||
# instead we currently look at RSS so we need to ask for purge
|
||||
r memory purge
|
||||
|
||||
# Test the the fragmentation is lower and that the defragger
|
||||
# stopped working
|
||||
set frag [s mem_fragmentation_ratio]
|
||||
assert {$frag < 1.55}
|
||||
set misses [s active_defrag_misses]
|
||||
after 500
|
||||
set misses2 [s active_defrag_misses]
|
||||
assert {$misses2 == $misses}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ start_server {tags {"other"}} {
|
||||
test {SELECT an out of range DB} {
|
||||
catch {r select 1000000} err
|
||||
set _ $err
|
||||
} {*invalid*}
|
||||
} {*index is out of range*}
|
||||
|
||||
tags {consistency} {
|
||||
if {![catch {package require sha1}]} {
|
||||
|
||||
@@ -330,7 +330,7 @@ start_server {tags {"scripting"}} {
|
||||
test {Globals protection reading an undeclared global variable} {
|
||||
catch {r eval {return a} 0} e
|
||||
set e
|
||||
} {*ERR*attempted to access unexisting global*}
|
||||
} {*ERR*attempted to access * global*}
|
||||
|
||||
test {Globals protection setting an undeclared global*} {
|
||||
catch {r eval {a=10} 0} e
|
||||
|
||||
+12
-1
@@ -31,12 +31,14 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
|
||||
} {0}
|
||||
|
||||
test {SLOWLOG - logged entry sanity check} {
|
||||
r client setname foobar
|
||||
r debug sleep 0.2
|
||||
set e [lindex [r slowlog get] 0]
|
||||
assert_equal [llength $e] 4
|
||||
assert_equal [llength $e] 6
|
||||
assert_equal [lindex $e 0] 105
|
||||
assert_equal [expr {[lindex $e 2] > 100000}] 1
|
||||
assert_equal [lindex $e 3] {debug sleep 0.2}
|
||||
assert_equal {foobar} [lindex $e 5]
|
||||
}
|
||||
|
||||
test {SLOWLOG - commands with too many arguments are trimmed} {
|
||||
@@ -67,4 +69,13 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} {
|
||||
set e [lindex [r slowlog get] 0]
|
||||
assert_equal [lindex $e 3] {debug sleep 0.2}
|
||||
}
|
||||
|
||||
test {SLOWLOG - can clean older entires} {
|
||||
r client setname lastentry_client
|
||||
r config set slowlog-max-len 1
|
||||
r debug sleep 0.2
|
||||
assert {[llength [r slowlog get]] == 1}
|
||||
set e [lindex [r slowlog get] 0]
|
||||
assert_equal {lastentry_client} [lindex $e 5]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,50 @@ start_server {
|
||||
assert_equal [r lindex l 1] [lindex $mylist 1]
|
||||
}
|
||||
|
||||
test {Regression for quicklist #3343 bug} {
|
||||
r del mylist
|
||||
r lpush mylist 401
|
||||
r lpush mylist 392
|
||||
r rpush mylist [string repeat x 5105]"799"
|
||||
r lset mylist -1 [string repeat x 1014]"702"
|
||||
r lpop mylist
|
||||
r lset mylist -1 [string repeat x 4149]"852"
|
||||
r linsert mylist before 401 [string repeat x 9927]"12"
|
||||
r lrange mylist 0 -1
|
||||
r ping ; # It's enough if the server is still alive
|
||||
} {PONG}
|
||||
|
||||
test {Stress tester for #3343-alike bugs} {
|
||||
r del key
|
||||
for {set j 0} {$j < 10000} {incr j} {
|
||||
set op [randomInt 6]
|
||||
set small_signed_count [expr 5-[randomInt 10]]
|
||||
if {[randomInt 2] == 0} {
|
||||
set ele [randomInt 1000]
|
||||
} else {
|
||||
set ele [string repeat x [randomInt 10000]][randomInt 1000]
|
||||
}
|
||||
switch $op {
|
||||
0 {r lpush key $ele}
|
||||
1 {r rpush key $ele}
|
||||
2 {r lpop key}
|
||||
3 {r rpop key}
|
||||
4 {
|
||||
catch {r lset key $small_signed_count $ele}
|
||||
}
|
||||
5 {
|
||||
set otherele [randomInt 1000]
|
||||
if {[randomInt 2] == 0} {
|
||||
set where before
|
||||
} else {
|
||||
set where after
|
||||
}
|
||||
r linsert key $where $otherele $ele
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags {slow} {
|
||||
test {ziplist implementation: value encoding and backlink} {
|
||||
if {$::accurate} {set iterations 100} else {set iterations 10}
|
||||
|
||||
@@ -507,7 +507,9 @@ start_server {
|
||||
create_list xlist "$large c"
|
||||
assert_equal 3 [r rpushx xlist d]
|
||||
assert_equal 4 [r lpushx xlist a]
|
||||
assert_equal "a $large c d" [r lrange xlist 0 -1]
|
||||
assert_equal 6 [r rpushx xlist 42 x]
|
||||
assert_equal 9 [r lpushx xlist y3 y2 y1]
|
||||
assert_equal "y1 y2 y3 a $large c d 42 x" [r lrange xlist 0 -1]
|
||||
}
|
||||
|
||||
test "LINSERT - $type" {
|
||||
|
||||
@@ -722,9 +722,7 @@ start_server {tags {"zset"}} {
|
||||
|
||||
assert_encoding $encoding zscoretest
|
||||
for {set i 0} {$i < $elements} {incr i} {
|
||||
set x [expr { double([lindex $aux $i]) } ]
|
||||
set y [expr { double([r zscore zscoretest $i]) } ]
|
||||
assert_equal $x $y
|
||||
assert_equal [lindex $aux $i] [r zscore zscoretest $i]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,9 +738,7 @@ start_server {tags {"zset"}} {
|
||||
r debug reload
|
||||
assert_encoding $encoding zscoretest
|
||||
for {set i 0} {$i < $elements} {incr i} {
|
||||
set x [expr { double([lindex $aux $i]) } ]
|
||||
set y [expr { double([r zscore zscoretest $i]) } ]
|
||||
assert_equal $x $y
|
||||
assert_equal [lindex $aux $i] [r zscore zscoretest $i]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
start_server {tags {"wait"}} {
|
||||
start_server {} {
|
||||
set slave [srv 0 client]
|
||||
set slave_host [srv 0 host]
|
||||
set slave_port [srv 0 port]
|
||||
set master [srv -1 client]
|
||||
set master_host [srv -1 host]
|
||||
set master_port [srv -1 port]
|
||||
|
||||
test {Setup slave} {
|
||||
$slave slaveof $master_host $master_port
|
||||
wait_for_condition 50 100 {
|
||||
[s 0 master_link_status] eq {up}
|
||||
} else {
|
||||
fail "Replication not started."
|
||||
}
|
||||
}
|
||||
|
||||
test {WAIT should acknowledge 1 additional copy of the data} {
|
||||
$master set foo 0
|
||||
$master incr foo
|
||||
$master incr foo
|
||||
$master incr foo
|
||||
assert {[$master wait 1 5000] == 1}
|
||||
assert {[$slave get foo] == 3}
|
||||
}
|
||||
|
||||
test {WAIT should not acknowledge 2 additional copies of the data} {
|
||||
$master incr foo
|
||||
assert {[$master wait 2 1000] <= 1}
|
||||
}
|
||||
|
||||
test {WAIT should not acknowledge 1 additional copy if slave is blocked} {
|
||||
exec src/redis-cli -h $slave_host -p $slave_port debug sleep 5 > /dev/null 2> /dev/null &
|
||||
after 1000 ;# Give redis-cli the time to execute the command.
|
||||
$master set foo 0
|
||||
$master incr foo
|
||||
$master incr foo
|
||||
$master incr foo
|
||||
assert {[$master wait 1 3000] == 0}
|
||||
}
|
||||
}}
|
||||
Reference in New Issue
Block a user