From 18b82d3b1dc09a01375ea555344f9e7d17e7b14b Mon Sep 17 00:00:00 2001 From: Gabriel Camargo Date: Thu, 12 Sep 2024 20:23:22 -0300 Subject: [PATCH] :zap: fix: improving performance in memory cache --- .gitignore | 3 +- core/cache/cache.cpp | 8 +++-- core/manager/manager.cpp | 77 ++++++++++++++++++++++------------------ core/manager/manager.h | 40 ++++++++++++--------- 4 files changed, 75 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 3b69524..d3e2c45 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ data/*.dat .env* .vscode/* *.pdb -*.ilk \ No newline at end of file +*.ilk +.vs/ \ No newline at end of file diff --git a/core/cache/cache.cpp b/core/cache/cache.cpp index 9ab2479..3b0c1e2 100644 --- a/core/cache/cache.cpp +++ b/core/cache/cache.cpp @@ -76,8 +76,12 @@ std::string Cache::get(const std::string& db, const std::string& key) noexcept { } bool Cache::set(const std::string& db, const std::string& key, const std::string& value, int expire) noexcept { - CacheStruct data{std::move(value), expire}; - cache_[db].insert_or_assign(key, std::move(data)); + CacheStruct data{value, expire}; + auto& dbData = cache_[db]; + + dbData.reserve(dbData.size() + 1); + + auto result = dbData.emplace(key, std::move(data)); isChange = true; return true; diff --git a/core/manager/manager.cpp b/core/manager/manager.cpp index d91d14c..9720625 100644 --- a/core/manager/manager.cpp +++ b/core/manager/manager.cpp @@ -22,7 +22,14 @@ #include "manager.h" Manager::Manager(boost::asio::ip::tcp::socket socket, Cache& cache, std::function onDisconnect, ConfigConnect& ConfigConn) - : socket_(std::move(socket)), cache_(cache), onDisconnect_(onDisconnect), ConfigConn_(ConfigConn) {} + : socket_(std::move(socket)), cache_(cache), onDisconnect_(onDisconnect), ConfigConn_(ConfigConn) { + command_map[Command.auth] = &Manager::invokeAuth; + command_map[Command.use] = &Manager::invokeUse; + command_map[Command.get] = &Manager::invokeGet; + command_map[Command.set] = &Manager::invokeSet; + command_map[Command.del] = &Manager::invokeDel; + command_map[Command.keys] = &Manager::invokeKeys; +} Manager::~Manager() { onDisconnect_(); @@ -38,14 +45,17 @@ void Manager::read() noexcept { socket_.async_read_some( boost::asio::buffer(buffer_), [this, self](const boost::system::error_code& ec, std::size_t length) { - if (ec) return; + if (ec) { + std::cerr << "Erro ao ler do socket: " << ec.message() << std::endl; + return; + }; data_.append(buffer_.data(), length); std::size_t start = 0; std::size_t pos; while ((pos = data_.find("\r\n", start)) != std::string::npos) { - std::string line = data_.substr(start, pos - start); + std::string_view line(data_.data() + start, pos - start); invokeAction(line); start = pos + 2; } @@ -56,24 +66,33 @@ void Manager::read() noexcept { ); } -void Manager::result(std::string value) noexcept { - boost::asio::async_write(socket_, boost::asio::buffer(value), - [this](boost::system::error_code ec, std::size_t){}); +void Manager::result(const std::string& value) noexcept { + boost::asio::async_write(socket_, boost::asio::buffer(value), [this](const boost::system::error_code& ec, std::size_t _) {}); } -void Manager::invokeAction(const std::string& line) noexcept { +void Manager::invokeAction(const std::string_view& line) noexcept { std::vector args; - std::string command; + char useCommand[5] = {0}; - const char* ptr = line.c_str(); + const char* ptr = line.data(); const char* end = ptr + line.size(); - while (ptr != end && !std::isspace(*ptr)) { - command.push_back(std::toupper(*ptr)); + int i = 0; + while (ptr != end && !std::isspace(*ptr) && i < 4) { + useCommand[i++] += std::toupper(*ptr); ++ptr; } - if (commands.all.find(command) == commands.all.end()) return result("ERROR: incorrect command"); + auto action = command_map.find(useCommand); + if (action == command_map.end()) return result("ERROR: incorrect command"); + + if (user.user.empty() && user.db.empty() && Command.authenticated.find(useCommand) != Command.authenticated.end()) { + return result("ERROR: you are not authenticated"); + } + + if (user.db == "*" && Command.selected_database.find(useCommand) != Command.selected_database.end()) { + return result("ERROR: use the USE DB command to choose the name of the database instance"); + } while (ptr != end && std::isspace(*ptr)) ++ptr; @@ -86,7 +105,7 @@ void Manager::invokeAction(const std::string& line) noexcept { if (quote) { if (escape) { - value.push_back(c); + value += c; escape = false; } else if (c == '\\') { escape = true; @@ -95,7 +114,7 @@ void Manager::invokeAction(const std::string& line) noexcept { args.push_back(std::move(value)); value.clear(); } else { - value.push_back(c); + value += c; } } else if (c == '"' || c == '\'') { quote = c; @@ -105,25 +124,15 @@ void Manager::invokeAction(const std::string& line) noexcept { value.clear(); } } else { - value.push_back(c); + value += c; } } if (!value.empty()) args.push_back(std::move(value)); - - if (commands.auth == command) return invokeAuth(args); - - if (user.user.empty() && user.db.empty()) return result("ERROR: you are not authenticated"); - if (commands.use == command) return invokeUse(args); - - if (user.db == "*") return result("ERROR: use the USE DB command to choose the name of the database instance"); - if (commands.get == command) return invokeGet(args); - if (commands.set == command) return invokeSet(args); - if (commands.del == command) return invokeDel(args); - if (commands.keys == command) return invokeKeys(args); + (this->*(action->second))(args); } -void Manager::invokeDel(std::vector args) noexcept { +void Manager::invokeDel(const std::vector& args) noexcept { if (args[0].empty()) return result("ERROR: use DEL KEY"); if (!cache_.del(user.db, args[0])){ @@ -133,7 +142,7 @@ void Manager::invokeDel(std::vector args) noexcept { result("SUCCESS: data deleted successfully"); } -void Manager::invokeSet(std::vector args) { +void Manager::invokeSet(const std::vector& args) noexcept { if (args.size() < 2 || args[0].empty() || args[1].empty()) return result("ERROR: use SET KEY VALUE (EXPIRE)"); int expire = -1; @@ -155,7 +164,7 @@ void Manager::invokeSet(std::vector args) { } -void Manager::invokeGet(std::vector args) noexcept { +void Manager::invokeGet(const std::vector& args) noexcept { if (args[0].empty()) return result("ERROR: use GET KEY"); std::string value = cache_.get(user.db, args[0]); @@ -163,10 +172,10 @@ void Manager::invokeGet(std::vector args) noexcept { return result("ERROR: there is no record for this key"); } - result("SUCCESS: " + value); + result("SUCCESS: $"+std::to_string(value.size())+"\r\n" + value); } -void Manager::invokeUse(std::vector args) noexcept { +void Manager::invokeUse(const std::vector& args) noexcept { if (args[0].empty()) return result("ERROR: use the `USE DB` command to choose the name of the database instance"); for (const auto& auth : ConfigConn_.auth.basic) { @@ -180,7 +189,7 @@ void Manager::invokeUse(std::vector args) noexcept { result("ERROR: you are not allowed to do this"); } -void Manager::invokeAuth(std::vector args) noexcept { +void Manager::invokeAuth(const std::vector& args) noexcept { if (args[0].empty() || args[1].empty()) return result("ERROR: use AUTH USER PASS"); for (const auto& auth : ConfigConn_.auth.basic) { @@ -195,13 +204,13 @@ void Manager::invokeAuth(std::vector args) noexcept { result("ERROR: failed to authenticate"); } -void Manager::invokeKeys(std::vector args) noexcept { +void Manager::invokeKeys(const std::vector& args) noexcept { std::string messageKeys; std::vector keys = cache_.keys(user.db); for (const std::string& key : keys) { messageKeys += key + "\n"; } - return result("SUCCESS: \r\n" + messageKeys); + return result("SUCCESS: $"+std::to_string(messageKeys.size())+"\r\n" + messageKeys); } diff --git a/core/manager/manager.h b/core/manager/manager.h index 538d6c5..3dd9a89 100644 --- a/core/manager/manager.h +++ b/core/manager/manager.h @@ -26,10 +26,11 @@ #include #include #include + #include #include #include #include - #include + #include #include #include #include @@ -38,16 +39,22 @@ #include "../entities/user.h" #include "../entities/config.h" - struct ManagerCommands { + struct ManagerCommand { std::string set = "SET"; - std::string del = "DEL"; std::string get = "GET"; - std::string auth = "AUTH"; std::string use = "USE"; + std::string del = "DEL"; + std::string auth = "AUTH"; std::string keys = "KEYS"; - std::unordered_set all = {"AUTH", "USE", "GET", "SET", "DEL", "KEYS"}; - }; + + std::unordered_set authenticated = { + "GET", "SET", "USE", "DEL", "KEYS" + }; + std::unordered_set selected_database = { + "GET", "SET", "DEL", "KEYS" + }; + }; class Manager: public std::enable_shared_from_this { public: @@ -58,23 +65,24 @@ private: void read() noexcept; - void result(std::string value) noexcept; - void invokeAction(const std::string& line) noexcept; - void invokeDel(std::vector args) noexcept; - void invokeSet(std::vector args); - void invokeGet(std::vector args) noexcept; - void invokeAuth(std::vector args) noexcept; - void invokeUse(std::vector args) noexcept; - void invokeKeys(std::vector args) noexcept; + void result(const std::string& value) noexcept; + void invokeAction(const std::string_view& line) noexcept; + void invokeDel(const std::vector& args) noexcept; + void invokeSet(const std::vector& args) noexcept; + void invokeGet(const std::vector& args) noexcept; + void invokeAuth(const std::vector& args) noexcept; + void invokeUse(const std::vector& args) noexcept; + void invokeKeys(const std::vector& args) noexcept; Cache& cache_; std::string data_; UserEntities user; - ManagerCommands commands; bool saveRunning_ = false; std::function onDisconnect_; boost::asio::ip::tcp::socket socket_; ConfigConnect& ConfigConn_; - std::array buffer_; + ManagerCommand Command; + std::array buffer_; + std::unordered_map& args) noexcept> command_map; }; #endif \ No newline at end of file