Skip to content

Commit b9b9f44

Browse files
Fix handling of NIL invalidation messages.
When CLIENT TRACKING is enabled, Redis will send an invalidation message with a NIL payload to all tracking clients after a FLUSHDB is executed. We didn't account for REDIS_REPLY_PUSH being a valid parent object to a NIL payload, and were failing an assertion. Additionally this commit adds a regression test for the logic.
1 parent acc9175 commit b9b9f44

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

hiredis.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ static void *createNilObject(const redisReadTask *task) {
257257
parent = task->parent->obj;
258258
assert(parent->type == REDIS_REPLY_ARRAY ||
259259
parent->type == REDIS_REPLY_MAP ||
260-
parent->type == REDIS_REPLY_SET);
260+
parent->type == REDIS_REPLY_SET ||
261+
parent->type == REDIS_REPLY_PUSH);
261262
parent->element[task->idx] = r;
262263
}
263264
return r;

test.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ struct privdata {
5353
int dtor_counter;
5454
};
5555

56+
struct pushCounters {
57+
int nil;
58+
int str;
59+
};
60+
5661
#ifdef HIREDIS_TEST_SSL
5762
redisSSLContext *_ssl_ctx = NULL;
5863
#endif
@@ -677,11 +682,25 @@ static void test_blocking_connection_errors(void) {
677682
#endif
678683
}
679684

680-
/* Dummy push handler */
681-
void push_handler(void *privdata, void *reply) {
682-
int *counter = privdata;
685+
/* Test push handler */
686+
void push_handler(void *privdata, void *r) {
687+
struct pushCounters *pcounts = privdata;
688+
redisReply *reply = r, *payload;
689+
690+
assert(reply && reply->type == REDIS_REPLY_PUSH && reply->elements == 2);
691+
692+
payload = reply->element[1];
693+
if (payload->type == REDIS_REPLY_ARRAY) {
694+
payload = payload->element[0];
695+
}
696+
697+
if (payload->type == REDIS_REPLY_STRING) {
698+
pcounts->str++;
699+
} else if (payload->type == REDIS_REPLY_NIL) {
700+
pcounts->nil++;
701+
}
702+
683703
freeReplyObject(reply);
684-
*counter += 1;
685704
}
686705

687706
/* Dummy function just to test setting a callback with redisOptions */
@@ -691,16 +710,16 @@ void push_handler_async(redisAsyncContext *ac, void *reply) {
691710
}
692711

693712
static void test_resp3_push_handler(redisContext *c) {
713+
struct pushCounters pc = {0};
694714
redisPushFn *old = NULL;
695715
redisReply *reply;
696716
void *privdata;
697-
int n = 0;
698717

699718
/* Switch to RESP3 and turn on client tracking */
700719
send_hello(c, 3);
701720
send_client_tracking(c, "ON");
702721
privdata = c->privdata;
703-
c->privdata = &n;
722+
c->privdata = &pc;
704723

705724
reply = redisCommand(c, "GET key:0");
706725
assert(reply != NULL);
@@ -717,7 +736,12 @@ static void test_resp3_push_handler(redisContext *c) {
717736
old = redisSetPushCallback(c, push_handler);
718737
test("We can set a custom RESP3 PUSH handler: ");
719738
reply = redisCommand(c, "SET key:0 val:0");
720-
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && n == 1);
739+
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.str == 1);
740+
freeReplyObject(reply);
741+
742+
test("We properly handle a NIL invalidation payload: ");
743+
reply = redisCommand(c, "FLUSHDB");
744+
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.nil == 1);
721745
freeReplyObject(reply);
722746

723747
/* Unset the push callback and generate an invalidate message making

0 commit comments

Comments
 (0)