From b83a0c835616d7d4369b5dafbfbd27910a5a23c5 Mon Sep 17 00:00:00 2001 From: Jett Date: Fri, 17 Nov 2023 11:55:12 +0800 Subject: [PATCH 1/7] feat: add and implement the incrby command --- src/base_cmd.h | 1 + src/cmd_kv.cc | 38 ++++++++++++++++++++++++++++++++++++++ src/cmd_kv.h | 12 ++++++++++++ src/cmd_table_manager.cc | 3 +++ src/store.cc | 37 +++++++++++++++++++++++++++++++++++-- src/store.h | 12 +++++++++--- 6 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/base_cmd.h b/src/base_cmd.h index f5f6e8501..f63457009 100644 --- a/src/base_cmd.h +++ b/src/base_cmd.h @@ -24,6 +24,7 @@ namespace pikiwidb { // string cmd const std::string kCmdNameSet = "set"; const std::string kCmdNameGet = "get"; +const std::string kCmdNameIncrby = "incrby"; // multi const std::string kCmdNameMulti = "multi"; diff --git a/src/cmd_kv.cc b/src/cmd_kv.cc index 9a626d157..863c12b16 100644 --- a/src/cmd_kv.cc +++ b/src/cmd_kv.cc @@ -6,6 +6,7 @@ */ #include "cmd_kv.h" +#include "pstd/pstd_string.h" #include "store.h" namespace pikiwidb { @@ -48,4 +49,41 @@ void SetCmd::DoCmd(PClient* client) { client->SetRes(CmdRes::kOk); } +IncrbyCmd::IncrbyCmd(const std::string& name, int16_t arity) + : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} + +bool IncrbyCmd::DoInitial(PClient* client) { + if (client->argv_.size() < 3) { + client->SetRes(CmdRes::kWrongNum, "incrby"); + return false; + } + printf("logloglog"); + if (!(pstd::String2int(client->argv_[2].data(), client->argv_[2].size(), &by_))) { + client->SetRes(CmdRes::kInvalidInt); + return false; + } + client->SetKey(client->argv_[1]); + return true; +} + +void IncrbyCmd::DoCmd(PClient* client) { + PObject* value; + PError err = PSTORE.Incrby(client->Key(), by_, &new_value_); + switch (err) { + case PError_type: + client->SetRes(CmdRes::kInvalidInt); + break; + case PError_notExist: // key not exist, set a new value + PSTORE.ClearExpire(client->Key()); // clear key's old ttl + PSTORE.SetValue(client->Key(), PObject::CreateString(by_)); + client->SetRes(CmdRes::kOk); + break; + case PError_ok: + client->AppendInteger(new_value_); + break; + default: + client->SetRes(CmdRes::kErrOther, "incrby cmd error"); + break; + } +} } // namespace pikiwidb \ No newline at end of file diff --git a/src/cmd_kv.h b/src/cmd_kv.h index a85272dcc..44dd58f25 100644 --- a/src/cmd_kv.h +++ b/src/cmd_kv.h @@ -33,4 +33,16 @@ class SetCmd : public BaseCmd { void DoCmd(PClient *client) override; }; +class IncrbyCmd : public BaseCmd { + public: + IncrbyCmd(const std::string &name, int16_t arity); + + protected: + bool DoInitial(PClient *client) override; + + private: + int64_t by_, new_value_ = 0; + void DoCmd(PClient *client) override; +}; + } // namespace pikiwidb diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index 36f4e845e..fbb7ba48d 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -32,6 +32,9 @@ void CmdTableManager::InitCmdTable() { cmds_->insert(std::make_pair(kCmdNameGet, std::move(getPtr))); std::unique_ptr setPtr = std::make_unique(kCmdNameSet, -3); cmds_->insert(std::make_pair(kCmdNameSet, std::move(setPtr))); + + std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, -3); + cmds_->insert(std::make_pair(kCmdNameIncrby, std::move(incrbyPtr))); } std::pair CmdTableManager::GetCommand(const std::string& cmdName, PClient* client) { diff --git a/src/store.cc b/src/store.cc index 43c5a1c59..dc3a55b40 100644 --- a/src/store.cc +++ b/src/store.cc @@ -441,9 +441,9 @@ bool PStore::DeleteKey(const PString& key) { size_t ret = 0; // erase() from folly ConcurrentHashmap will throw an exception if hash function crashes try { - ret = db->erase(key); + ret = db->erase(key); } catch (const std::exception& e) { - return false; + return false; } return ret != 0; @@ -556,6 +556,39 @@ PObject* PStore::SetValue(const PString& key, PObject&& value) { return const_cast(&obj); } +PError PStore::Incrby(const PString& key, int64_t value, int64_t* ret) { + PObject* old_value; + auto db = &dbs_[dbno_]; + + // shared when reading + std::shared_lock lock(mutex_); + PError err = getValueByType(key, old_value, PType_string); + if (err != PError_ok) { + return err; + } + char* end = nullptr; + auto str = pikiwidb::GetDecodedString(old_value); + int64_t ival = strtoll(str->c_str(), &end, 10); + if (*end != 0) { + // value is not a integer + return PError_type; + } + + PObject new_value; + *ret = ival + value; + new_value = PObject::CreateString((long)(*ret)); + new_value.lru = PObject::lruclock; + auto [realObj, status] = db->insert_or_assign(key, std::move(new_value)); + const PObject& obj = realObj->second; + + // put this key to sync list + if (!waitSyncKeys_.empty()) { + waitSyncKeys_[dbno_].insert_or_assign(key, &obj); + } + + return PError_ok; +} + void PStore::SetExpire(const PString& key, uint64_t when) const { expiredDBs_[dbno_].SetExpire(key, when); } int64_t PStore::TTL(const PString& key, uint64_t now) { return expiredDBs_[dbno_].TTL(key, now); } diff --git a/src/store.h b/src/store.h index 081d2cdcc..b16cb4cc3 100644 --- a/src/store.h +++ b/src/store.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include namespace pikiwidb { @@ -117,6 +119,8 @@ class PStore { PError GetValueByTypeNoTouch(const PString& key, PObject*& value, PType type = PType_invalid); PObject* SetValue(const PString& key, PObject&& value); + // incr + PError Incrby(const PString& key, int64_t value, int64_t* ret); // for expire key enum ExpireResult : std::int8_t { @@ -157,6 +161,8 @@ class PStore { private: PStore() : dbno_(0) {} + // mutex + mutable std::shared_mutex mutex_; PError getValueByType(const PString& key, PObject*& value, PType type = PType_invalid, bool touch = true); @@ -187,7 +193,7 @@ class PStore { size_t Size() const { return blockedClients_.size(); } private: - using Clients = std::list, uint64_t, ListPosition> >; + using Clients = std::list, uint64_t, ListPosition>>; using WaitingList = folly::ConcurrentHashMap>; WaitingList blockedClients_; @@ -199,9 +205,9 @@ class PStore { mutable std::vector dbs_; mutable std::vector expiredDBs_; std::vector blockedClients_; - std::vector > backends_; + std::vector> backends_; - using ToSyncDB = folly::ConcurrentHashMap >; + using ToSyncDB = folly::ConcurrentHashMap>; std::vector waitSyncKeys_; int dbno_ = -1; }; From 6374b48a3c08b2d26437488c161091b3469fd791 Mon Sep 17 00:00:00 2001 From: Jett Date: Sun, 19 Nov 2023 21:23:08 +0800 Subject: [PATCH 2/7] fix: deleted print log --- src/cmd_kv.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd_kv.cc b/src/cmd_kv.cc index 863c12b16..1eefad466 100644 --- a/src/cmd_kv.cc +++ b/src/cmd_kv.cc @@ -57,7 +57,6 @@ bool IncrbyCmd::DoInitial(PClient* client) { client->SetRes(CmdRes::kWrongNum, "incrby"); return false; } - printf("logloglog"); if (!(pstd::String2int(client->argv_[2].data(), client->argv_[2].size(), &by_))) { client->SetRes(CmdRes::kInvalidInt); return false; From ea8da60b9833183bd5c311c9aef11a08f793dc6a Mon Sep 17 00:00:00 2001 From: Jett Date: Wed, 29 Nov 2023 10:59:24 +0800 Subject: [PATCH 3/7] feat: resolve the issues found in pr --- src/cmd_kv.cc | 175 ++------------------------------------- src/cmd_kv.h | 1 - src/cmd_table_manager.cc | 2 +- src/store.cc | 2 +- 4 files changed, 8 insertions(+), 172 deletions(-) diff --git a/src/cmd_kv.cc b/src/cmd_kv.cc index 864e9a2ba..0efac72d4 100644 --- a/src/cmd_kv.cc +++ b/src/cmd_kv.cc @@ -215,180 +215,15 @@ void BitCountCmd::DoCmd(PClient* client) { client->AppendInteger(static_cast(count)); } -AppendCmd::AppendCmd(const std::string& name, int16_t arity) - : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} - -bool AppendCmd::DoInitial(PClient* client) { - client->SetKey(client->argv_[1]); - return true; -} - -void AppendCmd::DoCmd(PClient* client) { - PObject* value = nullptr; - PError err = PSTORE.GetValueByType(client->Key(), value, PType_string); - if (err != PError_ok) { - if (err == PError_notExist) { // = set command - PSTORE.ClearExpire(client->argv_[1]); // clear key's old ttl - PSTORE.SetValue(client->argv_[1], PObject::CreateString(client->argv_[2])); - client->AppendInteger(static_cast(client->argv_[2].size())); - } else { - client->SetRes(CmdRes::kErrOther, "append cmd error"); - } - return; - } - auto str = GetDecodedString(value); - std::string old_value(str->c_str(), str->size()); - std::string new_value = old_value + client->argv_[2]; - PSTORE.SetValue(client->argv_[1], PObject::CreateString(new_value)); - client->AppendInteger(static_cast(new_value.size())); -} - -GetsetCmd::GetsetCmd(const std::string& name, int16_t arity) - : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} - -bool GetsetCmd::DoInitial(PClient* client) { - client->SetKey(client->argv_[1]); - return true; -} - -void GetsetCmd::DoCmd(PClient* client) { - PObject* old_value = nullptr; - PError err = PSTORE.GetValueByType(client->Key(), old_value, PType_string); - if (err != PError_ok) { - if (err == PError_notExist) { // = set command - PSTORE.ClearExpire(client->argv_[1]); // clear key's old ttl - PSTORE.SetValue(client->argv_[1], PObject::CreateString(client->argv_[2])); - client->AppendString(""); - } else { - client->SetRes(CmdRes::kErrOther, "getset cmd error"); - } - return; - } - auto str = GetDecodedString(old_value); - PSTORE.ClearExpire(client->argv_[1]); // clear key's old ttl - PSTORE.SetValue(client->argv_[1], PObject::CreateString(client->argv_[2])); - client->AppendString(*str); -} - -MgetCmd::MgetCmd(const std::string& name, int16_t arity) - : BaseCmd(name, arity, CmdFlagsReadonly, AclCategoryRead | AclCategoryString) {} - -bool MgetCmd::DoInitial(PClient* client) { - std::vector keys(client->argv_.begin(), client->argv_.end()); - keys.erase(keys.begin()); - client->SetKey(keys); - return true; -} - -void MgetCmd::DoCmd(PClient* client) { - size_t valueSize = client->Keys().size(); - client->AppendArrayLen(static_cast(valueSize)); - for (const auto& k : client->Keys()) { - PObject* value = nullptr; - PError err = PSTORE.GetValueByType(k, value, PType_string); - if (err == PError_notExist) { - client->AppendStringLen(-1); - } else { - auto str = GetDecodedString(value); - std::string reply(str->c_str(), str->size()); - client->AppendStringLen(static_cast(reply.size())); - client->AppendContent(reply); - } - } -} - -MSetCmd::MSetCmd(const std::string& name, int16_t arity) - : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} - -bool MSetCmd::DoInitial(PClient* client) { - size_t argcSize = client->argv_.size(); - if (argcSize % 2 == 0) { - client->SetRes(CmdRes::kWrongNum, kCmdNameMset); - return false; - } - std::vector keys; - for (size_t index = 1; index < argcSize; index += 2) { - keys.emplace_back(client->argv_[index]); - } - client->SetKey(keys); - return true; -} - -void MSetCmd::DoCmd(PClient* client) { - int valueIndex = 2; - for (const auto& it : client->Keys()) { - PSTORE.ClearExpire(it); // clear key's old ttl - PSTORE.SetValue(it, PObject::CreateString(client->argv_[valueIndex])); - valueIndex += 2; - } - client->SetRes(CmdRes::kOk); -} - -BitCountCmd::BitCountCmd(const std::string& name, int16_t arity) - : BaseCmd(name, arity, CmdFlagsReadonly, AclCategoryRead | AclCategoryString) {} - -bool BitCountCmd::DoInitial(PClient* client) { - size_t paramSize = client->argv_.size(); - if (paramSize != 2 && paramSize != 4) { - client->SetRes(CmdRes::kSyntaxErr, kCmdNameBitCount); - return false; - } - client->SetKey(client->argv_[1]); - return true; -} - -void BitCountCmd::DoCmd(PClient* client) { - PObject* value = nullptr; - PError err = PSTORE.GetValueByType(client->argv_[1], value, PType_string); - if (err != PError_ok) { - if (err == PError_notExist) { - client->AppendInteger(0); - } else { - client->SetRes(CmdRes::kErrOther, "bitcount get key error"); - } - return; - } - - int64_t start_offset_; - int64_t end_offset_; - if (pstd::String2int(client->argv_[2], &start_offset_) == 0 || - pstd::String2int(client->argv_[3], &end_offset_) == 0) { - client->SetRes(CmdRes::kInvalidInt); - return; - } - - auto str = GetDecodedString(value); - auto value_length = static_cast(str->size()); - if (start_offset_ < 0) { - start_offset_ += value_length; - } - if (end_offset_ < 0) { - end_offset_ += value_length; - } - if (start_offset_ < 0) { - start_offset_ = 0; - } - if (end_offset_ < 0) { - end_offset_ = 0; - } - if (end_offset_ >= value_length) { - end_offset_ = value_length - 1; - } - size_t count = 0; - if (end_offset_ >= start_offset_) { - count = BitCount(reinterpret_cast(str->data()) + start_offset_, end_offset_ - start_offset_ + 1); - } - client->AppendInteger(static_cast(count)); -} - IncrbyCmd::IncrbyCmd(const std::string& name, int16_t arity) : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} bool IncrbyCmd::DoInitial(PClient* client) { - if (client->argv_.size() < 3) { + if (!CheckArg(client->argv_.size())) { client->SetRes(CmdRes::kWrongNum, "incrby"); return false; } + int64_t by_; if (!(pstd::String2int(client->argv_[2].data(), client->argv_[2].size(), &by_))) { client->SetRes(CmdRes::kInvalidInt); return false; @@ -398,7 +233,9 @@ bool IncrbyCmd::DoInitial(PClient* client) { } void IncrbyCmd::DoCmd(PClient* client) { - PObject* value; + int64_t new_value_ = 0; + int64_t by_ = 0; + pstd::String2int(client->argv_[2].data(), client->argv_[2].size(), &by_); PError err = PSTORE.Incrby(client->Key(), by_, &new_value_); switch (err) { case PError_type: @@ -407,7 +244,7 @@ void IncrbyCmd::DoCmd(PClient* client) { case PError_notExist: // key not exist, set a new value PSTORE.ClearExpire(client->Key()); // clear key's old ttl PSTORE.SetValue(client->Key(), PObject::CreateString(by_)); - client->SetRes(CmdRes::kOk); + client->AppendInteger(by_); break; case PError_ok: client->AppendInteger(new_value_); diff --git a/src/cmd_kv.h b/src/cmd_kv.h index 5735bc78a..e3ef2bab7 100644 --- a/src/cmd_kv.h +++ b/src/cmd_kv.h @@ -96,7 +96,6 @@ class IncrbyCmd : public BaseCmd { bool DoInitial(PClient *client) override; private: - int64_t by_, new_value_ = 0; void DoCmd(PClient *client) override; }; diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index 6a48c78fe..3ec353ed3 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -43,7 +43,7 @@ void CmdTableManager::InitCmdTable() { std::unique_ptr bitcountPtr = std::make_unique(kCmdNameBitCount, -2); cmds_->insert(std::make_pair(kCmdNameBitCount, std::move(bitcountPtr))); - std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, -3); + std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, -2); cmds_->insert(std::make_pair(kCmdNameIncrby, std::move(incrbyPtr))); } diff --git a/src/store.cc b/src/store.cc index dc3a55b40..3858634b9 100644 --- a/src/store.cc +++ b/src/store.cc @@ -561,7 +561,7 @@ PError PStore::Incrby(const PString& key, int64_t value, int64_t* ret) { auto db = &dbs_[dbno_]; // shared when reading - std::shared_lock lock(mutex_); + std::unique_lock lock(mutex_); PError err = getValueByType(key, old_value, PType_string); if (err != PError_ok) { return err; From 5a7050e64074c26d13cb260ed6725981e228e754 Mon Sep 17 00:00:00 2001 From: Jett Date: Wed, 29 Nov 2023 12:54:54 +0800 Subject: [PATCH 4/7] fix: initialize pointer --- src/store.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store.cc b/src/store.cc index 3858634b9..7379aa902 100644 --- a/src/store.cc +++ b/src/store.cc @@ -557,7 +557,7 @@ PObject* PStore::SetValue(const PString& key, PObject&& value) { } PError PStore::Incrby(const PString& key, int64_t value, int64_t* ret) { - PObject* old_value; + PObject* old_value = nullptr; auto db = &dbs_[dbno_]; // shared when reading From bcfb89cf441ece79e6da4a16213e0d9bf5c62ba0 Mon Sep 17 00:00:00 2001 From: Jett Date: Wed, 29 Nov 2023 12:56:46 +0800 Subject: [PATCH 5/7] fix: params nums --- src/cmd_table_manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index 3ec353ed3..6a48c78fe 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -43,7 +43,7 @@ void CmdTableManager::InitCmdTable() { std::unique_ptr bitcountPtr = std::make_unique(kCmdNameBitCount, -2); cmds_->insert(std::make_pair(kCmdNameBitCount, std::move(bitcountPtr))); - std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, -2); + std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, -3); cmds_->insert(std::make_pair(kCmdNameIncrby, std::move(incrbyPtr))); } From 5c041d5d9ae5efd58a91a94a725f1f7bb8c870df Mon Sep 17 00:00:00 2001 From: Jett Date: Wed, 29 Nov 2023 14:16:26 +0800 Subject: [PATCH 6/7] fix: fix commond params num --- src/cmd_table_manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_table_manager.cc b/src/cmd_table_manager.cc index 6a48c78fe..92215f1be 100644 --- a/src/cmd_table_manager.cc +++ b/src/cmd_table_manager.cc @@ -43,7 +43,7 @@ void CmdTableManager::InitCmdTable() { std::unique_ptr bitcountPtr = std::make_unique(kCmdNameBitCount, -2); cmds_->insert(std::make_pair(kCmdNameBitCount, std::move(bitcountPtr))); - std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, -3); + std::unique_ptr incrbyPtr = std::make_unique(kCmdNameIncrby, 3); cmds_->insert(std::make_pair(kCmdNameIncrby, std::move(incrbyPtr))); } From 25c543e2809552bc7c48968ea6ec6ba989e09558 Mon Sep 17 00:00:00 2001 From: Jett Date: Thu, 30 Nov 2023 11:34:06 +0800 Subject: [PATCH 7/7] feat: fix review bug --- src/cmd_kv.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/cmd_kv.cc b/src/cmd_kv.cc index 0efac72d4..b9f7aa970 100644 --- a/src/cmd_kv.cc +++ b/src/cmd_kv.cc @@ -219,11 +219,7 @@ IncrbyCmd::IncrbyCmd(const std::string& name, int16_t arity) : BaseCmd(name, arity, CmdFlagsWrite, AclCategoryWrite | AclCategoryString) {} bool IncrbyCmd::DoInitial(PClient* client) { - if (!CheckArg(client->argv_.size())) { - client->SetRes(CmdRes::kWrongNum, "incrby"); - return false; - } - int64_t by_; + int64_t by_ = 0; if (!(pstd::String2int(client->argv_[2].data(), client->argv_[2].size(), &by_))) { client->SetRes(CmdRes::kInvalidInt); return false;