diff options
author | Oran Agra <oran@redislabs.com> | 2023-01-05 08:21:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-05 08:21:57 +0200 |
commit | d0cc3de73f91ca79b2343e73e640b40709cfcaf5 (patch) | |
tree | f9825f25863edb505dbcbd038d5d4fe99cf92c82 /src/t_set.c | |
parent | cb1fff3cb6a944d1f9cc67f8aa8b1d92648bbade (diff) | |
download | redis-d0cc3de73f91ca79b2343e73e640b40709cfcaf5.tar.gz |
Fix issues with listpack encoded set (#11685)
PR #11290 added listpack encoding for sets, but was missing two things:
1. Correct handling of MEMORY USAGE (leading to an assertion).
2. Had an uncontrolled scratch buffer size in SRANDMEMBER leading to
OOM panic (reported in #11668). Fixed by copying logic from ZRANDMEMBER.
note that both issues didn't exist in any redis release.
Diffstat (limited to 'src/t_set.c')
-rw-r--r-- | src/t_set.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/src/t_set.c b/src/t_set.c index 557ba35ce..6a4840676 100644 --- a/src/t_set.c +++ b/src/t_set.c @@ -969,6 +969,11 @@ void spopCommand(client *c) { * implementation for more info. */ #define SRANDMEMBER_SUB_STRATEGY_MUL 3 +/* If client is trying to ask for a very large number of random elements, + * queuing may consume an unlimited amount of memory, so we want to limit + * the number of randoms per time. */ +#define SRANDFIELD_RANDOM_SAMPLE_LIMIT 1000 + void srandmemberWithCountCommand(client *c) { long l; unsigned long count, size; @@ -1010,13 +1015,19 @@ void srandmemberWithCountCommand(client *c) { if (set->encoding == OBJ_ENCODING_LISTPACK && count > 1) { /* Specialized case for listpack, traversing it only once. */ - listpackEntry *entries = zmalloc(count * sizeof(listpackEntry)); - lpRandomEntries(set->ptr, count, entries); - for (unsigned long i = 0; i < count; i++) { - if (entries[i].sval) - addReplyBulkCBuffer(c, entries[i].sval, entries[i].slen); - else - addReplyBulkLongLong(c, entries[i].lval); + unsigned long limit, sample_count; + limit = count > SRANDFIELD_RANDOM_SAMPLE_LIMIT ? SRANDFIELD_RANDOM_SAMPLE_LIMIT : count; + listpackEntry *entries = zmalloc(limit * sizeof(listpackEntry)); + while (count) { + sample_count = count > limit ? limit : count; + count -= sample_count; + lpRandomEntries(set->ptr, sample_count, entries); + for (unsigned long i = 0; i < sample_count; i++) { + if (entries[i].sval) + addReplyBulkCBuffer(c, entries[i].sval, entries[i].slen); + else + addReplyBulkLongLong(c, entries[i].lval); + } } zfree(entries); return; |