diff --git a/src/networking.c b/src/networking.c index 8412c0960..60d50497d 100644 --- a/src/networking.c +++ b/src/networking.c @@ -825,17 +825,18 @@ void addReplyLongLongWithPrefix(client *c, long long ll, char prefix) { * so we have a few shared objects to use if the integer is small * like it is most of the times. */ const int opt_hdr = ll < OBJ_SHARED_BULKHDR_LEN && ll >= 0; + const size_t hdr_len = OBJ_SHARED_HDR_STRLEN(ll); if (prefix == '*' && opt_hdr) { - addReply(c,shared.mbulkhdr[ll]); + addReplyProto(c,shared.mbulkhdr[ll]->ptr,hdr_len); return; } else if (prefix == '$' && opt_hdr) { - addReply(c,shared.bulkhdr[ll]); + addReplyProto(c,shared.bulkhdr[ll]->ptr,hdr_len); return; } else if (prefix == '%' && opt_hdr) { - addReply(c,shared.maphdr[ll]); + addReplyProto(c,shared.maphdr[ll]->ptr,hdr_len); return; } else if (prefix == '~' && opt_hdr) { - addReply(c,shared.sethdr[ll]); + addReplyProto(c,shared.sethdr[ll]->ptr,hdr_len); return; } 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);