mirror of https://mirror.osredm.com/root/redis.git
Optimization: Avoid deferred array reply on ZRANGE commands BYRANK (#10337)
Avoid deferred array reply on genericZrangebyrankCommand() when consumer type is client. I.e. any ZRANGE / ZREVRNGE (when tank is used). This was a performance regression introduced in #7844 (v 6.2) mainly affecting pipelined workloads. Co-authored-by: Oran Agra <oran@redislabs.com>
This commit is contained in:
parent
e8c5b66ed2
commit
1dc89e2d02
|
@ -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
|
* so we have a few shared objects to use if the integer is small
|
||||||
* like it is most of the times. */
|
* like it is most of the times. */
|
||||||
const int opt_hdr = ll < OBJ_SHARED_BULKHDR_LEN && ll >= 0;
|
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) {
|
if (prefix == '*' && opt_hdr) {
|
||||||
addReply(c,shared.mbulkhdr[ll]);
|
addReplyProto(c,shared.mbulkhdr[ll]->ptr,hdr_len);
|
||||||
return;
|
return;
|
||||||
} else if (prefix == '$' && opt_hdr) {
|
} else if (prefix == '$' && opt_hdr) {
|
||||||
addReply(c,shared.bulkhdr[ll]);
|
addReplyProto(c,shared.bulkhdr[ll]->ptr,hdr_len);
|
||||||
return;
|
return;
|
||||||
} else if (prefix == '%' && opt_hdr) {
|
} else if (prefix == '%' && opt_hdr) {
|
||||||
addReply(c,shared.maphdr[ll]);
|
addReplyProto(c,shared.maphdr[ll]->ptr,hdr_len);
|
||||||
return;
|
return;
|
||||||
} else if (prefix == '~' && opt_hdr) {
|
} else if (prefix == '~' && opt_hdr) {
|
||||||
addReply(c,shared.sethdr[ll]);
|
addReplyProto(c,shared.sethdr[ll]->ptr,hdr_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
src/t_zset.c
35
src/t_zset.c
|
@ -2848,7 +2848,7 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct zrange_result_handler zrange_result_handler;
|
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)(
|
typedef void (*zrangeResultFinalizeFunction)(
|
||||||
zrange_result_handler *c, size_t result_count);
|
zrange_result_handler *c, size_t result_count);
|
||||||
typedef void (*zrangeResultEmitCBufferFunction)(
|
typedef void (*zrangeResultEmitCBufferFunction)(
|
||||||
|
@ -2876,8 +2876,22 @@ struct zrange_result_handler {
|
||||||
zrangeResultEmitLongLongFunction emitResultFromLongLong;
|
zrangeResultEmitLongLongFunction emitResultFromLongLong;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Result handler methods for responding the ZRANGE to clients. */
|
/* Result handler methods for responding the ZRANGE to clients.
|
||||||
static void zrangeResultBeginClient(zrange_result_handler *handler) {
|
* 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);
|
handler->userdata = addReplyDeferredLen(handler->client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2912,6 +2926,9 @@ static void zrangeResultEmitLongLongToClient(zrange_result_handler *handler,
|
||||||
static void zrangeResultFinalizeClient(zrange_result_handler *handler,
|
static void zrangeResultFinalizeClient(zrange_result_handler *handler,
|
||||||
size_t result_count)
|
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
|
/* 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
|
* nested arrays in RESP3. We can't use a map response type since the
|
||||||
* client library needs to know to respect the order. */
|
* 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. */
|
/* 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();
|
handler->dstobj = createZsetListpackObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3019,11 +3037,11 @@ void genericZrangebyrankCommand(zrange_result_handler *handler,
|
||||||
if (end < 0) end = llen+end;
|
if (end < 0) end = llen+end;
|
||||||
if (start < 0) start = 0;
|
if (start < 0) start = 0;
|
||||||
|
|
||||||
handler->beginResultEmission(handler);
|
|
||||||
|
|
||||||
/* Invariant: start >= 0, so this test will be true when end < 0.
|
/* Invariant: start >= 0, so this test will be true when end < 0.
|
||||||
* The range is empty when start > end or start >= length. */
|
* The range is empty when start > end or start >= length. */
|
||||||
if (start > end || start >= llen) {
|
if (start > end || start >= llen) {
|
||||||
|
handler->beginResultEmission(handler, 0);
|
||||||
handler->finalizeResultEmission(handler, 0);
|
handler->finalizeResultEmission(handler, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3031,6 +3049,7 @@ void genericZrangebyrankCommand(zrange_result_handler *handler,
|
||||||
rangelen = (end-start)+1;
|
rangelen = (end-start)+1;
|
||||||
result_cardinality = rangelen;
|
result_cardinality = rangelen;
|
||||||
|
|
||||||
|
handler->beginResultEmission(handler, rangelen);
|
||||||
if (zobj->encoding == OBJ_ENCODING_LISTPACK) {
|
if (zobj->encoding == OBJ_ENCODING_LISTPACK) {
|
||||||
unsigned char *zl = zobj->ptr;
|
unsigned char *zl = zobj->ptr;
|
||||||
unsigned char *eptr, *sptr;
|
unsigned char *eptr, *sptr;
|
||||||
|
@ -3124,7 +3143,7 @@ void genericZrangebyscoreCommand(zrange_result_handler *handler,
|
||||||
int reverse) {
|
int reverse) {
|
||||||
unsigned long rangelen = 0;
|
unsigned long rangelen = 0;
|
||||||
|
|
||||||
handler->beginResultEmission(handler);
|
handler->beginResultEmission(handler, -1);
|
||||||
|
|
||||||
/* For invalid offset, return directly. */
|
/* For invalid offset, return directly. */
|
||||||
if (offset > 0 && offset >= (long)zsetLength(zobj)) {
|
if (offset > 0 && offset >= (long)zsetLength(zobj)) {
|
||||||
|
@ -3409,7 +3428,7 @@ void genericZrangebylexCommand(zrange_result_handler *handler,
|
||||||
{
|
{
|
||||||
unsigned long rangelen = 0;
|
unsigned long rangelen = 0;
|
||||||
|
|
||||||
handler->beginResultEmission(handler);
|
handler->beginResultEmission(handler, -1);
|
||||||
|
|
||||||
if (zobj->encoding == OBJ_ENCODING_LISTPACK) {
|
if (zobj->encoding == OBJ_ENCODING_LISTPACK) {
|
||||||
unsigned char *zl = zobj->ptr;
|
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);
|
zobj = lookupKeyRead(c->db, key);
|
||||||
if (zobj == NULL) {
|
if (zobj == NULL) {
|
||||||
if (store) {
|
if (store) {
|
||||||
handler->beginResultEmission(handler);
|
handler->beginResultEmission(handler, -1);
|
||||||
handler->finalizeResultEmission(handler, 0);
|
handler->finalizeResultEmission(handler, 0);
|
||||||
} else {
|
} else {
|
||||||
addReply(c, shared.emptyarray);
|
addReply(c, shared.emptyarray);
|
||||||
|
|
Loading…
Reference in New Issue