summaryrefslogtreecommitdiff
path: root/src/t_zset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/t_zset.c')
-rw-r--r--src/t_zset.c35
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);