summaryrefslogtreecommitdiff
path: root/src/t_set.c
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2023-01-05 08:21:57 +0200
committerGitHub <noreply@github.com>2023-01-05 08:21:57 +0200
commitd0cc3de73f91ca79b2343e73e640b40709cfcaf5 (patch)
treef9825f25863edb505dbcbd038d5d4fe99cf92c82 /src/t_set.c
parentcb1fff3cb6a944d1f9cc67f8aa8b1d92648bbade (diff)
downloadredis-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.c25
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;