Skip to content

Commit

Permalink
Add notification support for HFE (#13237)
Browse files Browse the repository at this point in the history
1. Add `hpersist` notification for `hpersist` command.
2. Add `pexpire` notification for `hexpire`, `hexpireat` and `hpexpire`.
  • Loading branch information
sundb committed May 9, 2024
1 parent ca4ed48 commit 7010f41
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/commands.def
Original file line number Diff line number Diff line change
Expand Up @@ -3671,7 +3671,7 @@ struct COMMAND_ARG HMSET_Args[] = {
#ifndef SKIP_CMD_KEY_SPECS_TABLE
/* HPERSIST key specs */
keySpec HPERSIST_Keyspecs[1] = {
{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}
{NULL,CMD_KEY_RW|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}
};
#endif

Expand Down Expand Up @@ -11109,7 +11109,7 @@ struct COMMAND_STRUCT redisCommandTable[] = {
{MAKE_CMD("hlen","Returns the number of fields in a hash.","O(1)","2.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HLEN_History,0,HLEN_Tips,0,hlenCommand,2,CMD_READONLY|CMD_FAST,ACL_CATEGORY_HASH,HLEN_Keyspecs,1,NULL,1),.args=HLEN_Args},
{MAKE_CMD("hmget","Returns the values of all fields in a hash.","O(N) where N is the number of fields being requested.","2.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HMGET_History,0,HMGET_Tips,0,hmgetCommand,-3,CMD_READONLY|CMD_FAST,ACL_CATEGORY_HASH,HMGET_Keyspecs,1,NULL,2),.args=HMGET_Args},
{MAKE_CMD("hmset","Sets the values of multiple fields.","O(N) where N is the number of fields being set.","2.0.0",CMD_DOC_DEPRECATED,"`HSET` with multiple field-value pairs","4.0.0","hash",COMMAND_GROUP_HASH,HMSET_History,0,HMSET_Tips,0,hsetCommand,-4,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_HASH,HMSET_Keyspecs,1,NULL,2),.args=HMSET_Args},
{MAKE_CMD("hpersist","Removes the expiration time for each specified field","O(N) where N is the number of arguments to the command","8.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HPERSIST_History,0,HPERSIST_Tips,0,hpersistCommand,-4,CMD_READONLY|CMD_FAST,ACL_CATEGORY_HASH,HPERSIST_Keyspecs,1,NULL,3),.args=HPERSIST_Args},
{MAKE_CMD("hpersist","Removes the expiration time for each specified field","O(N) where N is the number of arguments to the command","8.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HPERSIST_History,0,HPERSIST_Tips,0,hpersistCommand,-4,CMD_WRITE|CMD_FAST,ACL_CATEGORY_HASH,HPERSIST_Keyspecs,1,NULL,3),.args=HPERSIST_Args},
{MAKE_CMD("hpexpire","Set expiry for hash field using relative time to expire (milliseconds)","O(N) where N is the number of arguments to the command","8.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HPEXPIRE_History,0,HPEXPIRE_Tips,0,hpexpireCommand,-5,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_HASH,HPEXPIRE_Keyspecs,1,NULL,5),.args=HPEXPIRE_Args},
{MAKE_CMD("hpexpireat","Set expiry for hash field using an absolute Unix timestamp (milliseconds)","O(N) where N is the number of arguments to the command","8.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HPEXPIREAT_History,0,HPEXPIREAT_Tips,0,hpexpireatCommand,-5,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_HASH,HPEXPIREAT_Keyspecs,1,NULL,5),.args=HPEXPIREAT_Args},
{MAKE_CMD("hpexpiretime","Returns the expiration time of a hash field as a Unix timestamp, in msec.","O(N) where N is the number of arguments to the command","8.0.0",CMD_DOC_NONE,NULL,NULL,"hash",COMMAND_GROUP_HASH,HPEXPIRETIME_History,0,HPEXPIRETIME_Tips,0,hpexpiretimeCommand,-4,CMD_READONLY|CMD_FAST,ACL_CATEGORY_HASH,HPEXPIRETIME_Keyspecs,1,NULL,3),.args=HPEXPIRETIME_Args},
Expand Down
6 changes: 3 additions & 3 deletions src/commands/hpersist.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"function": "hpersistCommand",
"history": [],
"command_flags": [
"READONLY",
"WRITE",
"FAST"
],
"acl_categories": [
Expand All @@ -17,8 +17,8 @@
"key_specs": [
{
"flags": [
"RO",
"ACCESS"
"RW",
"UPDATE"
],
"begin_search": {
"index": {
Expand Down
10 changes: 8 additions & 2 deletions src/t_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ void hashTypeSetExDone(HashTypeSetEx *ex) {
if (ex->c) {
server.dirty += ex->fieldDeleted + ex->fieldUpdated;
signalModifiedKey(ex->c, ex->db, ex->key);
notifyKeyspaceEvent(NOTIFY_HASH, ex->cmd, ex->key, ex->db->id);
notifyKeyspaceEvent(NOTIFY_HASH, "hexpire", ex->key, ex->db->id);
}
if (ex->fieldDeleted && hashTypeLength(ex->hashObj, 0) == 0) {
dbDelete(ex->db,ex->key);
Expand Down Expand Up @@ -2947,6 +2947,7 @@ void hpexpiretimeCommand(client *c) {
void hpersistCommand(client *c) {
robj *hashObj;
long numFields = 0, numFieldsAt = 2;
int changed = 0; /* Used to determine whether to send a notification. */

/* Read the hash object */
if ((hashObj = lookupKeyReadOrReply(c, c->argv[1], shared.null[c->resp])) == NULL ||
Expand Down Expand Up @@ -3017,8 +3018,8 @@ void hpersistCommand(client *c) {

listpackExPersist(hashObj, field, fptr, vptr);
addReplyLongLong(c, HFE_PERSIST_OK);
changed = 1;
}
return;
} else if (hashObj->encoding == OBJ_ENCODING_HT) {
dict *d = hashObj->ptr;

Expand Down Expand Up @@ -3046,10 +3047,15 @@ void hpersistCommand(client *c) {

hfieldPersist(hashObj, hf);
addReplyLongLong(c, HFE_PERSIST_OK);
changed = 1;
}
} else {
serverPanic("Unknown encoding: %d", hashObj->encoding);
}

/* Generates a hpersist event if the expiry time associated with any field
* has been successfully deleted. */
if (changed) notifyKeyspaceEvent(NOTIFY_HASH,"hpersist",c->argv[1],c->db->id);
}

/**
Expand Down
14 changes: 13 additions & 1 deletion tests/unit/pubsub.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -353,17 +353,29 @@ start_server {tags {"pubsub network"}} {
$rd1 close
}

test "Keyspace notifications: hash events test" {
foreach {type max_lp_entries} {listpackex 512 hashtable 0} {
test "Keyspace notifications: hash events test ($type)" {
r config set hash-max-listpack-entries $max_lp_entries
r config set notify-keyspace-events Kh
r del myhash
set rd1 [redis_deferring_client]
assert_equal {1} [psubscribe $rd1 *]
r hmset myhash yes 1 no 0
r hincrby myhash yes 10
r hexpire myhash 999999 1 yes
r hexpireat myhash [expr {[clock seconds] + 999999}] NX 1 no
r hpexpire myhash 5 1 yes
r hpersist myhash 1 yes
assert_encoding $type myhash
assert_equal "pmessage * __keyspace@${db}__:myhash hset" [$rd1 read]
assert_equal "pmessage * __keyspace@${db}__:myhash hincrby" [$rd1 read]
assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read]
assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read]
assert_equal "pmessage * __keyspace@${db}__:myhash hexpire" [$rd1 read]
assert_equal "pmessage * __keyspace@${db}__:myhash hpersist" [$rd1 read]
$rd1 close
}
} ;# foreach

test "Keyspace notifications: stream events test" {
r config set notify-keyspace-events Kt
Expand Down

0 comments on commit 7010f41

Please sign in to comment.