diff --git a/README.md b/README.md index 0060c79..24d77bc 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ It uses a patched valkey version to make a cluster or sentinel-like setup less p ## Limitations and requirements -* Patched valkey (patches for valkey 9.0 are included in this repo) +* Patched valkey (patches for valkey 9.1 are included in this repo) * ZooKeeper as DCS * Single valkey instance per host * In clustered setup each shard must have it's own DCS prefix diff --git a/valkey_patches/0001_Add_replication_pause.patch b/valkey_patches/0001_Add_replication_pause.patch index e34c496..a303f24 100644 --- a/valkey_patches/0001_Add_replication_pause.patch +++ b/valkey_patches/0001_Add_replication_pause.patch @@ -1,8 +1,8 @@ diff --git a/src/config.c b/src/config.c -index d0158b2c4..f788aef6f 100644 +index fcbaee7e9..5c58b971f 100644 --- a/src/config.c +++ b/src/config.c -@@ -2588,6 +2588,25 @@ static int updateExtendedRedisCompat(const char **err) { +@@ -2641,6 +2641,25 @@ static int updateExtendedRedisCompat(const char **err) { return 1; } @@ -28,16 +28,16 @@ index d0158b2c4..f788aef6f 100644 static int updateSighandlerEnabled(const char **err) { UNUSED(err); if (server.crashlog_enabled) -@@ -3241,6 +3260,7 @@ standardConfig static_configs[] = { - createBoolConfig("hide-user-data-from-log", NULL, MODIFIABLE_CONFIG, server.hide_user_data_from_log, 1, NULL, NULL), +@@ -3312,6 +3331,7 @@ standardConfig static_configs[] = { createBoolConfig("lua-enable-insecure-api", "lua-enable-deprecated-api", MODIFIABLE_CONFIG | HIDDEN_CONFIG | PROTECTED_CONFIG, server.lua_enable_insecure_api, 0, NULL, updateLuaEnableInsecureApi), createBoolConfig("import-mode", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, server.import_mode, 0, NULL, NULL), + createBoolConfig("io-threads-always-active", NULL, MODIFIABLE_CONFIG | HIDDEN_CONFIG, server.io_threads_always_active, 0, NULL, NULL), + createBoolConfig("repl-paused", NULL, MODIFIABLE_CONFIG, server.repl_paused, 0, NULL, updateReplPaused), /* String Configs */ createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL), diff --git a/src/replication.c b/src/replication.c -index 82ee9450f..25726c542 100644 +index 13cbc4183..c30560b3d 100644 --- a/src/replication.c +++ b/src/replication.c @@ -59,7 +59,6 @@ void replicationResurrectProvisionalPrimary(void); @@ -48,7 +48,7 @@ index 82ee9450f..25726c542 100644 void replicationSteadyStateInit(void); void dualChannelSetupMainConnForPsync(connection *conn); void dualChannelSyncHandleRdbLoadCompletion(void); -@@ -1069,7 +1068,7 @@ void syncCommand(client *c) { +@@ -1115,7 +1114,7 @@ void syncCommand(client *c) { /* Refuse SYNC requests if we are a replica but the link with our primary * is not ok... */ @@ -57,7 +57,7 @@ index 82ee9450f..25726c542 100644 addReplyError(c, "-NOMASTERLINK Can't SYNC while not connected with my master"); return; } -@@ -5150,7 +5149,7 @@ void replicationCron(void) { +@@ -5284,7 +5283,7 @@ void replicationCron(void) { } /* Check if we should connect to a PRIMARY */ @@ -67,10 +67,10 @@ index 82ee9450f..25726c542 100644 connectWithPrimary(); } diff --git a/src/server.h b/src/server.h -index 25f01a31e..95d31758e 100644 +index 351b1e43c..c8e03be25 100644 --- a/src/server.h +++ b/src/server.h -@@ -2117,6 +2117,7 @@ struct valkeyServer { +@@ -2205,6 +2205,7 @@ struct valkeyServer { /* Synchronous replication. */ list *clients_waiting_acks; /* Clients waiting in WAIT or WAITAOF. */ int get_ack_from_replicas; /* If true we send REPLCONF GETACK. */ @@ -78,69 +78,15 @@ index 25f01a31e..95d31758e 100644 /* Limits */ unsigned int maxclients; /* Max number of simultaneous clients */ unsigned long long maxmemory; /* Max number of memory bytes to use */ -@@ -3116,6 +3117,8 @@ void updateFailoverStatus(void); +@@ -3240,6 +3241,8 @@ void updateFailoverStatus(void); void abortFailover(const char *err); const char *getFailoverStateString(void); sds getReplicaPortString(void); +int cancelReplicationHandshake(int reconnect); +int replicaIsInHandshakeState(void); int sendCurrentOffsetToReplica(client *replica); + int replicaRdbVersion(client *replica); void addRdbReplicaToPsyncWait(client *replica); - void initClientReplicationData(client *c); -diff --git a/tests/cluster/tests/99-yandex-cloud-patches.tcl b/tests/cluster/tests/99-yandex-cloud-patches.tcl -new file mode 100644 -index 000000000..6d0c1007b ---- /dev/null -+++ b/tests/cluster/tests/99-yandex-cloud-patches.tcl -@@ -0,0 +1,48 @@ -+# Test Yandex Cloud patches on cluster -+ -+source "../tests/includes/init-tests.tcl" -+ -+proc kill_clustered_redis {id} { -+ set pid [get_instance_attrib redis $id pid] -+ -+ stop_instance $pid -+ set_instance_attrib redis $id pid -1 -+ set_instance_attrib redis $id link you_tried_to_talk_with_killed_instance -+ -+ # Remove the PID from the list of pids to kill at exit. -+ set ::pids [lsearch -all -inline -not -exact $::pids $pid] -+} -+ -+test "Create a 2 node cluster (1 master and 1 replica)" { -+ create_cluster 1 1 -+} -+ -+test "Cluster is up" { -+ assert_cluster_state ok -+} -+ -+test "Instance #1 synced with the master" { -+ wait_for_condition 1000 50 { -+ [RI 1 master_link_status] eq {up} -+ } else { -+ fail "Instance #1 master link status is not up" -+ } -+} -+ -+test "Replication pause on instance #1 works" { -+ assert {[R 1 config set repl-paused yes] eq {OK}} -+ wait_for_condition 1000 50 { -+ [RI 1 master_link_status] eq {down} -+ } else { -+ fail "Instance #1 master link status is not down" -+ } -+} -+ -+test "Replication resume on instance #1 works" { -+ assert {[R 1 config set repl-paused no] eq {OK}} -+ wait_for_condition 1000 50 { -+ [RI 1 master_link_status] eq {up} -+ } else { -+ fail "Instance #1 master link status is not up" -+ } -+} diff --git a/tests/integration/yandex-cloud-patches.tcl b/tests/integration/yandex-cloud-patches.tcl new file mode 100644 index 000000000..a2c9bb949 @@ -203,6 +149,49 @@ index 000000000..a2c9bb949 + } + } +} --- -2.51.1 - +diff --git a/tests/unit/cluster/99-yandex-cloud-patches.tcl b/tests/unit/cluster/99-yandex-cloud-patches.tcl +new file mode 100644 +index 000000000..ca4d2f5ec +--- /dev/null ++++ b/tests/unit/cluster/99-yandex-cloud-patches.tcl +@@ -0,0 +1,40 @@ ++# Test Yandex Cloud patches on cluster ++ ++start_cluster 1 2 {tags {external:skip cluster}} { ++ ++test "Cluster is up" { ++ wait_for_cluster_state ok ++} ++ ++test "Instance 0 is master and 1 is replica" { ++ assert {[s 0 role] eq {master}} ++ assert {[s -1 role] eq {slave}} ++} ++ ++test "Instance 1 synced with the master" { ++ wait_for_condition 1000 50 { ++ [s -1 master_link_status] eq {up} ++ } else { ++ fail "Instance 1 master link status is not up" ++ } ++} ++ ++test "Replication pause on instance 1 works" { ++ assert {[R 1 config set repl-paused yes] eq {OK}} ++ wait_for_condition 1000 50 { ++ [s -1 master_link_status] eq {down} ++ } else { ++ fail "Instance 1 master link status is not down" ++ } ++} ++ ++test "Replication resume on instance 1 works" { ++ assert {[R 1 config set repl-paused no] eq {OK}} ++ wait_for_condition 1000 50 { ++ [s -1 master_link_status] eq {up} ++ } else { ++ fail "Instance 1 master link status is not up" ++ } ++} ++ ++} diff --git a/valkey_patches/0002_Allow_explicit_cluster_replication_cascades.patch b/valkey_patches/0002_Allow_explicit_cluster_replication_cascades.patch index 0b7fc3b..0d6d792 100644 --- a/valkey_patches/0002_Allow_explicit_cluster_replication_cascades.patch +++ b/valkey_patches/0002_Allow_explicit_cluster_replication_cascades.patch @@ -1,8 +1,8 @@ diff --git a/src/cluster_legacy.c b/src/cluster_legacy.c -index ed4768bfe..cc6fb7d1d 100644 +index 63cfc13a0..10adddf5c 100644 --- a/src/cluster_legacy.c +++ b/src/cluster_legacy.c -@@ -7733,7 +7733,7 @@ int clusterCommandSpecial(client *c) { +@@ -8120,7 +8120,7 @@ int clusterCommandSpecial(client *c) { } /* Can't replicate a replica. */ @@ -11,38 +11,24 @@ index ed4768bfe..cc6fb7d1d 100644 addReplyError(c, "I can only replicate a master, not a replica."); return 1; } -diff --git a/tests/cluster/tests/99-yandex-cloud-patches.tcl b/tests/cluster/tests/99-yandex-cloud-patches.tcl -index 6d0c1007b..04b644128 100644 ---- a/tests/cluster/tests/99-yandex-cloud-patches.tcl -+++ b/tests/cluster/tests/99-yandex-cloud-patches.tcl -@@ -13,8 +13,8 @@ proc kill_clustered_redis {id} { - set ::pids [lsearch -all -inline -not -exact $::pids $pid] - } - --test "Create a 2 node cluster (1 master and 1 replica)" { -- create_cluster 1 1 -+test "Create a 3 node cluster (1 master and 2 replicas)" { -+ create_cluster 1 2 - } - - test "Cluster is up" { -@@ -38,6 +38,16 @@ test "Replication pause on instance #1 works" { +diff --git a/tests/unit/cluster/99-yandex-cloud-patches.tcl b/tests/unit/cluster/99-yandex-cloud-patches.tcl +index ca4d2f5ec..bb7844a92 100644 +--- a/tests/unit/cluster/99-yandex-cloud-patches.tcl ++++ b/tests/unit/cluster/99-yandex-cloud-patches.tcl +@@ -28,6 +28,16 @@ test "Replication pause on instance 1 works" { } } +test "Replication cascade with paused instance works" { + assert {[R 2 config set cluster-slave-no-failover yes] eq {OK}} -+ assert {[R 2 cluster replicate [R 1 CLUSTER MYID]] eq {OK}} ++ assert {[R 2 cluster replicate [R 1 cluster myid]] eq {OK}} + wait_for_condition 1000 50 { -+ [RI 2 master_link_status] eq {up} ++ [s -2 master_link_status] eq {up} + } else { -+ fail "Instance #2 master link status is not up" ++ fail "Instance 2 master link status is not up" + } +} + - test "Replication resume on instance #1 works" { + test "Replication resume on instance 1 works" { assert {[R 1 config set repl-paused no] eq {OK}} wait_for_condition 1000 50 { --- -2.51.1 - diff --git a/valkey_patches/0003_Add_offline_mode.patch b/valkey_patches/0003_Add_offline_mode.patch index 2066f3c..b66b111 100644 --- a/valkey_patches/0003_Add_offline_mode.patch +++ b/valkey_patches/0003_Add_offline_mode.patch @@ -1,8 +1,8 @@ diff --git a/src/config.c b/src/config.c -index f788aef6f..aafa0616a 100644 +index 5c58b971f..0d852e730 100644 --- a/src/config.c +++ b/src/config.c -@@ -623,6 +623,8 @@ void loadServerConfigFromString(sds config) { +@@ -631,6 +631,8 @@ void loadServerConfigFromString(sds config) { if (server.hz < CONFIG_MIN_HZ) server.hz = CONFIG_MIN_HZ; if (server.hz > CONFIG_MAX_HZ) server.hz = CONFIG_MAX_HZ; @@ -11,7 +11,7 @@ index f788aef6f..aafa0616a 100644 sdsfreesplitres(lines, totlines); reading_config_file = 0; return; -@@ -3206,6 +3208,31 @@ static int applyClientMaxMemoryUsage(const char **err) { +@@ -3276,6 +3278,31 @@ static int isValidDbHashSeed(sds val, const char **err) { return 1; } @@ -43,7 +43,7 @@ index f788aef6f..aafa0616a 100644 standardConfig static_configs[] = { /* Bool configs */ createBoolConfig("rdbchecksum", NULL, IMMUTABLE_CONFIG, server.rdb_checksum, 1, NULL, NULL), -@@ -3461,6 +3488,7 @@ standardConfig static_configs[] = { +@@ -3536,6 +3563,7 @@ standardConfig static_configs[] = { createSpecialConfig("rdma-bind", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, setConfigRdmaBindOption, getConfigRdmaBindOption, rewriteConfigRdmaBindOption, applyRdmaBind), createSpecialConfig("replicaof", "slaveof", IMMUTABLE_CONFIG | MULTI_ARG_CONFIG, setConfigReplicaOfOption, getConfigReplicaOfOption, rewriteConfigReplicaOfOption, NULL), createSpecialConfig("latency-tracking-info-percentiles", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, setConfigLatencyTrackingInfoPercentilesOutputOption, getConfigLatencyTrackingInfoPercentilesOutputOption, rewriteConfigLatencyTrackingInfoPercentilesOutputOption, NULL), @@ -52,10 +52,10 @@ index f788aef6f..aafa0616a 100644 /* NULL Terminator, this is dropped when we convert to the runtime array. */ {NULL}, diff --git a/src/server.c b/src/server.c -index 46a20d1ae..860a3cb41 100644 +index e018a6182..7594a672e 100644 --- a/src/server.c +++ b/src/server.c -@@ -2664,9 +2664,15 @@ int listenToPort(connListener *sfd) { +@@ -2717,9 +2717,15 @@ int listenToPort(connListener *sfd) { int j; int port = sfd->port; char **bindaddr = sfd->bindaddr; @@ -72,7 +72,7 @@ index 46a20d1ae..860a3cb41 100644 for (j = 0; j < sfd->bindaddr_count; j++) { char *addr = bindaddr[j]; -@@ -6865,8 +6871,8 @@ void dismissMemoryInChild(void) { +@@ -7176,8 +7182,8 @@ void dismissMemoryInChild(void) { /* madvise(MADV_DONTNEED) may not work if Transparent Huge Pages is enabled. */ if (server.thp_enabled) return; @@ -83,20 +83,11 @@ index 46a20d1ae..860a3cb41 100644 #if defined(USE_JEMALLOC) && defined(__linux__) listIter li; listNode *ln; -@@ -7311,7 +7317,7 @@ __attribute__((weak)) int main(int argc, char **argv) { - } - if (server.sentinel_mode) sentinelCheckConfigFile(); - -- /* Do system checks */ -+ /* Do system checks */ - #ifdef __linux__ - linuxMemoryWarnings(); - sds err_msg = NULL; diff --git a/src/server.h b/src/server.h -index 95d31758e..a82eabd26 100644 +index c8e03be25..d941665ea 100644 --- a/src/server.h +++ b/src/server.h -@@ -2118,6 +2118,9 @@ struct valkeyServer { +@@ -2206,6 +2206,9 @@ struct valkeyServer { list *clients_waiting_acks; /* Clients waiting in WAIT or WAITAOF. */ int get_ack_from_replicas; /* If true we send REPLCONF GETACK. */ int repl_paused; /* If true we don't try to connect to master */ @@ -135,6 +126,3 @@ index 000000000..b8c3ba453 + } + } +} --- -2.51.1 - diff --git a/valkey_patches/0004_Add_waitquorum_command.patch b/valkey_patches/0004_Add_waitquorum_command.patch index 76cc02c..75f4cf4 100644 --- a/valkey_patches/0004_Add_waitquorum_command.patch +++ b/valkey_patches/0004_Add_waitquorum_command.patch @@ -1,8 +1,8 @@ diff --git a/src/commands.def b/src/commands.def -index fa63d4c74..0688e0e29 100644 +index 08cad9db4..437e59948 100644 --- a/src/commands.def +++ b/src/commands.def -@@ -3031,6 +3031,26 @@ struct COMMAND_ARG WAITAOF_Args[] = { +@@ -3066,6 +3066,26 @@ struct COMMAND_ARG WAITAOF_Args[] = { {MAKE_ARG("timeout",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, }; @@ -29,20 +29,20 @@ index fa63d4c74..0688e0e29 100644 /********** GEOADD ********************/ #ifndef SKIP_CMD_HISTORY_TABLE -@@ -11771,6 +11791,7 @@ struct COMMAND_STRUCT serverCommandTable[] = { - {MAKE_CMD("unlink","Asynchronously deletes one or more keys.","O(1) for each key removed regardless of its size. Then the command does O(N) work in a different thread in order to reclaim memory, where N is the number of allocations the deleted objects where composed of.","4.0.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,UNLINK_History,0,UNLINK_Tips,2,unlinkCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_KEYSPACE,UNLINK_Keyspecs,1,NULL,1),.args=UNLINK_Args}, - {MAKE_CMD("wait","Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed.","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,WAIT_History,0,WAIT_Tips,2,waitCommand,3,CMD_BLOCKING,ACL_CATEGORY_CONNECTION,WAIT_Keyspecs,0,NULL,2),.args=WAIT_Args}, - {MAKE_CMD("waitaof","Blocks until all of the preceding write commands sent by the connection are written to the append-only file of the primary and/or replicas.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,WAITAOF_History,0,WAITAOF_Tips,2,waitaofCommand,4,CMD_BLOCKING,ACL_CATEGORY_CONNECTION,WAITAOF_Keyspecs,0,NULL,3),.args=WAITAOF_Args}, -+{MAKE_CMD("waitquorum","Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed on replicas quorum.","O(1)","8.0.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,WAITQUORUM_History,0,WAITQUORUM_Tips,2,waitquorumCommand,1,0,ACL_CATEGORY_CONNECTION,WAITQUORUM_Keyspecs,0,NULL,0)}, +@@ -11899,6 +11919,7 @@ struct COMMAND_STRUCT serverCommandTable[] = { + {MAKE_CMD("unlink","Asynchronously deletes one or more keys.","O(1) for each key removed regardless of its size. Then the command does O(N) work in a different thread in order to reclaim memory, where N is the number of allocations the deleted objects where composed of.","4.0.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,UNLINK_History,0,UNLINK_Tips,2,unlinkCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_FAST|ACL_CATEGORY_KEYSPACE|ACL_CATEGORY_WRITE,NULL,UNLINK_Keyspecs,1,NULL,1),.args=UNLINK_Args}, + {MAKE_CMD("wait","Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed.","O(1)","3.0.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,WAIT_History,0,WAIT_Tips,2,waitCommand,3,CMD_BLOCKING,ACL_CATEGORY_BLOCKING|ACL_CATEGORY_CONNECTION|ACL_CATEGORY_SLOW,NULL,WAIT_Keyspecs,0,NULL,2),.args=WAIT_Args}, + {MAKE_CMD("waitaof","Blocks until all of the preceding write commands sent by the connection are written to the append-only file of the primary and/or replicas.","O(1)","7.2.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,WAITAOF_History,0,WAITAOF_Tips,2,waitaofCommand,4,CMD_BLOCKING,ACL_CATEGORY_BLOCKING|ACL_CATEGORY_CONNECTION|ACL_CATEGORY_SLOW,NULL,WAITAOF_Keyspecs,0,NULL,3),.args=WAITAOF_Args}, ++{MAKE_CMD("waitquorum","Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed on replicas quorum.","O(1)","8.0.0",CMD_DOC_NONE,NULL,NULL,"generic",COMMAND_GROUP_GENERIC,WAITQUORUM_History,0,WAITQUORUM_Tips,2,waitquorumCommand,1,CMD_BLOCKING,ACL_CATEGORY_BLOCKING|ACL_CATEGORY_CONNECTION|ACL_CATEGORY_SLOW,NULL,WAITQUORUM_Keyspecs,0,NULL,0)}, /* geo */ - {MAKE_CMD("geoadd","Adds one or more members to a geospatial index. The key is created if it doesn't exist.","O(log(N)) for each item added, where N is the number of elements in the sorted set.","3.2.0",CMD_DOC_NONE,NULL,NULL,"geo",COMMAND_GROUP_GEO,GEOADD_History,1,GEOADD_Tips,0,geoaddCommand,-5,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_GEO,GEOADD_Keyspecs,1,NULL,4),.args=GEOADD_Args}, - {MAKE_CMD("geodist","Returns the distance between two members of a geospatial index.","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,"geo",COMMAND_GROUP_GEO,GEODIST_History,0,GEODIST_Tips,0,geodistCommand,-4,CMD_READONLY,ACL_CATEGORY_GEO,GEODIST_Keyspecs,1,NULL,4),.args=GEODIST_Args}, + {MAKE_CMD("geoadd","Adds one or more members to a geospatial index. The key is created if it doesn't exist.","O(log(N)) for each item added, where N is the number of elements in the sorted set.","3.2.0",CMD_DOC_NONE,NULL,NULL,"geo",COMMAND_GROUP_GEO,GEOADD_History,1,GEOADD_Tips,0,geoaddCommand,-5,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_GEO|ACL_CATEGORY_SLOW|ACL_CATEGORY_WRITE,NULL,GEOADD_Keyspecs,1,NULL,4),.args=GEOADD_Args}, + {MAKE_CMD("geodist","Returns the distance between two members of a geospatial index.","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,"geo",COMMAND_GROUP_GEO,GEODIST_History,0,GEODIST_Tips,0,geodistCommand,-4,CMD_READONLY,ACL_CATEGORY_GEO|ACL_CATEGORY_READ|ACL_CATEGORY_SLOW,NULL,GEODIST_Keyspecs,1,NULL,4),.args=GEODIST_Args}, diff --git a/src/commands/waitquorum.json b/src/commands/waitquorum.json new file mode 100644 -index 000000000..18b21012d +index 000000000..4c6491cbe --- /dev/null +++ b/src/commands/waitquorum.json -@@ -0,0 +1,24 @@ +@@ -0,0 +1,27 @@ +{ + "WAITQUORUM": { + "summary": "Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed on replicas quorum.", @@ -52,9 +52,12 @@ index 000000000..18b21012d + "arity": 1, + "function": "waitquorumCommand", + "command_flags": [ ++ "BLOCKING" + ], + "acl_categories": [ -+ "CONNECTION" ++ "BLOCKING", ++ "CONNECTION", ++ "SLOW" + ], + "command_tips": [ + "REQUEST_POLICY:ALL_SHARDS", @@ -68,10 +71,10 @@ index 000000000..18b21012d + } +} diff --git a/src/config.c b/src/config.c -index aafa0616a..19ba2ba84 100644 +index 0d852e730..67491815a 100644 --- a/src/config.c +++ b/src/config.c -@@ -3233,6 +3233,79 @@ static void rewriteConfigOfflineMode(standardConfig *config, const char *name, s +@@ -3303,6 +3303,79 @@ static void rewriteConfigOfflineMode(standardConfig *config, const char *name, s rewriteConfigYesNoOption(state, name, server.offline_initial, 0); } @@ -151,15 +154,15 @@ index aafa0616a..19ba2ba84 100644 standardConfig static_configs[] = { /* Bool configs */ createBoolConfig("rdbchecksum", NULL, IMMUTABLE_CONFIG, server.rdb_checksum, 1, NULL, NULL), -@@ -3397,6 +3470,7 @@ standardConfig static_configs[] = { - createIntConfig("rdma-port", NULL, MODIFIABLE_CONFIG, 0, 65535, server.rdma_ctx_config.port, 0, INTEGER_CONFIG, NULL, updateRdmaPort), +@@ -3470,6 +3543,7 @@ standardConfig static_configs[] = { createIntConfig("rdma-rx-size", NULL, IMMUTABLE_CONFIG, 64 * 1024, 16 * 1024 * 1024, server.rdma_ctx_config.rx_size, 1024 * 1024, INTEGER_CONFIG, NULL, NULL), createIntConfig("rdma-completion-vector", NULL, IMMUTABLE_CONFIG, -1, 1024, server.rdma_ctx_config.completion_vector, -1, INTEGER_CONFIG, NULL, NULL), + createIntConfig("cluster-message-gossip-perc", NULL, MODIFIABLE_CONFIG | HIDDEN_CONFIG, 1, 100, server.cluster_message_gossip_perc, 10, INTEGER_CONFIG, NULL, NULL), + createIntConfig("quorum-replicas-to-write", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.quorum_replicas_to_write, 0, INTEGER_CONFIG, NULL, NULL), /* Unsigned int configs */ createUIntConfig("maxclients", NULL, MODIFIABLE_CONFIG, 1, UINT_MAX, server.maxclients, 10000, INTEGER_CONFIG, NULL, updateMaxclients), -@@ -3489,6 +3563,7 @@ standardConfig static_configs[] = { +@@ -3564,6 +3638,7 @@ standardConfig static_configs[] = { createSpecialConfig("replicaof", "slaveof", IMMUTABLE_CONFIG | MULTI_ARG_CONFIG, setConfigReplicaOfOption, getConfigReplicaOfOption, rewriteConfigReplicaOfOption, NULL), createSpecialConfig("latency-tracking-info-percentiles", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, setConfigLatencyTrackingInfoPercentilesOutputOption, getConfigLatencyTrackingInfoPercentilesOutputOption, rewriteConfigLatencyTrackingInfoPercentilesOutputOption, NULL), createSpecialConfig("offline", NULL, MODIFIABLE_CONFIG, setOfflineMode, getOfflineMode, rewriteConfigOfflineMode, applyBind), @@ -168,10 +171,10 @@ index aafa0616a..19ba2ba84 100644 /* NULL Terminator, this is dropped when we convert to the runtime array. */ {NULL}, diff --git a/src/replication.c b/src/replication.c -index 25726c542..56124321e 100644 +index c30560b3d..ab85d1a38 100644 --- a/src/replication.c +++ b/src/replication.c -@@ -1525,7 +1525,8 @@ void replconfCommand(client *c) { +@@ -1578,7 +1578,8 @@ void replconfCommand(client *c) { * It does a few things: * 1) Put the replica in ONLINE state. * 2) Update the count of "good replicas". @@ -181,7 +184,7 @@ index 25726c542..56124321e 100644 * * the return value indicates that the replica should be disconnected. * */ -@@ -1541,6 +1542,7 @@ int replicaPutOnline(client *replica) { +@@ -1594,6 +1595,7 @@ int replicaPutOnline(client *replica) { replica->repl_data->repl_ack_time = server.unixtime; /* Prevent false timeout. */ refreshGoodReplicasCount(); @@ -189,7 +192,7 @@ index 25726c542..56124321e 100644 /* Fire the replica change modules event. */ moduleFireServerEvent(VALKEYMODULE_EVENT_REPLICA_CHANGE, VALKEYMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE, NULL); serverLog(LL_NOTICE, "Synchronization with replica %s succeeded", replicationGetReplicaName(replica)); -@@ -4886,6 +4888,23 @@ int replicationCountAOFAcksByOffset(long long offset) { +@@ -5020,6 +5022,23 @@ int replicationCountAOFAcksByOffset(long long offset) { return count; } @@ -213,7 +216,7 @@ index 25726c542..56124321e 100644 /* WAIT for N replicas to acknowledge the processing of our latest * write command (and all the previous commands). */ void waitCommand(client *c) { -@@ -4920,6 +4939,64 @@ void waitCommand(client *c) { +@@ -5054,6 +5073,64 @@ void waitCommand(client *c) { replicationRequestAckFromReplicas(); } @@ -278,7 +281,7 @@ index 25726c542..56124321e 100644 /* WAIT for N replicas and / or local primary to acknowledge our latest * write command got synced to the disk. */ void waitaofCommand(client *c) { -@@ -4978,8 +5055,10 @@ void unblockClientWaitingReplicas(client *c) { +@@ -5112,8 +5189,10 @@ void unblockClientWaitingReplicas(client *c) { void processClientsWaitingReplicas(void) { long long last_offset = 0; long long last_aof_offset = 0; @@ -289,7 +292,7 @@ index 25726c542..56124321e 100644 listIter li; listNode *ln; -@@ -5002,16 +5081,25 @@ void processClientsWaitingReplicas(void) { +@@ -5136,16 +5215,25 @@ void processClientsWaitingReplicas(void) { * offset and number of replicas, we remember it so the next client * may be unblocked without calling replicationCountAcksByOffset() * or calling replicationCountAOFAcksByOffset() @@ -319,7 +322,7 @@ index 25726c542..56124321e 100644 /* Check if the number of replicas is satisfied. */ if (numreplicas < c->bstate->numreplicas) continue; -@@ -5019,6 +5107,9 @@ void processClientsWaitingReplicas(void) { +@@ -5153,6 +5241,9 @@ void processClientsWaitingReplicas(void) { if (is_wait_aof) { last_aof_offset = c->bstate->reploffset; last_aof_numreplicas = numreplicas; @@ -330,10 +333,10 @@ index 25726c542..56124321e 100644 last_offset = c->bstate->reploffset; last_numreplicas = numreplicas; diff --git a/src/server.c b/src/server.c -index 860a3cb41..c22e7a7dc 100644 +index 7594a672e..60c8bbddd 100644 --- a/src/server.c +++ b/src/server.c -@@ -2311,6 +2311,8 @@ void initServerConfig(void) { +@@ -2361,6 +2361,8 @@ void initServerConfig(void) { server.loading_process_events_interval_ms = LOADING_PROCESS_EVENTS_INTERVAL_DEFAULT; server.loading_rio = NULL; @@ -342,7 +345,7 @@ index 860a3cb41..c22e7a7dc 100644 /* Replication partial resync backlog */ server.repl_backlog = NULL; server.repl_no_replicas_since = time(NULL); -@@ -6314,12 +6316,13 @@ sds genValkeyInfoString(dict *section_dict, int all_sections, int everything) { +@@ -6597,12 +6599,13 @@ sds genValkeyInfoString(dict *section_dict, int all_sections, int everything) { info = sdscatprintf(info, "slave%d:ip=%s,port=%d,state=%s," @@ -359,10 +362,10 @@ index 860a3cb41..c22e7a7dc 100644 } } diff --git a/src/server.h b/src/server.h -index a82eabd26..2b501f5bf 100644 +index d941665ea..d47bf8642 100644 --- a/src/server.h +++ b/src/server.h -@@ -949,6 +949,7 @@ typedef struct blockingState { +@@ -981,6 +981,7 @@ typedef struct blockingState { /* BLOCKED_WAIT */ int numreplicas; /* Number of replicas we are waiting for ACK. */ @@ -370,7 +373,7 @@ index a82eabd26..2b501f5bf 100644 int numlocal; /* Indication if WAITAOF is waiting for local fsync. */ long long reploffset; /* Replication offset to reach. */ -@@ -1185,6 +1186,7 @@ typedef struct ClientPubSubData { +@@ -1225,6 +1226,7 @@ typedef struct ClientPubSubData { typedef struct ClientReplicationData { int repl_state; /* Replication state if this is a replica. */ int repl_start_cmd_stream_on_ack; /* Install replica write handler on first ACK. */ @@ -378,7 +381,7 @@ index a82eabd26..2b501f5bf 100644 int repldbfd; /* Replication DB file descriptor. */ off_t repldboff; /* Replication DB file offset. */ off_t repldbsize; /* Replication DB file size. */ -@@ -1739,6 +1741,8 @@ struct valkeyServer { +@@ -1821,6 +1823,8 @@ struct valkeyServer { * RDB transfer until their main channel establishes partial synchronization. */ client *current_client; /* The client that triggered the command execution (External or AOF). */ client *executing_client; /* The client executing the current command (possibly script or module). */ @@ -387,7 +390,7 @@ index a82eabd26..2b501f5bf 100644 #ifdef LOG_REQ_RES char *req_res_logfile; /* Path of log file for logging all requests and their replies. If NULL, no logging will be -@@ -3091,11 +3095,13 @@ void resizeReplicationBacklog(void); +@@ -3215,11 +3219,13 @@ void resizeReplicationBacklog(void); void replicationSetPrimary(char *ip, int port, int full_sync_required, bool disconnect_blocked); void replicationUnsetPrimary(void); void refreshGoodReplicasCount(void); @@ -401,7 +404,7 @@ index a82eabd26..2b501f5bf 100644 void replicationSendNewlineToPrimary(void); long long replicationGetReplicaOffset(void); char *replicationGetReplicaName(client *c); -@@ -4032,6 +4038,7 @@ void bitposCommand(client *c); +@@ -4193,6 +4199,7 @@ void bitposCommand(client *c); void replconfCommand(client *c); void waitCommand(client *c); void waitaofCommand(client *c); @@ -481,6 +484,3 @@ index b8c3ba453..2cb4cdca5 100644 + } +} +} --- -2.51.1 - diff --git a/valkey_patches/0005_Add_senticache.patch b/valkey_patches/0005_Add_senticache.patch index c8f5c19..d3a5f65 100644 --- a/valkey_patches/0005_Add_senticache.patch +++ b/valkey_patches/0005_Add_senticache.patch @@ -1,15 +1,15 @@ diff --git a/.gitignore b/.gitignore -index d85087c45..b0eabf988 100644 +index 636e29b86..4d96302d1 100644 --- a/.gitignore +++ b/.gitignore -@@ -12,6 +12,8 @@ dump*.rdb +@@ -14,6 +14,8 @@ dump*.rdb *-check-dump *-cli *-sentinel +*-senticache +!/runtest-senticache *-server - *-unit-tests + *-unit-gtests doc-tools diff --git a/runtest-senticache b/runtest-senticache new file mode 100755 @@ -47,50 +47,53 @@ index 000000000..5e922cd9f +sentinel resolve-hostnames no +sentinel announce-hostnames no diff --git a/src/Makefile b/src/Makefile -index 1ce928167..e6bbde88a 100644 +index 2812c4dba..1f14ad4aa 100644 --- a/src/Makefile +++ b/src/Makefile -@@ -422,8 +422,10 @@ endif +@@ -462,6 +462,7 @@ endif ENGINE_NAME=valkey SERVER_NAME=$(ENGINE_NAME)-server$(PROG_SUFFIX) ENGINE_SENTINEL_NAME=$(ENGINE_NAME)-sentinel$(PROG_SUFFIX) +ENGINE_SENTICACHE_NAME=$(ENGINE_NAME)-senticache$(PROG_SUFFIX) - ENGINE_TRACE_OBJ=trace/trace.o trace/trace_commands.o trace/trace_db.o trace/trace_cluster.o trace/trace_server.o trace/trace_rdb.o trace/trace_aof.o - ENGINE_SERVER_OBJ=threads_mngr.o adlist.o vector.o quicklist.o ae.o anet.o dict.o hashtable.o kvstore.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o memory_prefetch.o io_threads.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o cluster_legacy.o cluster_slot_stats.o crc16.o cluster_migrateslots.o endianconv.o commandlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crccombine.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o valkey-check-rdb.o valkey-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o allocator_defrag.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o lolwut9.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script.o functions.o commands.o strl.o connection.o unix.o logreqres.o rdma.o scripting_engine.o entry.o vset.o lua/script_lua.o lua/function_lua.o lua/engine_lua.o lua/debug_lua.o -+ENGINE_SENTICACHE_OBJ=threads_mngr.o adlist.o vector.o quicklist.o ae.o anet.o dict.o hashtable.o kvstore.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o memory_prefetch.o io_threads.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o cluster_legacy.o cluster_slot_stats.o crc16.o cluster_migrateslots.o endianconv.o commandlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crccombine.o crc64.o bitops.o senticache.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o valkey-check-rdb.o valkey-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o allocator_defrag.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o lolwut9.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script.o functions.o commands.o strl.o connection.o unix.o logreqres.o rdma.o scripting_engine.o entry.o vset.o lua/script_lua.o lua/function_lua.o lua/engine_lua.o lua/debug_lua.o + ENGINE_TRACE_OBJ = \ + trace/trace.o \ + trace/trace_aof.o \ +@@ -584,6 +585,7 @@ ENGINE_SERVER_OBJ = \ + zmalloc.o \ + queues.o ENGINE_SERVER_OBJ+=$(ENGINE_TRACE_OBJ) ++ENGINE_SENTICACHE_OBJ = $(patsubst sentinel.o,senticache.o,$(ENGINE_SERVER_OBJ)) ENGINE_CLI_NAME=$(ENGINE_NAME)-cli$(PROG_SUFFIX) - ENGINE_CLI_OBJ=anet.o adlist.o dict.o valkey-cli.o zmalloc.o release.o ae.o serverassert.o crcspeed.o crccombine.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o cli_commands.o sds.o util.o sha256.o -@@ -448,7 +450,7 @@ ifeq ($(USE_FAST_FLOAT),yes) - FINAL_LIBS += $(FAST_FLOAT_STRTOD_OBJECT) - endif + ENGINE_CLI_OBJ = \ + adlist.o \ +@@ -653,6 +655,7 @@ endif + DEPENDENCY_TARGETS+= gtest-parallel --all: $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(TLS_MODULE) $(RDMA_MODULE) -+all: $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_SENTICACHE_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(TLS_MODULE) $(RDMA_MODULE) - @echo "" - @echo "Hint: It's a good idea to run 'make test' ;)" + ALL_BUILD_PREREQUISITES=$(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(TLS_MODULE) $(RDMA_MODULE) ++ALL_BUILD_PREREQUISITES+= $(ENGINE_SENTICACHE_NAME) + + all: $(ALL_BUILD_PREREQUISITES) @echo "" -@@ -512,6 +514,10 @@ $(ENGINE_UNIT_TESTS): $(ENGINE_TEST_OBJ) $(ENGINE_LIB_NAME) +@@ -719,6 +722,10 @@ $(ENGINE_LIB_NAME): $(ENGINE_SERVER_OBJ) $(ENGINE_SENTINEL_NAME): $(SERVER_NAME) $(ENGINE_INSTALL) $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) +# valkey-senticache +$(ENGINE_SENTICACHE_NAME): $(ENGINE_SENTICACHE_OBJ) -+ $(SERVER_LD) -o $@ $^ ../deps/libvalkey/lib/libvalkey.a ../deps/lua/src/liblua.a ../deps/hdr_histogram/libhdrhistogram.a ../deps/fpconv/libfpconv.a $(FINAL_LIBS) ++ $(SERVER_LD) -o $@ $^ ../deps/libvalkey/lib/libvalkey.a ../deps/hdr_histogram/libhdrhistogram.a ../deps/fpconv/libfpconv.a $(FINAL_LIBS) $(LUA_LDFLAGS) + # valkey-check-rdb $(ENGINE_CHECK_RDB_NAME): $(SERVER_NAME) $(ENGINE_INSTALL) $(SERVER_NAME) $(ENGINE_CHECK_RDB_NAME) -@@ -574,7 +580,7 @@ endif - commands.c: $(COMMANDS_DEF_FILENAME).def +@@ -775,6 +782,7 @@ commands.c: $(COMMANDS_DEF_FILENAME).def clean: -- rm -rf $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(ENGINE_UNIT_TESTS) $(ENGINE_LIB_NAME) unit/*.o unit/*.d lua/*.o lua/*.d trace/*.o trace/*.d *.o *.gcda *.gcno *.gcov valkey.info lcov-html Makefile.dep *.so -+ rm -rf $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_SENTICACHE_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(ENGINE_UNIT_TESTS) $(ENGINE_LIB_NAME) unit/*.o unit/*.d lua/*.o lua/*.d trace/*.o trace/*.d *.o *.gcda *.gcno *.gcov valkey.info lcov-html Makefile.dep *.so + rm -rf $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(ENGINE_UNIT_GTESTS) $(ENGINE_LIB_NAME) trace/*.o trace/*.d *.o *.gcda *.gcno *.gcov valkey.info lcov-html Makefile.dep *.so ++ rm -rf $(ENGINE_SENTICACHE_NAME) rm -f $(DEP) + -(cd modules/lua && $(MAKE) clean) - .PHONY: clean -@@ -599,6 +605,9 @@ test-modules: $(SERVER_NAME) +@@ -806,6 +814,9 @@ test-modules: $(SERVER_NAME) test-sentinel: $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) @(cd ..; ./runtest-sentinel) @@ -100,8 +103,8 @@ index 1ce928167..e6bbde88a 100644 test-cluster: $(SERVER_NAME) $(ENGINE_CLI_NAME) @(cd ..; ./runtest-cluster) -@@ -637,6 +646,7 @@ helgrind: - install: all +@@ -845,6 +856,7 @@ helgrind: + install: all $(LUA_MODULE_INSTALL) @mkdir -p $(INSTALL_BIN) $(call MAKE_INSTALL,$(SERVER_NAME),$(INSTALL_BIN)) + $(call MAKE_INSTALL,$(ENGINE_SENTICACHE_NAME),$(INSTALL_BIN)) @@ -109,10 +112,10 @@ index 1ce928167..e6bbde88a 100644 $(call MAKE_INSTALL,$(ENGINE_CLI_NAME),$(INSTALL_BIN)) @ln -sf $(SERVER_NAME) $(INSTALL_BIN)/$(ENGINE_CHECK_RDB_NAME) diff --git a/src/commands.def b/src/commands.def -index 0688e0e29..c3168d2f5 100644 +index 437e59948..b07106d81 100644 --- a/src/commands.def +++ b/src/commands.def -@@ -6160,6 +6160,23 @@ struct COMMAND_STRUCT SCRIPT_Subcommands[] = { +@@ -6234,6 +6234,23 @@ struct COMMAND_STRUCT SCRIPT_Subcommands[] = { #define SCRIPT_Keyspecs NULL #endif @@ -136,20 +139,20 @@ index 0688e0e29..c3168d2f5 100644 /********** SENTINEL CKQUORUM ********************/ #ifndef SKIP_CMD_HISTORY_TABLE -@@ -6728,6 +6745,7 @@ struct COMMAND_ARG SENTINEL_SLAVES_Args[] = { +@@ -6802,6 +6819,7 @@ struct COMMAND_ARG SENTINEL_SLAVES_Args[] = { /* SENTINEL command table */ struct COMMAND_STRUCT SENTINEL_Subcommands[] = { -+{MAKE_CMD("cache-update","Update Senticache state","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_CACHE_UPDATE_History,0,SENTINEL_CACHE_UPDATE_Tips,0,sentinelCommand,-4,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_CACHE_UPDATE_Keyspecs,0,NULL,0)}, - {MAKE_CMD("ckquorum","Checks for a Sentinel quorum.",NULL,"2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_CKQUORUM_History,0,SENTINEL_CKQUORUM_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_CKQUORUM_Keyspecs,0,NULL,1),.args=SENTINEL_CKQUORUM_Args}, - {MAKE_CMD("config","Configures Sentinel.","O(N) when N is the number of configuration parameters provided","6.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_CONFIG_History,1,SENTINEL_CONFIG_Tips,0,sentinelCommand,-4,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_CONFIG_Keyspecs,0,NULL,1),.args=SENTINEL_CONFIG_Args}, - {MAKE_CMD("debug","Lists or updates the current configurable parameters of Sentinel.","O(N) where N is the number of configurable parameters","7.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_DEBUG_History,0,SENTINEL_DEBUG_Tips,0,sentinelCommand,-2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,0,SENTINEL_DEBUG_Keyspecs,0,NULL,1),.args=SENTINEL_DEBUG_Args}, ++{MAKE_CMD("cache-update","Update Senticache state","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_CACHE_UPDATE_History,0,SENTINEL_CACHE_UPDATE_Tips,0,sentinelCommand,-4,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS|ACL_CATEGORY_SLOW,NULL,SENTINEL_CACHE_UPDATE_Keyspecs,0,NULL,0)}, + {MAKE_CMD("ckquorum","Checks for a Sentinel quorum.",NULL,"2.8.4",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_CKQUORUM_History,0,SENTINEL_CKQUORUM_Tips,0,sentinelCommand,3,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS|ACL_CATEGORY_SLOW,NULL,SENTINEL_CKQUORUM_Keyspecs,0,NULL,1),.args=SENTINEL_CKQUORUM_Args}, + {MAKE_CMD("config","Configures Sentinel.","O(N) when N is the number of configuration parameters provided","6.2.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_CONFIG_History,1,SENTINEL_CONFIG_Tips,0,sentinelCommand,-4,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS|ACL_CATEGORY_SLOW,NULL,SENTINEL_CONFIG_Keyspecs,0,NULL,1),.args=SENTINEL_CONFIG_Args}, + {MAKE_CMD("debug","Lists or updates the current configurable parameters of Sentinel.","O(N) where N is the number of configurable parameters","7.0.0",CMD_DOC_NONE,NULL,NULL,"sentinel",COMMAND_GROUP_SENTINEL,SENTINEL_DEBUG_History,0,SENTINEL_DEBUG_Tips,0,sentinelCommand,-2,CMD_ADMIN|CMD_SENTINEL|CMD_ONLY_SENTINEL,ACL_CATEGORY_ADMIN|ACL_CATEGORY_DANGEROUS|ACL_CATEGORY_SLOW,NULL,SENTINEL_DEBUG_Keyspecs,0,NULL,1),.args=SENTINEL_DEBUG_Args}, diff --git a/src/commands/sentinel-cache-update.json b/src/commands/sentinel-cache-update.json new file mode 100644 -index 000000000..acea39255 +index 000000000..e3a4b9129 --- /dev/null +++ b/src/commands/sentinel-cache-update.json -@@ -0,0 +1,17 @@ +@@ -0,0 +1,22 @@ +{ + "CACHE-UPDATE": { + "summary": "Update Senticache state", @@ -164,12 +167,17 @@ index 000000000..acea39255 + "SENTINEL", + "ONLY_SENTINEL" + ], -+ "arguments": [] ++ "arguments": [], ++ "acl_categories": [ ++ "ADMIN", ++ "DANGEROUS", ++ "SLOW" ++ ] + } +} diff --git a/src/senticache.c b/src/senticache.c new file mode 100644 -index 000000000..076bd60e3 +index 000000000..39f8b2c6c --- /dev/null +++ b/src/senticache.c @@ -0,0 +1,1750 @@ @@ -1610,7 +1618,7 @@ index 000000000..076bd60e3 + size_t valueEnd = 0; + + for (int i = 3; i < c->argc; i++) { -+ updateCommand = sdscatsds(updateCommand, c->argv[i]->ptr); ++ updateCommand = sdscatsds(updateCommand, objectGetVal(c->argv[i])); + if (i != c->argc - 1) { + updateCommand = sdscatlen(updateCommand, " ", 1); + } @@ -1673,7 +1681,7 @@ index 000000000..076bd60e3 +} + +void sentinelCommand(client *c) { -+ if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr, "help")) { ++ if (c->argc == 2 && !strcasecmp(objectGetVal(c->argv[1]), "help")) { + const char *help[] = {"CKQUORUM ", + " Check if the current Sentinel configuration is able to reach the quorum", + " needed to failover a master and the majority needed to authorize the", @@ -1694,43 +1702,43 @@ index 000000000..076bd60e3 + " Show a list of Sentinel instances for this master and their state.", + NULL}; + addReplyHelp(c, help); -+ } else if (!strcasecmp(c->argv[1]->ptr, "cache-update")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "cache-update")) { + if (c->argc < 4) goto numargserr; -+ if (!strcasecmp(c->argv[2]->ptr, sentinel.cache_update_secret)) { ++ if (!strcasecmp(objectGetVal(c->argv[2]), sentinel.cache_update_secret)) { + sentinelCacheUpdate(c); + } else { + addReplySubcommandSyntaxError(c); + } -+ } else if (!strcasecmp(c->argv[1]->ptr, "masters")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "masters")) { + /* SENTINEL MASTERS */ + if (c->argc != 2) goto numargserr; + addReplyDictOfValkeyInstances(c, sentinel.primaries); -+ } else if (!strcasecmp(c->argv[1]->ptr, "master")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "master")) { + /* SENTINEL MASTER */ + sentinelValkeyInstance *ri; + + if (c->argc != 3) goto numargserr; + if ((ri = sentinelGetPrimaryOrReplyError(c)) == NULL) return; + addReplysentinelValkeyInstance(c, ri); -+ } else if (!strcasecmp(c->argv[1]->ptr, "slaves") || !strcasecmp(c->argv[1]->ptr, "replicas")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "slaves") || !strcasecmp(objectGetVal(c->argv[1]), "replicas")) { + /* SENTINEL REPLICAS */ + sentinelValkeyInstance *ri; + + if (c->argc != 3) goto numargserr; + if ((ri = sentinelGetPrimaryOrReplyError(c)) == NULL) return; + addReplyDictOfValkeyInstances(c, ri->replicas); -+ } else if (!strcasecmp(c->argv[1]->ptr, "sentinels")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "sentinels")) { + /* SENTINEL SENTINELS */ + sentinelValkeyInstance *ri; + + if (c->argc != 3) goto numargserr; + if ((ri = sentinelGetPrimaryOrReplyError(c)) == NULL) return; + addReplyDictOfValkeyInstances(c, ri->sentinels); -+ } else if (!strcasecmp(c->argv[1]->ptr, "myid") && c->argc == 2) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "myid") && c->argc == 2) { + /* SENTINEL MYID */ + addReplyBulkCBuffer(c, sentinel.myid, CONFIG_RUN_ID_SIZE); -+ } else if (!strcasecmp(c->argv[1]->ptr, "get-master-addr-by-name") || -+ !strcasecmp(c->argv[1]->ptr, "get-master-addr-by-name")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "get-master-addr-by-name") || ++ !strcasecmp(objectGetVal(c->argv[1]), "get-master-addr-by-name")) { + /* SENTINEL GET-MASTER-ADDR-BY-NAME */ + sentinelValkeyInstance *ri; + @@ -1745,12 +1753,12 @@ index 000000000..076bd60e3 + addReplyBulkCString(c, announceSentinelAddr(addr)); + addReplyBulkLongLong(c, addr->port); + } -+ } else if (!strcasecmp(c->argv[1]->ptr, "ckquorum")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "ckquorum")) { + /* SENTINEL CKQUORUM */ + if (c->argc != 3) goto numargserr; + addReplySds(c, sdscatfmt(sdsempty(), "+OK 1 usable Sentinels. Quorum and failover authorization " + "can be reached\r\n")); -+ } else if (!strcasecmp(c->argv[1]->ptr, "info-cache")) { ++ } else if (!strcasecmp(objectGetVal(c->argv[1]), "info-cache")) { + /* SENTINEL INFO-CACHE */ + if (c->argc < 2) goto numargserr; + mstime_t now = mstime(); @@ -1766,7 +1774,7 @@ index 000000000..076bd60e3 + + for (int i = 2; i < c->argc; i++) { + sentinelValkeyInstance *ri; -+ ri = sentinelGetPrimaryByName(c->argv[i]->ptr); ++ ri = sentinelGetPrimaryByName(objectGetVal(c->argv[i])); + if (!ri) continue; /* ignore non-existing names */ + dictAdd(primaries_local, ri->name, ri); + } @@ -1924,10 +1932,10 @@ index 000000000..076bd60e3 + /* just do nothing */ +} diff --git a/src/server.c b/src/server.c -index c22e7a7dc..7012e6f10 100644 +index 60c8bbddd..2d1359cfd 100644 --- a/src/server.c +++ b/src/server.c -@@ -6908,6 +6908,8 @@ int checkForSentinelMode(int argc, char **argv, char *exec_name) { +@@ -7219,6 +7219,8 @@ int checkForSentinelMode(int argc, char **argv, char *exec_name) { /* valkey may install symlinks like redis-sentinel -> valkey-sentinel. */ if (strstr(exec_name, "redis-sentinel") != NULL) return 1; @@ -1937,12 +1945,12 @@ index c22e7a7dc..7012e6f10 100644 if (!strcmp(argv[j], "--sentinel")) return 1; return 0; diff --git a/tests/instances.tcl b/tests/instances.tcl -index 76d9e14bc..04b1397a2 100644 +index 4782a5e49..e0871b646 100644 --- a/tests/instances.tcl +++ b/tests/instances.tcl -@@ -26,10 +26,12 @@ set ::dont_clean 0 - set ::simulate_error 0 - set ::failed 0 +@@ -27,10 +27,12 @@ set ::failed 0 + set ::failed_tests {} + set ::failures_output_file "" set ::sentinel_instances {} +set ::senticache_instances {} set ::valkey_instances {} @@ -1953,16 +1961,16 @@ index 76d9e14bc..04b1397a2 100644 set ::valkey_port_count 1024 set ::host "127.0.0.1" set ::leaked_fds_file [file normalize "tmp/leaked_fds.txt"] -@@ -53,6 +55,8 @@ proc exec_instance {type dirname cfgfile} { - set prgname valkey-server +@@ -58,6 +60,8 @@ proc exec_instance {type dirname cfgfile} { + set program_path $::VALKEY_SERVER_BIN } elseif {$type eq "sentinel"} { - set prgname valkey-sentinel + set program_path $::VALKEY_SENTINEL_BIN + } elseif {$type eq "senticache"} { -+ set prgname valkey-senticache ++ set program_path $::VALKEY_SENTICACHE_BIN } else { error "Unknown instance type." } -@@ -544,6 +548,21 @@ proc S {n args} { +@@ -596,6 +600,21 @@ proc S {n args} { [dict get $s link] {*}$args } @@ -1986,10 +1994,17 @@ index 76d9e14bc..04b1397a2 100644 # [Rn 0] info diff --git a/tests/senticache/run.tcl b/tests/senticache/run.tcl new file mode 100644 -index 000000000..a5e20774b +index 000000000..0ac34396e --- /dev/null +++ b/tests/senticache/run.tcl -@@ -0,0 +1,23 @@ +@@ -0,0 +1,30 @@ ++# Senticache test suite. Copyright (C) 2022 Yandex Cloud. ++# This software is released under the BSD License. See the COPYING file for ++# more information. ++ ++# Set the executable paths at project root ++source tests/support/set_executable_path.tcl ++ +cd tests/senticache +source ../instances.tcl + @@ -2195,10 +2210,10 @@ index 000000000..4944e0096 @@ -0,0 +1 @@ +senticache_* diff --git a/tests/sentinel/tests/00-base.tcl b/tests/sentinel/tests/00-base.tcl -index 33e590ab5..4f766459e 100644 +index 97cc6540a..787581138 100644 --- a/tests/sentinel/tests/00-base.tcl +++ b/tests/sentinel/tests/00-base.tcl -@@ -82,7 +82,7 @@ test "Basic failover works if the primary is down" { +@@ -89,7 +89,7 @@ test "Basic failover works if the primary is down" { kill_instance valkey $master_id foreach_sentinel_id id { S $id sentinel debug ping-period 500 @@ -2207,6 +2222,15 @@ index 33e590ab5..4f766459e 100644 wait_for_condition 1000 100 { [lindex [S $id SENTINEL GET-PRIMARY-ADDR-BY-NAME mymaster] 1] != $old_port } else { --- -2.51.1 - +diff --git a/tests/support/set_executable_path.tcl b/tests/support/set_executable_path.tcl +index 684f22952..35b5f9aff 100644 +--- a/tests/support/set_executable_path.tcl ++++ b/tests/support/set_executable_path.tcl +@@ -26,6 +26,7 @@ set ::VALKEY_BENCHMARK_BIN [valkey_bin_absolute_path "valkey-benchmark"] + set ::VALKEY_CHECK_AOF_BIN [valkey_bin_absolute_path "valkey-check-aof"] + set ::VALKEY_CHECK_RDB_BIN [valkey_bin_absolute_path "valkey-check-rdb"] + set ::VALKEY_SENTINEL_BIN [valkey_bin_absolute_path "valkey-sentinel"] ++set ::VALKEY_SENTICACHE_BIN [valkey_bin_absolute_path "valkey-senticache"] + + # TLS module path: in CMake builds it's in lib/, in Make builds it's in src/ + if {[info exists ::env(VALKEY_BIN_DIR)]} { diff --git a/valkey_patches/build.sh b/valkey_patches/build.sh index 9ab2c40..50f4dc0 100755 --- a/valkey_patches/build.sh +++ b/valkey_patches/build.sh @@ -7,7 +7,7 @@ DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt -y install build-essential git cd /app git clone https://github.com/valkey-io/valkey.git cd valkey -git checkout 9.0.4 +git checkout 9.1.0 for i in ../valkey_patches/*.patch do