From 5b0a06af48997794af60dabb58ce4336ef56f73d Mon Sep 17 00:00:00 2001 From: Itamar Haber Date: Tue, 25 Aug 2020 15:58:50 +0300 Subject: [PATCH] Expands lazyfree's effort estimate to include Streams (#5794) Otherwise, it is treated as a single allocation and freed synchronously. The following logic is used for estimating the effort in constant-ish time complexity: 1. Check the number of nodes. 1. Add an allocation for each consumer group registered inside the stream. 1. Check the number of PELs in the first CG, and then add this count times the number of CGs. 1. Check the number of consumers in the first CG, and then add this count times the number of CGs. --- src/lazyfree.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lazyfree.c b/src/lazyfree.c index f01504e70..cbcc1c240 100644 --- a/src/lazyfree.c +++ b/src/lazyfree.c @@ -41,6 +41,30 @@ size_t lazyfreeGetFreeEffort(robj *obj) { } else if (obj->type == OBJ_HASH && obj->encoding == OBJ_ENCODING_HT) { dict *ht = obj->ptr; return dictSize(ht); + } else if (obj->type == OBJ_STREAM) { + size_t effort = 0; + stream *s = obj->ptr; + + /* Make a best effort estimate to maintain constant runtime. Every macro + * node in the Stream is one allocation. */ + effort += s->rax->numnodes; + + /* Every consumer group is an allocation and so are the entries in its + * PEL. We use size of the first group's PEL as an estimate for all + * others. */ + if (s->cgroups) { + raxIterator ri; + streamCG *cg; + raxStart(&ri,s->cgroups); + raxSeek(&ri,"^",NULL,0); + /* There must be at least one group so the following should always + * work. */ + serverAssert(raxNext(&ri)); + cg = ri.data; + effort += raxSize(s->cgroups)*(1+raxSize(cg->pel)); + raxStop(&ri); + } + return effort; } else { return 1; /* Everything else is a single allocation. */ }