mirror of https://mirror.osredm.com/root/redis.git
Fix issue with argv not being shrunk (#13698)
Found by @ShooterIT ## Describe If a client first creates a command with a very large number of parameters, such as 10,000 parameters, the argv will be expanded to accommodate 10,000. If the subsequent commands have fewer than 10,000 parameters, this argv will continue to be reused and will never be shrunk. ## Solution When determining whether it is necessary to rebuild argv, if the length of the previous argv has already exceeded 1024, we will progressively create argv regardless. ## Free argv in cron Add a new condition to determine whether argv needs to be resized in cron. When the number of parameters exceeds 128, we will resize it regardless to avoid a single client consuming too much memory. It will now occupy a maximum of (128 * 8 bytes). --------- Co-authored-by: Yuan Wang <wangyuancode@163.com>
This commit is contained in:
parent
08d714d0e5
commit
21aee83abd
|
@ -2428,8 +2428,12 @@ int processMultibulkBuffer(client *c) {
|
|||
c->multibulklen = ll;
|
||||
|
||||
/* Setup argv array on client structure.
|
||||
* Create new argv if space is insufficient or if we need to allocate it gradually. */
|
||||
if (unlikely(c->multibulklen > c->argv_len || c->multibulklen > 1024)) {
|
||||
* Create new argv in the following cases:
|
||||
* 1) When the requested size is greater than the current size.
|
||||
* 2) When the requested size is less than the current size, because
|
||||
* we always allocate argv gradually with a maximum size of 1024,
|
||||
* Therefore, if argv_len exceeds this limit, we always reallocate. */
|
||||
if (unlikely(c->multibulklen > c->argv_len || c->argv_len > 1024)) {
|
||||
zfree(c->argv);
|
||||
c->argv_len = min(c->multibulklen, 1024);
|
||||
c->argv = zmalloc(sizeof(robj*)*c->argv_len);
|
||||
|
|
|
@ -791,8 +791,11 @@ int clientsCronFreeArgvIfIdle(client *c) {
|
|||
/* If the client is in the middle of parsing a command, or if argv is in use
|
||||
* (e.g. parsed in the IO thread but not yet executed, or blocked), exit ASAP. */
|
||||
if (!c->argv || c->multibulklen || c->argc) return 0;
|
||||
|
||||
/* Free argv if the client has been idle for more than 2 seconds or if argv
|
||||
* size is too large. */
|
||||
time_t idletime = server.unixtime - c->lastinteraction;
|
||||
if (idletime > 2) {
|
||||
if (idletime > 2 || c->argv_len > 128) {
|
||||
c->argv_len = 0;
|
||||
zfree(c->argv);
|
||||
c->argv = NULL;
|
||||
|
|
|
@ -10,7 +10,6 @@ start_server {tags {"lazyfree"}} {
|
|||
set peak_mem [s used_memory]
|
||||
assert {[r unlink myset] == 1}
|
||||
assert {$peak_mem > $orig_mem+1000000}
|
||||
reconnect ;# free the memory of reused argv of client
|
||||
wait_for_condition 50 100 {
|
||||
[s used_memory] < $peak_mem &&
|
||||
[s used_memory] < $orig_mem*2
|
||||
|
@ -33,7 +32,6 @@ start_server {tags {"lazyfree"}} {
|
|||
set peak_mem [s used_memory]
|
||||
r flushdb async
|
||||
assert {$peak_mem > $orig_mem+1000000}
|
||||
reconnect ;# free the memory of reused argv of client
|
||||
wait_for_condition 50 100 {
|
||||
[s used_memory] < $peak_mem &&
|
||||
[s used_memory] < $orig_mem*2
|
||||
|
|
Loading…
Reference in New Issue