From 18264d641b1c1cb2d4b4053fe9a6934190ef84b7 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. (cherry picked from commit 5b0a06af48997794af60dabb58ce4336ef56f73d) (cherry picked from commit 5a9a653f3edebed5514d94ddc3aa4bf228fcecda) --- src/lazyfree.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lazyfree.c b/src/lazyfree.c index 3d3159c90..8c65cbd3f 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. */ }