@@ -217,6 +217,15 @@ class KeywordCommandBase : public Commander {
217217};
218218
219219class CommandTSCreateBase : public KeywordCommandBase {
220+ public:
221+ Status Execute ([[maybe_unused]] engine::Context &ctx, Server *srv, [[maybe_unused]] Connection *conn,
222+ [[maybe_unused]] std::string *output) override {
223+ if (srv->GetConfig ()->cluster_enabled && getCreateOption ().labels .size ()) {
224+ return {Status::RedisExecErr, " Specifying LABELS is not supported in cluster mode" };
225+ }
226+ return Status::OK ();
227+ }
228+
220229 protected:
221230 const TSCreateOption &getCreateOption () const { return create_option_; }
222231
@@ -308,6 +317,9 @@ class CommandTSCreate : public CommandTSCreateBase {
308317 return CommandTSCreateBase::Parse (args);
309318 }
310319 Status Execute (engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
320+ auto sc = CommandTSCreateBase::Execute (ctx, srv, conn, output);
321+ if (!sc.IsOK ()) return sc;
322+
311323 auto timeseries_db = TimeSeries (srv->storage , conn->GetNamespace ());
312324 auto s = timeseries_db.Create (ctx, args_[1 ], getCreateOption ());
313325 if (!s.ok () && s.IsInvalidArgument ()) return {Status::RedisExecErr, errKeyAlreadyExists};
@@ -387,6 +399,9 @@ class CommandTSAdd : public CommandTSCreateBase {
387399 return CommandTSCreateBase::Parse (args);
388400 }
389401 Status Execute (engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
402+ auto sc = CommandTSCreateBase::Execute (ctx, srv, conn, output);
403+ if (!sc.IsOK ()) return sc;
404+
390405 auto timeseries_db = TimeSeries (srv->storage , conn->GetNamespace ());
391406 const auto &option = getCreateOption ();
392407
@@ -851,6 +866,9 @@ class CommandTSMGet : public CommandTSMGetBase {
851866 return CommandTSMGetBase::Parse (args);
852867 }
853868 Status Execute (engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
869+ if (srv->GetConfig ()->cluster_enabled ) {
870+ return {Status::RedisExecErr, " TS.MGet is not supported in cluster mode" };
871+ }
854872 auto timeseries_db = TimeSeries (srv->storage , conn->GetNamespace ());
855873 std::vector<TSMGetResult> results;
856874 auto s = timeseries_db.MGet (ctx, getMGetOption (), is_return_latest_, &results);
@@ -898,6 +916,9 @@ class CommandTSMRange : public CommandTSRangeBase, public CommandTSMGetBase {
898916 return Status::OK ();
899917 }
900918 Status Execute (engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
919+ if (srv->GetConfig ()->cluster_enabled ) {
920+ return {Status::RedisExecErr, " TS.MRANGE is not supported in cluster mode" };
921+ }
901922 auto timeseries_db = TimeSeries (srv->storage , conn->GetNamespace ());
902923 std::vector<TSMRangeResult> results;
903924 auto s = timeseries_db.MRange (ctx, option_, &results);
@@ -978,6 +999,117 @@ class CommandTSMRange : public CommandTSRangeBase, public CommandTSMGetBase {
978999 TSMRangeOption option_;
9791000};
9801001
1002+ class CommandTSIncrByDecrBy : public CommandTSCreateBase {
1003+ public:
1004+ CommandTSIncrByDecrBy () { registerDefaultHandlers (); }
1005+ Status Parse (const std::vector<std::string> &args) override {
1006+ CommandParser parser (args, 2 );
1007+ auto value_parse = parser.TakeFloat <double >();
1008+ if (!value_parse.IsOK ()) {
1009+ return {Status::RedisParseErr, errInvalidValue};
1010+ }
1011+ value_ = value_parse.GetValue ();
1012+ if (util::ToUpper (args[0 ]) == " TS.DECRBY" ) {
1013+ value_ = -value_;
1014+ }
1015+ CommandTSCreateBase::setSkipNum (3 );
1016+ return CommandTSCreateBase::Parse (args);
1017+ }
1018+ Status Execute (engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
1019+ auto sc = CommandTSCreateBase::Execute (ctx, srv, conn, output);
1020+ if (!sc.IsOK ()) return sc;
1021+
1022+ auto timeseries_db = TimeSeries (srv->storage , conn->GetNamespace ());
1023+ const auto &option = getCreateOption ();
1024+
1025+ if (!is_ts_set_) {
1026+ // TODO: Should modify function `Add` and `IncrBy` to add a sample with current time
1027+ }
1028+ TSChunk::AddResult res;
1029+ auto s = timeseries_db.IncrBy (ctx, args_[1 ], {ts_, value_}, option, &res);
1030+ if (!s.ok ()) return {Status::RedisExecErr, s.ToString ()};
1031+
1032+ if (res.type == TSChunk::AddResultType::kOld ) {
1033+ *output +=
1034+ redis::Error ({Status::NotOK, " timestamp must be equal to or higher than the maximum existing timestamp" });
1035+ } else {
1036+ *output += FormatAddResultAsRedisReply (res);
1037+ }
1038+ return Status::OK ();
1039+ }
1040+
1041+ protected:
1042+ void registerDefaultHandlers () override {
1043+ CommandTSCreateBase::registerDefaultHandlers ();
1044+ registerHandler (" TIMESTAMP" , [this ](TSOptionsParser &parser) {
1045+ auto s = handleTimeStamp (parser, ts_);
1046+ if (!s.IsOK ()) return s;
1047+ is_ts_set_ = true ;
1048+ return Status::OK ();
1049+ });
1050+ }
1051+ static Status handleTimeStamp (TSOptionsParser &parser, uint64_t &ts) {
1052+ auto parse_timestamp = parser.TakeInt <uint64_t >();
1053+ if (!parse_timestamp.IsOK ()) {
1054+ return {Status::RedisParseErr, errInvalidTimestamp};
1055+ }
1056+ ts = parse_timestamp.GetValue ();
1057+ return Status::OK ();
1058+ }
1059+
1060+ private:
1061+ bool is_ts_set_ = false ;
1062+ uint64_t ts_ = 0 ;
1063+ double value_ = 0 ;
1064+ };
1065+
1066+ class CommandTSDel : public Commander {
1067+ public:
1068+ Status Parse (const std::vector<std::string> &args) override {
1069+ if (args.size () < 4 ) {
1070+ return {Status::RedisParseErr, " wrong number of arguments for 'ts.del' command" };
1071+ }
1072+ CommandParser parser (args, 2 );
1073+ // Parse start timestamp
1074+ auto start_parse = parser.TakeInt <uint64_t >();
1075+ if (!start_parse.IsOK ()) {
1076+ auto start_ts_str = parser.TakeStr ();
1077+ if (!start_ts_str.IsOK () || start_ts_str.GetValue () != " -" ) {
1078+ return {Status::RedisParseErr, " wrong fromTimestamp" };
1079+ }
1080+ // "-" means use default start timestamp: 0
1081+ } else {
1082+ start_ts_ = start_parse.GetValue ();
1083+ }
1084+ // Parse end timestamp
1085+ auto end_parse = parser.TakeInt <uint64_t >();
1086+ if (!end_parse.IsOK ()) {
1087+ auto end_ts_str = parser.TakeStr ();
1088+ if (!end_ts_str.IsOK () || end_ts_str.GetValue () != " +" ) {
1089+ return {Status::RedisParseErr, " wrong toTimestamp" };
1090+ }
1091+ // "+" means use default end timestamp: MAX_TIMESTAMP
1092+ } else {
1093+ end_ts_ = end_parse.GetValue ();
1094+ }
1095+ return Commander::Parse (args);
1096+ }
1097+ Status Execute (engine::Context &ctx, Server *srv, Connection *conn, std::string *output) override {
1098+ auto timeseries_db = TimeSeries (srv->storage , conn->GetNamespace ());
1099+ uint64_t deleted_count = 0 ;
1100+ auto s = timeseries_db.Del (ctx, args_[1 ], start_ts_, end_ts_, &deleted_count);
1101+ if (!s.ok ()) {
1102+ return {Status::RedisExecErr, s.ToString ()};
1103+ }
1104+ *output = redis::Integer (deleted_count);
1105+ return Status::OK ();
1106+ }
1107+
1108+ private:
1109+ uint64_t start_ts_ = 0 ;
1110+ uint64_t end_ts_ = TSSample::MAX_TIMESTAMP;
1111+ };
1112+
9811113REDIS_REGISTER_COMMANDS (Timeseries, MakeCmdAttr<CommandTSCreate>(" ts.create" , -2 , " write" , 1 , 1 , 1 ),
9821114 MakeCmdAttr<CommandTSAdd>(" ts.add" , -4 , " write" , 1 , 1 , 1 ),
9831115 MakeCmdAttr<CommandTSMAdd>(" ts.madd" , -4 , " write" , 1 , -3 , 1 ),
@@ -986,6 +1118,9 @@ REDIS_REGISTER_COMMANDS(Timeseries, MakeCmdAttr<CommandTSCreate>("ts.create", -2
9861118 MakeCmdAttr<CommandTSGet>(" ts.get" , -2 , " read-only" , 1 , 1 , 1 ),
9871119 MakeCmdAttr<CommandTSCreateRule>(" ts.createrule" , -6 , " write" , 1 , 2 , 1 ),
9881120 MakeCmdAttr<CommandTSMGet>(" ts.mget" , -3 , " read-only" , NO_KEY),
989- MakeCmdAttr<CommandTSMRange>(" ts.mrange" , -5 , " read-only" , NO_KEY), );
1121+ MakeCmdAttr<CommandTSMRange>(" ts.mrange" , -5 , " read-only" , NO_KEY),
1122+ MakeCmdAttr<CommandTSIncrByDecrBy>(" ts.incrby" , -3 , " write" , 1 , 1 , 1 ),
1123+ MakeCmdAttr<CommandTSIncrByDecrBy>(" ts.decrby" , -3 , " write" , 1 , 1 , 1 ),
1124+ MakeCmdAttr<CommandTSDel>(" ts.del" , -4 , " write" , 1 , 1 , 1 ), );
9901125
9911126} // namespace redis
0 commit comments