diff options
Diffstat (limited to 'src/t_zset.c')
-rw-r--r-- | src/t_zset.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/src/t_zset.c b/src/t_zset.c index e09d4528b..bc947c965 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -2848,7 +2848,7 @@ typedef enum { typedef struct zrange_result_handler zrange_result_handler; -typedef void (*zrangeResultBeginFunction)(zrange_result_handler *c); +typedef void (*zrangeResultBeginFunction)(zrange_result_handler *c, long length); typedef void (*zrangeResultFinalizeFunction)( zrange_result_handler *c, size_t result_count); typedef void (*zrangeResultEmitCBufferFunction)( @@ -2876,8 +2876,22 @@ struct zrange_result_handler { zrangeResultEmitLongLongFunction emitResultFromLongLong; }; -/* Result handler methods for responding the ZRANGE to clients. */ -static void zrangeResultBeginClient(zrange_result_handler *handler) { +/* Result handler methods for responding the ZRANGE to clients. + * length can be used to provide the result length in advance (avoids deferred reply overhead). + * length can be set to -1 if the result length is not know in advance. + */ +static void zrangeResultBeginClient(zrange_result_handler *handler, long length) { + if (length > 0) { + /* In case of WITHSCORES, respond with a single array in RESP2, and + * nested arrays in RESP3. We can't use a map response type since the + * client library needs to know to respect the order. */ + if (handler->withscores && (handler->client->resp == 2)) { + length *= 2; + } + addReplyArrayLen(handler->client, length); + handler->userdata = NULL; + return; + } handler->userdata = addReplyDeferredLen(handler->client); } @@ -2912,6 +2926,9 @@ static void zrangeResultEmitLongLongToClient(zrange_result_handler *handler, static void zrangeResultFinalizeClient(zrange_result_handler *handler, size_t result_count) { + /* If the reply size was know at start there's nothing left to do */ + if (!handler->userdata) + return; /* In case of WITHSCORES, respond with a single array in RESP2, and * nested arrays in RESP3. We can't use a map response type since the * client library needs to know to respect the order. */ @@ -2923,8 +2940,9 @@ static void zrangeResultFinalizeClient(zrange_result_handler *handler, } /* Result handler methods for storing the ZRANGESTORE to a zset. */ -static void zrangeResultBeginStore(zrange_result_handler *handler) +static void zrangeResultBeginStore(zrange_result_handler *handler, long length) { + UNUSED(length); handler->dstobj = createZsetListpackObject(); } @@ -3019,11 +3037,11 @@ void genericZrangebyrankCommand(zrange_result_handler *handler, if (end < 0) end = llen+end; if (start < 0) start = 0; - handler->beginResultEmission(handler); /* Invariant: start >= 0, so this test will be true when end < 0. * The range is empty when start > end or start >= length. */ if (start > end || start >= llen) { + handler->beginResultEmission(handler, 0); handler->finalizeResultEmission(handler, 0); return; } @@ -3031,6 +3049,7 @@ void genericZrangebyrankCommand(zrange_result_handler *handler, rangelen = (end-start)+1; result_cardinality = rangelen; + handler->beginResultEmission(handler, rangelen); if (zobj->encoding == OBJ_ENCODING_LISTPACK) { unsigned char *zl = zobj->ptr; unsigned char *eptr, *sptr; @@ -3124,7 +3143,7 @@ void genericZrangebyscoreCommand(zrange_result_handler *handler, int reverse) { unsigned long rangelen = 0; - handler->beginResultEmission(handler); + handler->beginResultEmission(handler, -1); /* For invalid offset, return directly. */ if (offset > 0 && offset >= (long)zsetLength(zobj)) { @@ -3409,7 +3428,7 @@ void genericZrangebylexCommand(zrange_result_handler *handler, { unsigned long rangelen = 0; - handler->beginResultEmission(handler); + handler->beginResultEmission(handler, -1); if (zobj->encoding == OBJ_ENCODING_LISTPACK) { unsigned char *zl = zobj->ptr; @@ -3647,7 +3666,7 @@ void zrangeGenericCommand(zrange_result_handler *handler, int argc_start, int st zobj = lookupKeyRead(c->db, key); if (zobj == NULL) { if (store) { - handler->beginResultEmission(handler); + handler->beginResultEmission(handler, -1); handler->finalizeResultEmission(handler, 0); } else { addReply(c, shared.emptyarray); |