From 7de1ada070da9f929d5c5cfab7f07a5de07305e7 Mon Sep 17 00:00:00 2001 From: chendianqiang Date: Sun, 1 Jul 2018 14:43:53 +0800 Subject: [PATCH] limit the size of pending-querybuf in masterclient --- src/server.c | 11 +++++++++++ src/server.h | 1 + tests/test_helper.tcl | 1 + tests/unit/pendingquerybuf.tcl | 35 ++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 tests/unit/pendingquerybuf.tcl diff --git a/src/server.c b/src/server.c index 647aee24b..224054d2d 100644 --- a/src/server.c +++ b/src/server.c @@ -858,6 +858,17 @@ int clientsCronResizeQueryBuffer(client *c) { /* Reset the peak again to capture the peak memory usage in the next * cycle. */ c->querybuf_peak = 0; + + if (c->flags & CLIENT_MASTER) { + /* There are two conditions to resize the pending query buffer: + * 1) Pending Query buffer is > LIMIT_PENDING_QUERYBUF. + * 2) used length is smaller than pending_querybuf_size/2 */ + size_t pending_querybuf_size = sdsAllocSize(c->pending_querybuf); + if(pending_querybuf_size > LIMIT_PENDING_QUERYBUF && + sdslen(c->pending_querybuf) < (pending_querybuf_size>>1)){ + c->pending_querybuf = sdsRemoveFreeSpace(c->pending_querybuf); + } + } return 0; } diff --git a/src/server.h b/src/server.h index d9c512c5e..b0492963e 100644 --- a/src/server.h +++ b/src/server.h @@ -184,6 +184,7 @@ typedef long long mstime_t; /* millisecond time type. */ #define PROTO_MBULK_BIG_ARG (1024*32) #define LONG_STR_SIZE 21 /* Bytes needed for long -> str + '\0' */ #define AOF_AUTOSYNC_BYTES (1024*1024*32) /* fdatasync every 32MB */ +#define LIMIT_PENDING_QUERYBUF (4*1024*1024) /* 4mb */ /* When configuring the server eventloop, we setup it so that the total number * of file descriptors we can handle are server.maxclients + RESERVED_FDS + diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl index 8b4d1eacf..3e2443577 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -61,6 +61,7 @@ set ::all_tests { unit/hyperloglog unit/lazyfree unit/wait + unit/pendingquerybuf } # Index to the next test to run in the ::all_tests list. set ::next_test 0 diff --git a/tests/unit/pendingquerybuf.tcl b/tests/unit/pendingquerybuf.tcl new file mode 100644 index 000000000..caa940d8e --- /dev/null +++ b/tests/unit/pendingquerybuf.tcl @@ -0,0 +1,35 @@ +proc info_memory {r property} { + if {[regexp "\r\n$property:(.*?)\r\n" [{*}$r info memory] _ value]} { + set _ $value + } +} + +proc prepare_value {size} { + set _v "c" + for {set i 1} {$i < $size} {incr i} { + append _v 0 + } + return $_v +} + +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 "pending querybuf: check size of pending_querybuf after set a big value" { + $slave slaveof $master_host $master_port + set _v [prepare_value [expr 32*1024*1024]] + $master set key $_v + after 2000 + set m_usedmemory [info_memory $master used_memory] + set s_usedmemory [info_memory $slave used_memory] + if { $s_usedmemory > $m_usedmemory + 10*1024*1024 } { + fail "the used_memory of slave is too larger than master.Master:$m_usedmemory Slave:$s_usedmemory" + } + } +}}