From 8f1d2add8836b5a70a313df8a4802fdcc1817741 Mon Sep 17 00:00:00 2001 From: hulk Date: Sat, 15 Jun 2024 11:43:33 +0800 Subject: [PATCH] chore(error): unify error by adding Redis error codes for Status (#2362) This PR introduces new error codes to identify Redis error prefixes, and forces using status to unify Redis errors. You MUST convert it to Status to send a Redis error response. --- src/cluster/cluster.cc | 19 +++-- src/cluster/cluster_defs.h | 2 +- src/cluster/replication.cc | 9 ++- src/cluster/sync_migrate_context.cc | 2 +- src/commands/cmd_bloom_filter.cc | 8 +- src/commands/cmd_cluster.cc | 20 ++--- src/commands/cmd_hash.cc | 9 +-- src/commands/cmd_key.cc | 14 ++-- src/commands/cmd_list.cc | 6 +- src/commands/cmd_replication.cc | 4 +- src/commands/cmd_script.cc | 3 +- src/commands/cmd_server.cc | 32 ++++---- src/commands/cmd_stream.cc | 24 ++---- src/commands/cmd_txn.cc | 3 +- src/commands/cmd_zset.cc | 20 ++--- src/commands/error_constants.h | 6 +- src/common/status.h | 14 +++- src/server/redis_connection.cc | 28 +++---- src/server/redis_reply.cc | 24 +++++- src/server/redis_reply.h | 6 +- src/server/worker.cc | 5 +- src/storage/rdb.cc | 109 ++++++---------------------- src/storage/scripting.cc | 11 ++- src/types/json.h | 2 +- 24 files changed, 162 insertions(+), 218 deletions(-) diff --git a/src/cluster/cluster.cc b/src/cluster/cluster.cc index d080ed34452..8d373e0dfc1 100644 --- a/src/cluster/cluster.cc +++ b/src/cluster/cluster.cc @@ -363,7 +363,7 @@ Status Cluster::ImportSlot(redis::Connection *conn, int slot, int state) { Status Cluster::GetClusterInfo(std::string *cluster_infos) { if (version_ < 0) { - return {Status::ClusterDown, errClusterNoInitialized}; + return {Status::RedisClusterDown, errClusterNoInitialized}; } cluster_infos->clear(); @@ -421,7 +421,7 @@ Status Cluster::GetClusterInfo(std::string *cluster_infos) { // ... continued until done Status Cluster::GetSlotsInfo(std::vector *slots_infos) { if (version_ < 0) { - return {Status::ClusterDown, errClusterNoInitialized}; + return {Status::RedisClusterDown, errClusterNoInitialized}; } slots_infos->clear(); @@ -464,7 +464,7 @@ SlotInfo Cluster::genSlotNodeInfo(int start, int end, const std::shared_ptr Cluster::GetReplicas(const std::string &node_id) { if (version_ < 0) { - return {Status::ClusterDown, errClusterNoInitialized}; + return {Status::RedisClusterDown, errClusterNoInitialized}; } auto item = nodes_.find(node_id); @@ -821,13 +821,13 @@ Status Cluster::CanExecByMySelf(const redis::CommandAttributes *attributes, cons int cur_slot = GetSlotIdFromKey(cmd_tokens[i]); if (slot == -1) slot = cur_slot; if (slot != cur_slot) { - return {Status::RedisExecErr, "CROSSSLOT Attempted to access keys that don't hash to the same slot"}; + return {Status::RedisCrossSlot, "Attempted to access keys that don't hash to the same slot"}; } } if (slot == -1) return Status::OK(); if (slots_nodes_[slot] == nullptr) { - return {Status::ClusterDown, "CLUSTERDOWN Hash slot not served"}; + return {Status::RedisClusterDown, "Hash slot not served"}; } if (myself_ && myself_ == slots_nodes_[slot]) { @@ -835,12 +835,12 @@ Status Cluster::CanExecByMySelf(const redis::CommandAttributes *attributes, cons // Server can't change the topology directly, so we record the migrated slots // to move the requests of the migrated slots to the destination node. if (migrated_slots_.count(slot) > 0) { // I'm not serving the migrated slot - return {Status::RedisExecErr, fmt::format("MOVED {} {}", slot, migrated_slots_[slot])}; + return {Status::RedisMoved, fmt::format("{} {}", slot, migrated_slots_[slot])}; } // To keep data consistency, slot will be forbidden write while sending the last incremental data. // During this phase, the requests of the migrating slot has to be rejected. if ((attributes->flags & redis::kCmdWrite) && IsWriteForbiddenSlot(slot)) { - return {Status::RedisExecErr, "TRYAGAIN Can't write to slot being migrated which is in write forbidden phase"}; + return {Status::RedisTryAgain, "Can't write to slot being migrated which is in write forbidden phase"}; } return Status::OK(); // I'm serving this slot @@ -868,8 +868,7 @@ Status Cluster::CanExecByMySelf(const redis::CommandAttributes *attributes, cons return Status::OK(); // My master is serving this slot } - return {Status::RedisExecErr, - fmt::format("MOVED {} {}:{}", slot, slots_nodes_[slot]->host, slots_nodes_[slot]->port)}; + return {Status::RedisMoved, fmt::format("{} {}:{}", slot, slots_nodes_[slot]->host, slots_nodes_[slot]->port)}; } // Only HARD mode is meaningful to the Kvrocks cluster, diff --git a/src/cluster/cluster_defs.h b/src/cluster/cluster_defs.h index 6638db8807e..0178ac75884 100644 --- a/src/cluster/cluster_defs.h +++ b/src/cluster/cluster_defs.h @@ -36,7 +36,7 @@ inline constexpr const char *errSlotOutOfRange = "Slot is out of range"; inline constexpr const char *errInvalidClusterVersion = "Invalid cluster version"; inline constexpr const char *errSlotOverlapped = "Slot distribution is overlapped"; inline constexpr const char *errNoMasterNode = "The node isn't a master"; -inline constexpr const char *errClusterNoInitialized = "CLUSTERDOWN The cluster is not initialized"; +inline constexpr const char *errClusterNoInitialized = "The cluster is not initialized"; inline constexpr const char *errInvalidClusterNodeInfo = "Invalid cluster nodes info"; inline constexpr const char *errInvalidImportState = "Invalid import state"; diff --git a/src/cluster/replication.cc b/src/cluster/replication.cc index a3567284091..3de51a94047 100644 --- a/src/cluster/replication.cc +++ b/src/cluster/replication.cc @@ -1000,15 +1000,18 @@ Status ReplicationThread::parseWriteBatch(const std::string &batch_string) { } bool ReplicationThread::isRestoringError(std::string_view err) { - return err == std::string(RESP_PREFIX_ERROR) + redis::errRestoringBackup; + // err doesn't contain the CRLF, so cannot use redis::Error here. + return err == RESP_PREFIX_ERROR + redis::StatusToRedisErrorMsg({Status::RedisLoading, redis::errRestoringBackup}); } bool ReplicationThread::isWrongPsyncNum(std::string_view err) { - return err == std::string(RESP_PREFIX_ERROR) + redis::errWrongNumArguments; + // err doesn't contain the CRLF, so cannot use redis::Error here. + return err == RESP_PREFIX_ERROR + redis::StatusToRedisErrorMsg({Status::NotOK, redis::errWrongNumArguments}); } bool ReplicationThread::isUnknownOption(std::string_view err) { - return err == fmt::format("{}ERR {}", RESP_PREFIX_ERROR, redis::errUnknownOption); + // err doesn't contain the CRLF, so cannot use redis::Error here. + return err == RESP_PREFIX_ERROR + redis::StatusToRedisErrorMsg({Status::NotOK, redis::errUnknownOption}); } rocksdb::Status WriteBatchHandler::PutCF(uint32_t column_family_id, const rocksdb::Slice &key, diff --git a/src/cluster/sync_migrate_context.cc b/src/cluster/sync_migrate_context.cc index 3ba2806ca45..f1de89b6e26 100644 --- a/src/cluster/sync_migrate_context.cc +++ b/src/cluster/sync_migrate_context.cc @@ -68,7 +68,7 @@ void SyncMigrateContext::OnWrite(bufferevent *bev) { if (migrate_result_) { conn_->Reply(redis::SimpleString("OK")); } else { - conn_->Reply(redis::Error("ERR " + migrate_result_.Msg())); + conn_->Reply(redis::Error(migrate_result_)); } timer_.reset(); diff --git a/src/commands/cmd_bloom_filter.cc b/src/commands/cmd_bloom_filter.cc index f33979e3d50..bb2df94e2f5 100644 --- a/src/commands/cmd_bloom_filter.cc +++ b/src/commands/cmd_bloom_filter.cc @@ -33,7 +33,7 @@ constexpr const char *errInvalidErrorRate = "error rate should be between 0 and constexpr const char *errInvalidCapacity = "capacity should be larger than 0"; constexpr const char *errInvalidExpansion = "expansion should be greater or equal to 1"; constexpr const char *errNonscalingButExpand = "nonscaling filters cannot expand"; -constexpr const char *errFilterFull = "ERR nonscaling filter is full"; +constexpr const char *errFilterFull = "nonscaling filter is full"; } // namespace namespace redis { @@ -119,7 +119,7 @@ class CommandBFAdd : public Commander { *output = redis::Integer(0); break; case BloomFilterAddResult::kFull: - *output = redis::Error(errFilterFull); + *output = redis::Error({Status::NotOK, errFilterFull}); break; } return Status::OK(); @@ -152,7 +152,7 @@ class CommandBFMAdd : public Commander { *output += redis::Integer(0); break; case BloomFilterAddResult::kFull: - *output += redis::Error(errFilterFull); + *output += redis::Error({Status::NotOK, errFilterFull}); break; } } @@ -248,7 +248,7 @@ class CommandBFInsert : public Commander { *output += redis::Integer(0); break; case BloomFilterAddResult::kFull: - *output += redis::Error(errFilterFull); + *output += redis::Error({Status::NotOK, errFilterFull}); break; } } diff --git a/src/commands/cmd_cluster.cc b/src/commands/cmd_cluster.cc index 8ada4e8eec0..0f9b17603fc 100644 --- a/src/commands/cmd_cluster.cc +++ b/src/commands/cmd_cluster.cc @@ -90,7 +90,7 @@ class CommandCluster : public Commander { } } } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "nodes") { std::string nodes_desc; @@ -98,7 +98,7 @@ class CommandCluster : public Commander { if (s.IsOK()) { *output = conn->VerbatimString("txt", nodes_desc); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "info") { std::string cluster_info; @@ -106,21 +106,21 @@ class CommandCluster : public Commander { if (s.IsOK()) { *output = conn->VerbatimString("txt", cluster_info); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "import") { Status s = srv->cluster->ImportSlot(conn, static_cast(slot_), state_); if (s.IsOK()) { *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "reset") { Status s = srv->cluster->Reset(); if (s.IsOK()) { *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "replicas") { auto node_id = args_[2]; @@ -128,7 +128,7 @@ class CommandCluster : public Commander { if (s.IsOK()) { *output = conn->VerbatimString("txt", s.GetValue()); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else { return {Status::RedisExecErr, "Invalid cluster command options"}; @@ -252,7 +252,7 @@ class CommandClusterX : public Commander { need_persist_nodes_info = true; *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "setnodeid") { Status s = srv->cluster->SetNodeId(args_[2]); @@ -260,7 +260,7 @@ class CommandClusterX : public Commander { need_persist_nodes_info = true; *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "setslot") { Status s = srv->cluster->SetSlotRanges(slot_ranges_, args_[4], set_version_); @@ -268,7 +268,7 @@ class CommandClusterX : public Commander { need_persist_nodes_info = true; *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else if (subcommand_ == "version") { int64_t v = srv->cluster->GetVersion(); @@ -287,7 +287,7 @@ class CommandClusterX : public Commander { } *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else { return {Status::RedisExecErr, "Invalid cluster command options"}; diff --git a/src/commands/cmd_hash.cc b/src/commands/cmd_hash.cc index 6db97f89025..677f131eb98 100644 --- a/src/commands/cmd_hash.cc +++ b/src/commands/cmd_hash.cc @@ -326,16 +326,11 @@ class CommandHRangeByLex : public Commander { return parser.InvalidSyntax(); } } - Status s; if (spec_.reversed) { - s = ParseRangeLexSpec(args[3], args[2], &spec_); + return ParseRangeLexSpec(args[3], args[2], &spec_); } else { - s = ParseRangeLexSpec(args[2], args[3], &spec_); + return ParseRangeLexSpec(args[2], args[3], &spec_); } - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } - return Status::OK(); } Status Execute(Server *srv, Connection *conn, std::string *output) override { diff --git a/src/commands/cmd_key.cc b/src/commands/cmd_key.cc index 24d8fe29c4d..d7219841a80 100644 --- a/src/commands/cmd_key.cc +++ b/src/commands/cmd_key.cc @@ -480,8 +480,7 @@ class CommandSort : public Commander { } if (type != RedisType::kRedisList && type != RedisType::kRedisSet && type != RedisType::kRedisZSet) { - *output = Error("WRONGTYPE Operation against a key holding the wrong kind of value"); - return Status::OK(); + return {Status::RedisWrongType, "Operation against a key holding the wrong kind of value"}; } /* When sorting a set with no sort specified, we must sort the output @@ -508,15 +507,12 @@ class CommandSort : public Commander { switch (res) { case Database::SortResult::UNKNOWN_TYPE: - *output = redis::Error("Unknown Type"); - break; + return {Status::RedisErrorNoPrefix, "Unknown Type"}; case Database::SortResult::DOUBLE_CONVERT_ERROR: - *output = redis::Error("One or more scores can't be converted into double"); - break; + return {Status::RedisErrorNoPrefix, "One or more scores can't be converted into double"}; case Database::SortResult::LIMIT_EXCEEDED: - *output = redis::Error("The number of elements to be sorted exceeds SORT_LENGTH_LIMIT = " + - std::to_string(SORT_LENGTH_LIMIT)); - break; + return {Status::RedisErrorNoPrefix, + "The number of elements to be sorted exceeds SORT_LENGTH_LIMIT = " + std::to_string(SORT_LENGTH_LIMIT)}; case Database::SortResult::DONE: if (sort_argument_.storekey.empty()) { std::vector output_vec; diff --git a/src/commands/cmd_list.cc b/src/commands/cmd_list.cc index f354d64cc4b..e9e17266625 100644 --- a/src/commands/cmd_list.cc +++ b/src/commands/cmd_list.cc @@ -304,7 +304,7 @@ class CommandBPop : public BlockingCommander { conn_->Reply(conn_->MultiBulkString({*last_key_ptr, std::move(elem)})); } } else if (!s.IsNotFound()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); } return s; @@ -414,7 +414,7 @@ class CommandBLMPop : public BlockingCommander { conn_->Reply(redis::Array({redis::BulkString(chosen_key), std::move(elems_bulk)})); } } else if (!s.IsNotFound()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); } return s; @@ -757,7 +757,7 @@ class CommandBLMove : public BlockingCommander { std::string elem; auto s = list_db.LMove(args_[1], args_[2], src_left_, dst_left_, &elem); if (!s.ok() && !s.IsNotFound()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); return true; } diff --git a/src/commands/cmd_replication.cc b/src/commands/cmd_replication.cc index 5ec6faa03b6..d3f3c0f25c5 100644 --- a/src/commands/cmd_replication.cc +++ b/src/commands/cmd_replication.cc @@ -102,7 +102,7 @@ class CommandPSync : public Commander { srv->stats.IncrPSyncOKCount(); s = srv->AddSlave(conn, next_repl_seq_); if (!s.IsOK()) { - std::string err = redis::Error(s.Msg()); + std::string err = redis::Error(s); s = util::SockSend(conn->GetFD(), err, conn->GetBufferEvent()); if (!s.IsOK()) { LOG(WARNING) << "failed to send error message to the replica: " << s.Msg(); @@ -230,7 +230,7 @@ class CommandFetchMeta : public Commander { std::string files; auto s = engine::Storage::ReplDataManager::GetFullReplDataInfo(srv->storage, &files); if (!s.IsOK()) { - s = util::SockSend(repl_fd, redis::Error("can't create db checkpoint"), bev); + s = util::SockSend(repl_fd, redis::Error({Status::RedisErrorNoPrefix, "can't create db checkpoint"}), bev); if (!s.IsOK()) { LOG(WARNING) << "[replication] Failed to send error response: " << s.Msg(); } diff --git a/src/commands/cmd_script.cc b/src/commands/cmd_script.cc index 34a7183756d..2547c289fcf 100644 --- a/src/commands/cmd_script.cc +++ b/src/commands/cmd_script.cc @@ -31,8 +31,7 @@ class CommandEvalImpl : public Commander { public: Status Execute(Server *srv, Connection *conn, std::string *output) override { if (evalsha && args_[1].size() != 40) { - *output = redis::Error(errNoMatchingScript); - return Status::OK(); + return {Status::RedisNoScript, errNoMatchingScript}; } int64_t numkeys = GET_OR_RET(ParseInt(args_[2], 10)); diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc index 114eee15f27..d595875d7bb 100644 --- a/src/commands/cmd_server.cc +++ b/src/commands/cmd_server.cc @@ -95,17 +95,17 @@ class CommandNamespace : public Commander { } } else if (args_.size() == 4 && sub_command == "set") { Status s = srv->GetNamespace()->Set(args_[2], args_[3]); - *output = s.IsOK() ? redis::SimpleString("OK") : redis::Error("ERR " + s.Msg()); + *output = s.IsOK() ? redis::SimpleString("OK") : redis::Error(s); LOG(WARNING) << "Updated namespace: " << args_[2] << " with token: " << args_[3] << ", addr: " << conn->GetAddr() << ", result: " << s.Msg(); } else if (args_.size() == 4 && sub_command == "add") { Status s = srv->GetNamespace()->Add(args_[2], args_[3]); - *output = s.IsOK() ? redis::SimpleString("OK") : redis::Error("ERR " + s.Msg()); + *output = s.IsOK() ? redis::SimpleString("OK") : redis::Error(s); LOG(WARNING) << "New namespace: " << args_[2] << " with token: " << args_[3] << ", addr: " << conn->GetAddr() << ", result: " << s.Msg(); } else if (args_.size() == 3 && sub_command == "del") { Status s = srv->GetNamespace()->Del(args_[2]); - *output = s.IsOK() ? redis::SimpleString("OK") : redis::Error("ERR " + s.Msg()); + *output = s.IsOK() ? redis::SimpleString("OK") : redis::Error(s); LOG(WARNING) << "Deleted namespace: " << args_[2] << ", addr: " << conn->GetAddr() << ", result: " << s.Msg(); } else { return {Status::RedisExecErr, "NAMESPACE subcommand must be one of GET, SET, DEL, ADD"}; @@ -224,7 +224,7 @@ class CommandConfig : public Commander { if (args_.size() == 2 && sub_command == "rewrite") { Status s = config->Rewrite(srv->GetNamespace()->List()); - if (!s.IsOK()) return {Status::RedisExecErr, s.Msg()}; + if (!s.IsOK()) return s; *output = redis::SimpleString("OK"); LOG(INFO) << "# CONFIG REWRITE executed with success"; @@ -315,7 +315,7 @@ class CommandDBSize : public Commander { if (s.IsOK()) { *output = redis::SimpleString("OK"); } else { - return {Status::RedisExecErr, s.Msg()}; + return s; } } else { return {Status::RedisExecErr, "DBSIZE subcommand only supports scan"}; @@ -630,9 +630,9 @@ class CommandDebug : public Commander { } else if (protocol_type_ == "verbatim") { // verbatim string *output = conn->VerbatimString("txt", "verbatim string"); } else { - *output = redis::Error( - "Wrong protocol type name. Please use one of the following: " - "string|integer|double|array|set|bignum|true|false|null|attrib|verbatim"); + return {Status::RedisErrorNoPrefix, + "Wrong protocol type name. Please use one of the following: " + "string|integer|double|array|set|bignum|true|false|null|attrib|verbatim"}; } } else if (subcommand_ == "dbsize-limit") { srv->storage->SetDBSizeLimit(dbsize_limit_); @@ -741,8 +741,7 @@ class CommandHello final : public Commander { // kvrocks only supports REPL2 by now, but for supporting some // `hello 3`, it will not report error when using 3. if (protocol < 2 || protocol > 3) { - conn->Reply(redis::Error("NOPROTO unsupported protocol version")); - return Status::OK(); + return {Status::RedisNoProto, "unsupported protocol version"}; } } @@ -986,9 +985,7 @@ class CommandSlaveOf : public Commander { } auto s = IsTryingToReplicateItself(srv, host_, port_); - if (!s.IsOK()) { - return {Status::RedisExecErr, s.Msg()}; - } + if (!s.IsOK()) return s; s = srv->AddMaster(host_, port_, false); if (s.IsOK()) { *output = redis::SimpleString("OK"); @@ -1101,7 +1098,7 @@ class CommandRestore : public Commander { auto stream_ptr = std::make_unique(args_[3]); RDB rdb(srv->storage, conn->GetNamespace(), std::move(stream_ptr)); auto s = rdb.Restore(args_[1], args_[3], ttl_ms_); - if (!s.IsOK()) return {Status::RedisExecErr, s.Msg()}; + if (!s.IsOK()) return s; *output = redis::SimpleString("OK"); return Status::OK(); } @@ -1215,9 +1212,8 @@ class CommandApplyBatch : public Commander { auto options = svr->storage->DefaultWriteOptions(); options.low_pri = low_pri_; auto s = svr->storage->ApplyWriteBatch(options, std::move(raw_batch_)); - if (!s.IsOK()) { - return {Status::RedisExecErr, s.Msg()}; - } + if (!s.IsOK()) return s; + *output = redis::Integer(size); return Status::OK(); } @@ -1262,7 +1258,7 @@ class CommandDump : public Commander { auto stream_ptr = std::make_unique(result); RDB rdb(srv->storage, conn->GetNamespace(), std::move(stream_ptr)); auto s = rdb.Dump(key, type); - if (!s.IsOK()) return {Status::RedisExecErr, s.Msg()}; + if (!s.IsOK()) return s; CHECK(dynamic_cast(rdb.GetStream().get()) != nullptr); *output = redis::BulkString(static_cast(rdb.GetStream().get())->GetInput()); return Status::OK(); diff --git a/src/commands/cmd_stream.cc b/src/commands/cmd_stream.cc index 7b3bf54e236..ba4f7d9870c 100644 --- a/src/commands/cmd_stream.cc +++ b/src/commands/cmd_stream.cc @@ -39,9 +39,7 @@ class CommandXAck : public Commander { StreamEntryID tmp_id; for (size_t i = 3; i < args.size(); ++i) { auto s = ParseStreamEntryID(args[i], &tmp_id); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; entry_ids_.emplace_back(tmp_id); } @@ -130,9 +128,7 @@ class CommandXAdd : public Commander { } auto s = ParseStreamEntryID(args[min_id_idx], &min_id_); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; with_min_id_ = true; i += eq_sign_found ? 3 : 2; @@ -145,9 +141,7 @@ class CommandXAdd : public Commander { if (!entry_id_found) { auto result = ParseNextStreamEntryIDStrategy(val); - if (!result.IsOK()) { - return {Status::RedisParseErr, result.Msg()}; - } + if (!result.IsOK()) return result; next_id_strategy_ = std::move(*result); @@ -1130,7 +1124,7 @@ class CommandXRead : public Commander, std::vector result; auto s = stream_db.Range(streams_[i], options, &result); if (!s.ok() && !s.IsNotFound()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); return; } @@ -1423,7 +1417,7 @@ class CommandXReadGroup : public Commander, auto s = stream_db.RangeWithPending(streams_[i], options, &result, group_name_, consumer_name_, noack_, latest_marks_[i]); if (!s.ok() && !s.IsNotFound()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); return; } @@ -1599,9 +1593,7 @@ class CommandXSetId : public Commander { stream_name_ = args[1]; auto s = redis::ParseStreamEntryID(args[2], &last_id_); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; if (args.size() == 3) { return Status::OK(); @@ -1619,9 +1611,7 @@ class CommandXSetId : public Commander { } else if (util::EqualICase(args[i], "maxdeletedid") && i + 1 < args.size()) { StreamEntryID id; s = redis::ParseStreamEntryID(args[i + 1], &id); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; max_deleted_id_ = std::make_optional(id.ms, id.seq); i += 2; diff --git a/src/commands/cmd_txn.cc b/src/commands/cmd_txn.cc index fa1a47aadae..130533fbc9b 100644 --- a/src/commands/cmd_txn.cc +++ b/src/commands/cmd_txn.cc @@ -68,8 +68,7 @@ class CommandExec : public Commander { auto reset_multiexec = MakeScopeExit([conn] { conn->ResetMultiExec(); }); if (conn->IsMultiError()) { - *output = redis::Error("EXECABORT Transaction discarded"); - return Status::OK(); + return {Status::RedisExecAbort, "Transaction discarded"}; } if (srv->IsWatchedKeysModified(conn)) { diff --git a/src/commands/cmd_zset.cc b/src/commands/cmd_zset.cc index c32c976a431..715747ab8a4 100644 --- a/src/commands/cmd_zset.cc +++ b/src/commands/cmd_zset.cc @@ -136,9 +136,7 @@ class CommandZCount : public Commander { public: Status Parse(const std::vector &args) override { Status s = ParseRangeScoreSpec(args[2], args[3], &spec_); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; return Commander::Parse(args); } @@ -204,9 +202,7 @@ class CommandZLexCount : public Commander { public: Status Parse(const std::vector &args) override { Status s = ParseRangeLexSpec(args[2], args[3], &spec_); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; return Commander::Parse(args); } @@ -369,7 +365,7 @@ class CommandBZPop : public BlockingCommander { redis::ZSet zset_db(srv_->storage, conn_->GetNamespace()); auto s = PopFromMultipleZsets(&zset_db, keys_, min_, 1, &user_key, &member_scores); if (!s.ok()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); return true; } @@ -548,7 +544,7 @@ class CommandBZMPop : public BlockingCommander { redis::ZSet zset_db(srv_->storage, conn_->GetNamespace()); auto s = PopFromMultipleZsets(&zset_db, keys_, flag_ == ZSET_MIN, count_, &user_key, &member_scores); if (!s.ok()) { - conn_->Reply(redis::Error("ERR " + s.ToString())); + conn_->Reply(redis::Error({Status::NotOK, s.ToString()})); return true; } @@ -985,9 +981,7 @@ class CommandZRemRangeByScore : public Commander { public: Status Parse(const std::vector &args) override { Status s = ParseRangeScoreSpec(args[2], args[3], &spec_); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; return Commander::Parse(args); } @@ -1014,9 +1008,7 @@ class CommandZRemRangeByLex : public Commander { public: Status Parse(const std::vector &args) override { Status s = ParseRangeLexSpec(args[2], args[3], &spec_); - if (!s.IsOK()) { - return {Status::RedisParseErr, s.Msg()}; - } + if (!s.IsOK()) return s; return Commander::Parse(args); } diff --git a/src/commands/error_constants.h b/src/commands/error_constants.h index 2074a705531..ea2c38b72c0 100644 --- a/src/commands/error_constants.h +++ b/src/commands/error_constants.h @@ -40,10 +40,10 @@ inline constexpr const char *errLimitOptionNotAllowed = inline constexpr const char *errZSetLTGTNX = "GT, LT, and/or NX options at the same time are not compatible"; inline constexpr const char *errScoreIsNotValidFloat = "score is not a valid float"; inline constexpr const char *errValueIsNotFloat = "value is not a valid float"; -inline constexpr const char *errNoMatchingScript = "NOSCRIPT No matching script. Please use EVAL"; +inline constexpr const char *errNoMatchingScript = "No matching script. Please use EVAL"; inline constexpr const char *errUnknownOption = "unknown option"; inline constexpr const char *errUnknownSubcommandOrWrongArguments = "Unknown subcommand or wrong number of arguments"; -inline constexpr const char *errWrongNumArguments = "ERR wrong number of arguments"; -inline constexpr const char *errRestoringBackup = "LOADING kvrocks is restoring the db from backup"; +inline constexpr const char *errWrongNumArguments = "wrong number of arguments"; +inline constexpr const char *errRestoringBackup = "kvrocks is restoring the db from backup"; } // namespace redis diff --git a/src/common/status.h b/src/common/status.h index b425ea5b238..d06c2f06014 100644 --- a/src/common/status.h +++ b/src/common/status.h @@ -50,9 +50,21 @@ class [[nodiscard]] Status { RedisInvalidCmd, RedisParseErr, RedisExecErr, + RedisErrorNoPrefix, + RedisNoProto, + RedisLoading, + RedisMasterDown, + RedisNoScript, + RedisNoAuth, + RedisWrongType, + RedisReadOnly, + RedisExecAbort, + RedisMoved, + RedisCrossSlot, + RedisTryAgain, + RedisClusterDown, // Cluster - ClusterDown, ClusterInvalidInfo, // Blocking diff --git a/src/server/redis_connection.cc b/src/server/redis_connection.cc index f3960a66001..0457c71d57e 100644 --- a/src/server/redis_connection.cc +++ b/src/server/redis_connection.cc @@ -87,7 +87,7 @@ void Connection::OnRead(struct bufferevent *bev) { auto s = req_.Tokenize(Input()); if (!s.IsOK()) { EnableFlag(redis::Connection::kCloseAfterReply); - Reply(redis::Error("ERR " + s.Msg())); + Reply(redis::Error(s)); LOG(INFO) << "[connection] Failed to tokenize the request. Error: " << s.Msg(); return; } @@ -432,7 +432,7 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { auto cmd_s = Server::LookupAndCreateCommand(cmd_tokens.front()); if (!cmd_s.IsOK()) { if (is_multi_exec) multi_error_ = true; - Reply(redis::Error("ERR unknown command " + cmd_tokens.front())); + Reply(redis::Error({Status::NotOK, "unknown command " + cmd_tokens.front()})); continue; } auto current_cmd = std::move(*cmd_s); @@ -444,7 +444,7 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { if (GetNamespace().empty()) { if (!password.empty()) { if (cmd_name != "auth" && cmd_name != "hello") { - Reply(redis::Error("NOAUTH Authentication required.")); + Reply(redis::Error({Status::RedisNoAuth, "Authentication required."})); continue; } } else { @@ -477,7 +477,7 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { } if (srv_->IsLoading() && !(cmd_flags & kCmdLoading)) { - Reply(redis::Error(errRestoringBackup)); + Reply(redis::Error({Status::RedisLoading, errRestoringBackup})); if (is_multi_exec) multi_error_ = true; continue; } @@ -485,7 +485,7 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { int tokens = static_cast(cmd_tokens.size()); if (!attributes->CheckArity(tokens)) { if (is_multi_exec) multi_error_ = true; - Reply(redis::Error("ERR wrong number of arguments")); + Reply(redis::Error({Status::NotOK, "wrong number of arguments"})); continue; } @@ -493,12 +493,12 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { auto s = current_cmd->Parse(); if (!s.IsOK()) { if (is_multi_exec) multi_error_ = true; - Reply(redis::Error("ERR " + s.Msg())); + Reply(redis::Error(s)); continue; } if (is_multi_exec && (cmd_flags & kCmdNoMulti)) { - Reply(redis::Error("ERR Can't execute " + cmd_name + " in MULTI")); + Reply(redis::Error({Status::NotOK, "Can't execute " + cmd_name + " in MULTI"})); multi_error_ = true; continue; } @@ -507,7 +507,7 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { s = srv_->cluster->CanExecByMySelf(attributes, cmd_tokens, this); if (!s.IsOK()) { if (is_multi_exec) multi_error_ = true; - Reply(redis::Error(s.Msg())); + Reply(redis::Error(s)); continue; } } @@ -525,20 +525,20 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { } if (config->slave_readonly && srv_->IsSlave() && (cmd_flags & kCmdWrite)) { - Reply(redis::Error("READONLY You can't write against a read only slave.")); + Reply(redis::Error({Status::RedisReadOnly, "You can't write against a read only slave."})); continue; } if ((cmd_flags & kCmdWrite) && !(cmd_flags & kCmdNoDBSizeCheck) && srv_->storage->ReachedDBSizeLimit()) { - Reply(redis::Error("ERR write command not allowed when reached max-db-size.")); + Reply(redis::Error({Status::NotOK, "write command not allowed when reached max-db-size."})); continue; } if (!config->slave_serve_stale_data && srv_->IsSlave() && cmd_name != "info" && cmd_name != "slaveof" && srv_->GetReplicationState() != kReplConnected) { - Reply( - redis::Error("MASTERDOWN Link with MASTER is down " - "and slave-serve-stale-data is set to 'no'.")); + Reply(redis::Error({Status::RedisMasterDown, + "Link with MASTER is down " + "and slave-serve-stale-data is set to 'no'."})); continue; } @@ -585,7 +585,7 @@ void Connection::ExecuteCommands(std::deque *to_process_cmds) { // Reply for MULTI if (!s.IsOK()) { - Reply(redis::Error("ERR " + s.Msg())); + Reply(redis::Error(s)); continue; } diff --git a/src/server/redis_reply.cc b/src/server/redis_reply.cc index d2143b6a787..20e15e512f8 100644 --- a/src/server/redis_reply.cc +++ b/src/server/redis_reply.cc @@ -20,15 +20,37 @@ #include "redis_reply.h" +#include #include +const std::map redisErrorPrefixMapping = { + {Status::RedisErrorNoPrefix, ""}, {Status::RedisNoProto, "NOPROTO"}, + {Status::RedisLoading, "LOADING"}, {Status::RedisMasterDown, "MASTERDOWN"}, + {Status::RedisNoScript, "NOSCRIPT"}, {Status::RedisNoAuth, "NOAUTH"}, + {Status::RedisWrongType, "WRONGTYPE"}, {Status::RedisReadOnly, "READONLY"}, + {Status::RedisExecAbort, "EXECABORT"}, {Status::RedisMoved, "MOVED"}, + {Status::RedisCrossSlot, "CROSSSLOT"}, {Status::RedisTryAgain, "TRYAGAIN"}, + {Status::RedisClusterDown, "CLUSTERDOWN"}}; + namespace redis { void Reply(evbuffer *output, const std::string &data) { evbuffer_add(output, data.c_str(), data.length()); } std::string SimpleString(const std::string &data) { return "+" + data + CRLF; } -std::string Error(const std::string &err) { return "-" + err + CRLF; } +std::string Error(const Status &s) { return RESP_PREFIX_ERROR + StatusToRedisErrorMsg(s) + CRLF; } + +std::string StatusToRedisErrorMsg(const Status &s) { + CHECK(!s.IsOK()); + std::string prefix = "ERR"; + if (auto it = redisErrorPrefixMapping.find(s.GetCode()); it != redisErrorPrefixMapping.end()) { + prefix = it->second; + } + if (prefix.empty()) { + return s.Msg(); + } + return prefix + " " + s.Msg(); +} std::string BulkString(const std::string &data) { return "$" + std::to_string(data.length()) + CRLF + data + CRLF; } diff --git a/src/server/redis_reply.h b/src/server/redis_reply.h index c7fd3b2a8e2..f50c559d704 100644 --- a/src/server/redis_reply.h +++ b/src/server/redis_reply.h @@ -25,6 +25,8 @@ #include #include +#include "status.h" + #define CRLF "\r\n" // NOLINT #define RESP_PREFIX_ERROR "-" // NOLINT #define RESP_PREFIX_SIMPLE_STRING "+" // NOLINT @@ -35,7 +37,9 @@ enum class RESP { v2, v3 }; void Reply(evbuffer *output, const std::string &data); std::string SimpleString(const std::string &data); -std::string Error(const std::string &err); + +std::string Error(const Status &s); +std::string StatusToRedisErrorMsg(const Status &s); template , int> = 0> std::string Integer(T data) { diff --git a/src/server/worker.cc b/src/server/worker.cc index 1e8fed37441..22054e1faf8 100644 --- a/src/server/worker.cc +++ b/src/server/worker.cc @@ -167,7 +167,7 @@ void Worker::newTCPConnection(evconnlistener *listener, evutil_socket_t fd, sock s = AddConnection(conn); if (!s.IsOK()) { - std::string err_msg = redis::Error("ERR " + s.Msg()); + std::string err_msg = redis::Error({Status::NotOK, s.Msg()}); s = util::SockSend(fd, err_msg, ssl); if (!s.IsOK()) { LOG(WARNING) << "Failed to send error response to socket: " << s.Msg(); @@ -200,8 +200,7 @@ void Worker::newUnixSocketConnection(evconnlistener *listener, evutil_socket_t f auto s = AddConnection(conn); if (!s.IsOK()) { - std::string err_msg = redis::Error("ERR " + s.Msg()); - s = util::SockSend(fd, err_msg); + s = util::SockSend(fd, redis::Error(s)); if (!s.IsOK()) { LOG(WARNING) << "Failed to send error response to socket: " << s.Msg(); } diff --git a/src/storage/rdb.cc b/src/storage/rdb.cc index f513caca698..31c56f00159 100644 --- a/src/storage/rdb.cc +++ b/src/storage/rdb.cc @@ -688,9 +688,9 @@ Status RDB::Dump(const std::string &key, const RedisType type) { /* Serialize the object in an RDB-like format. It consist of an object type * byte followed by the serialized object. This is understood by RESTORE. */ auto s = SaveObjectType(type); - if (!s.IsOK()) return {Status::RedisExecErr, s.Msg()}; + if (!s.IsOK()) return s; s = SaveObject(key, type); - if (!s.IsOK()) return {Status::RedisExecErr, s.Msg()}; + if (!s.IsOK()) return s; /* Write the footer, this is how it looks like: * ----------------+---------------------+---------------+ @@ -705,21 +705,14 @@ Status RDB::Dump(const std::string &key, const RedisType type) { buf[0] = MinRDBVersion & 0xff; buf[1] = (MinRDBVersion >> 8) & 0xff; s = stream_->Write((const char *)buf, 2); - if (!s.IsOK()) { - return {Status::RedisExecErr, s.Msg()}; - } + if (!s.IsOK()) return s; /* CRC64 */ CHECK(dynamic_cast(stream_.get()) != nullptr); std::string &output = static_cast(stream_.get())->GetInput(); uint64_t crc = crc64(0, (unsigned char *)(output.c_str()), output.length()); memrev64ifbe(&crc); - s = stream_->Write((const char *)(&crc), 8); - if (!s.IsOK()) { - return {Status::RedisExecErr, s.Msg()}; - } - - return Status::OK(); + return stream_->Write((const char *)(&crc), 8); } Status RDB::SaveObjectType(const RedisType type) { @@ -797,48 +790,28 @@ Status RDB::RdbSaveLen(uint64_t len) { if (len < (1 << 6)) { /* Save a 6 bit len */ buf[0] = (len & 0xFF) | (RDB6BitLen << 6); - auto status = stream_->Write((const char *)buf, 1); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } - return Status::OK(); + return stream_->Write((const char *)buf, 1); } else if (len < (1 << 14)) { /* Save a 14 bit len */ buf[0] = ((len >> 8) & 0xFF) | (RDB14BitLen << 6); buf[1] = len & 0xFF; - auto status = stream_->Write((const char *)buf, 2); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } - return Status::OK(); + return stream_->Write((const char *)buf, 2); } else if (len <= UINT32_MAX) { /* Save a 32 bit len */ buf[0] = RDB32BitLen; auto status = stream_->Write((const char *)buf, 1); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; uint32_t len32 = htonl(len); - status = stream_->Write((const char *)(&len32), 4); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } - return Status::OK(); + return stream_->Write((const char *)(&len32), 4); } else { /* Save a 64 bit len */ buf[0] = RDB64BitLen; auto status = stream_->Write((const char *)buf, 1); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; len = htonu64(len); - status = stream_->Write((const char *)(&len), 8); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } - return Status::OK(); + return stream_->Write((const char *)(&len), 8); } } @@ -857,11 +830,7 @@ Status RDB::SaveStringObject(const std::string &value) { // encode integer enclen = rdbEncodeInteger(integer_value, buf); if (enclen > 0) { - auto status = stream_->Write((const char *)buf, enclen); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } - return Status::OK(); + return stream_->Write((const char *)buf, enclen); } } } @@ -871,14 +840,9 @@ Status RDB::SaveStringObject(const std::string &value) { /* Store verbatim */ auto status = RdbSaveLen(value.length()); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; if (value.length() > 0) { - status = stream_->Write(value.c_str(), value.length()); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + return stream_->Write(value.c_str(), value.length()); } return Status::OK(); } @@ -886,15 +850,11 @@ Status RDB::SaveStringObject(const std::string &value) { Status RDB::SaveListObject(const std::vector &elems) { if (elems.size() > 0) { auto status = RdbSaveLen(elems.size()); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; for (const auto &elem : elems) { auto status = rdbSaveZipListObject(elem); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; } } else { LOG(WARNING) << "the size of elems is zero"; @@ -906,15 +866,11 @@ Status RDB::SaveListObject(const std::vector &elems) { Status RDB::SaveSetObject(const std::vector &members) { if (members.size() > 0) { auto status = RdbSaveLen(members.size()); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; for (const auto &elem : members) { status = SaveStringObject(elem); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; } } else { LOG(WARNING) << "the size of elems is zero"; @@ -926,20 +882,14 @@ Status RDB::SaveSetObject(const std::vector &members) { Status RDB::SaveZSetObject(const std::vector &member_scores) { if (member_scores.size() > 0) { auto status = RdbSaveLen(member_scores.size()); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; for (const auto &elem : member_scores) { status = SaveStringObject(elem.member); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; status = rdbSaveBinaryDoubleValue(elem.score); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; } } else { LOG(WARNING) << "the size of member_scores is zero"; @@ -951,20 +901,14 @@ Status RDB::SaveZSetObject(const std::vector &member_scores) { Status RDB::SaveHashObject(const std::vector &field_values) { if (field_values.size() > 0) { auto status = RdbSaveLen(field_values.size()); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; for (const auto &p : field_values) { status = SaveStringObject(p.field); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; status = SaveStringObject(p.value); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } + if (!status.IsOK()) return status; } } else { LOG(WARNING) << "the size of field_values is zero"; @@ -1024,10 +968,5 @@ Status RDB::rdbSaveZipListObject(const std::string &elem) { ZipList::SetZipListLength(zl_ptr, ziplist_size, 1); zl_ptr[ziplist_size - 1] = zlEnd; - auto status = SaveStringObject(zl_string); - if (!status.IsOK()) { - return {Status::RedisExecErr, status.Msg()}; - } - - return Status::OK(); + return SaveStringObject(zl_string); } diff --git a/src/storage/scripting.cc b/src/storage/scripting.cc index 409d5e19f92..5197eb5c1b1 100644 --- a/src/storage/scripting.cc +++ b/src/storage/scripting.cc @@ -611,8 +611,7 @@ Status EvalGenericCommand(redis::Connection *conn, const std::string &body_or_sh auto s = srv->ScriptGet(funcname + 2, &body); if (!s.IsOK()) { lua_pop(lua, 1); /* remove the error handler from the stack. */ - *output = redis::Error(redis::errNoMatchingScript); - return Status::OK(); + return {Status::RedisNoScript, redis::errNoMatchingScript}; } } else { body = body_or_sha; @@ -640,8 +639,8 @@ Status EvalGenericCommand(redis::Connection *conn, const std::string &body_or_sh SetGlobalArray(lua, "ARGV", argv); if (lua_pcall(lua, 0, 1, -2)) { - auto msg = fmt::format("ERR running script (call to {}): {}", funcname, lua_tostring(lua, -1)); - *output = redis::Error(msg); + auto msg = fmt::format("running script (call to {}): {}", funcname, lua_tostring(lua, -1)); + *output = redis::Error({Status::NotOK, msg}); lua_pop(lua, 2); } else { *output = ReplyToRedisReply(conn, lua); @@ -755,7 +754,7 @@ int RedisGenericCommand(lua_State *lua, int raise_error) { if (config->cluster_enabled) { auto s = srv->cluster->CanExecByMySelf(attributes, args, conn); if (!s.IsOK()) { - PushError(lua, s.Msg().c_str()); + PushError(lua, redis::StatusToRedisErrorMsg(s).c_str()); return raise_error ? RaiseError(lua) : 1; } } @@ -1192,7 +1191,7 @@ std::string ReplyToRedisReply(redis::Connection *conn, lua_State *lua) { lua_rawget(lua, -2); t = lua_type(lua, -1); if (t == LUA_TSTRING) { - output = redis::Error(lua_tostring(lua, -1)); + output = redis::Error({Status::RedisErrorNoPrefix, lua_tostring(lua, -1)}); lua_pop(lua, 1); return output; } diff --git a/src/types/json.h b/src/types/json.h index 0ce88797295..13abb5cc954 100644 --- a/src/types/json.h +++ b/src/types/json.h @@ -238,7 +238,7 @@ struct JsonValue { } catch (const jsoncons::jsonpath::jsonpath_error &e) { return {Status::NotOK, e.what()}; } - if (!s) return {Status::NotOK, s.Msg()}; + if (!s) return s; return results; }