diff --git a/redis.conf b/redis.conf index 34b755718..4fbbaf7e0 100644 --- a/redis.conf +++ b/redis.conf @@ -1827,6 +1827,7 @@ latency-monitor-threshold 0 # z Sorted set commands # x Expired events (events generated every time a key expires) # e Evicted events (events generated when a key is evicted for maxmemory) +# n New key events (Note: not included in the 'A' class) # t Stream commands # d Module key type events # m Key-miss events (Note: It is not included in the 'A' class) diff --git a/src/config.c b/src/config.c index 3b5d4d349..cb3ff2e45 100644 --- a/src/config.c +++ b/src/config.c @@ -2691,7 +2691,7 @@ static int setConfigNotifyKeyspaceEventsOption(standardConfig *config, sds *argv } int flags = keyspaceEventsStringToFlags(argv[0]); if (flags == -1) { - *err = "Invalid event class character. Use 'Ag$lshzxeKEtmd'."; + *err = "Invalid event class character. Use 'Ag$lshzxeKEtmdn'."; return 0; } server.notify_keyspace_events = flags; diff --git a/src/db.c b/src/db.c index d4da756f1..10da1e923 100644 --- a/src/db.c +++ b/src/db.c @@ -182,6 +182,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) { dictSetVal(db->dict, de, val); signalKeyAsReady(db, key, val->type); if (server.cluster_enabled) slotToKeyAddEntry(de, db); + notifyKeyspaceEvent(NOTIFY_NEW,"new",key,db->id); } /* This is a special version of dbAdd() that is used only when loading diff --git a/src/notify.c b/src/notify.c index 28c0048cb..633e35bdc 100644 --- a/src/notify.c +++ b/src/notify.c @@ -57,6 +57,7 @@ int keyspaceEventsStringToFlags(char *classes) { case 't': flags |= NOTIFY_STREAM; break; case 'm': flags |= NOTIFY_KEY_MISS; break; case 'd': flags |= NOTIFY_MODULE; break; + case 'n': flags |= NOTIFY_NEW; break; default: return -1; } } @@ -84,6 +85,7 @@ sds keyspaceEventsFlagsToString(int flags) { if (flags & NOTIFY_EVICTED) res = sdscatlen(res,"e",1); if (flags & NOTIFY_STREAM) res = sdscatlen(res,"t",1); if (flags & NOTIFY_MODULE) res = sdscatlen(res,"d",1); + if (flags & NOTIFY_NEW) res = sdscatlen(res,"n",1); } if (flags & NOTIFY_KEYSPACE) res = sdscatlen(res,"K",1); if (flags & NOTIFY_KEYEVENT) res = sdscatlen(res,"E",1); diff --git a/src/server.h b/src/server.h index 37f7f3d7e..65727cd40 100644 --- a/src/server.h +++ b/src/server.h @@ -603,6 +603,7 @@ typedef enum { #define NOTIFY_KEY_MISS (1<<11) /* m (Note: This one is excluded from NOTIFY_ALL on purpose) */ #define NOTIFY_LOADED (1<<12) /* module only key space notification, indicate a key loaded from rdb */ #define NOTIFY_MODULE (1<<13) /* d, module key space notification */ +#define NOTIFY_NEW (1<<14) /* n, new key notification */ #define NOTIFY_ALL (NOTIFY_GENERIC | NOTIFY_STRING | NOTIFY_LIST | NOTIFY_SET | NOTIFY_HASH | NOTIFY_ZSET | NOTIFY_EXPIRED | NOTIFY_EVICTED | NOTIFY_STREAM | NOTIFY_MODULE) /* A flag */ /* Using the following macro you can run code inside serverCron() with the diff --git a/tests/unit/pubsub.tcl b/tests/unit/pubsub.tcl index 4435a9b1d..ea8964cf3 100644 --- a/tests/unit/pubsub.tcl +++ b/tests/unit/pubsub.tcl @@ -390,4 +390,17 @@ start_server {tags {"pubsub network"}} { r config set notify-keyspace-events EA assert_equal {AE} [lindex [r config get notify-keyspace-events] 1] } + + test "Keyspace notifications: new key test" { + r config set notify-keyspace-events En + set rd1 [redis_deferring_client] + assert_equal {1} [psubscribe $rd1 *] + r set foo bar + # second set of foo should not cause a 'new' event + r set foo baz + r set bar bar + assert_equal "pmessage * __keyevent@${db}__:new foo" [$rd1 read] + assert_equal "pmessage * __keyevent@${db}__:new bar" [$rd1 read] + $rd1 close + } }