Skip to content

Commit

Permalink
Merge pull request #12 from camargo2019/fix/improving-performance-in-…
Browse files Browse the repository at this point in the history
…memory-cache

⚡ fix: improving performance in memory cache
  • Loading branch information
camargo2019 authored Sep 12, 2024
2 parents 0dab72c + 18b82d3 commit 9612232
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 53 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ data/*.dat
.env*
.vscode/*
*.pdb
*.ilk
*.ilk
.vs/
8 changes: 6 additions & 2 deletions core/cache/cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
77 changes: 43 additions & 34 deletions core/manager/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@
#include "manager.h"

Manager::Manager(boost::asio::ip::tcp::socket socket, Cache& cache, std::function<void()> 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_();
Expand All @@ -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;
}
Expand All @@ -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<std::string> 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;

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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<std::string> args) noexcept {
void Manager::invokeDel(const std::vector<std::string>& args) noexcept {
if (args[0].empty()) return result("ERROR: use DEL KEY");

if (!cache_.del(user.db, args[0])){
Expand All @@ -133,7 +142,7 @@ void Manager::invokeDel(std::vector<std::string> args) noexcept {
result("SUCCESS: data deleted successfully");
}

void Manager::invokeSet(std::vector<std::string> args) {
void Manager::invokeSet(const std::vector<std::string>& args) noexcept {
if (args.size() < 2 || args[0].empty() || args[1].empty()) return result("ERROR: use SET KEY VALUE (EXPIRE)");

int expire = -1;
Expand All @@ -155,18 +164,18 @@ void Manager::invokeSet(std::vector<std::string> args) {

}

void Manager::invokeGet(std::vector<std::string> args) noexcept {
void Manager::invokeGet(const std::vector<std::string>& args) noexcept {
if (args[0].empty()) return result("ERROR: use GET KEY");

std::string value = cache_.get(user.db, args[0]);
if (value.empty()){
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<std::string> args) noexcept {
void Manager::invokeUse(const std::vector<std::string>& 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) {
Expand All @@ -180,7 +189,7 @@ void Manager::invokeUse(std::vector<std::string> args) noexcept {
result("ERROR: you are not allowed to do this");
}

void Manager::invokeAuth(std::vector<std::string> args) noexcept {
void Manager::invokeAuth(const std::vector<std::string>& args) noexcept {
if (args[0].empty() || args[1].empty()) return result("ERROR: use AUTH USER PASS");

for (const auto& auth : ConfigConn_.auth.basic) {
Expand All @@ -195,13 +204,13 @@ void Manager::invokeAuth(std::vector<std::string> args) noexcept {
result("ERROR: failed to authenticate");
}

void Manager::invokeKeys(std::vector<std::string> args) noexcept {
void Manager::invokeKeys(const std::vector<std::string>& args) noexcept {
std::string messageKeys;
std::vector<std::string> 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);
}

40 changes: 24 additions & 16 deletions core/manager/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
#include <vector>
#include <memory>
#include <chrono>
#include <charconv>
#include <iostream>
#include <stdexcept>
#include <functional>
#include <charconv>
#include <string_view>
#include <system_error>
#include <unordered_set>
#include <unordered_map>
Expand All @@ -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<std::string> all = {"AUTH", "USE", "GET", "SET", "DEL", "KEYS"};
};

std::unordered_set<std::string> authenticated = {
"GET", "SET", "USE", "DEL", "KEYS"
};

std::unordered_set<std::string> selected_database = {
"GET", "SET", "DEL", "KEYS"
};
};

class Manager: public std::enable_shared_from_this<Manager> {
public:
Expand All @@ -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<std::string> args) noexcept;
void invokeSet(std::vector<std::string> args);
void invokeGet(std::vector<std::string> args) noexcept;
void invokeAuth(std::vector<std::string> args) noexcept;
void invokeUse(std::vector<std::string> args) noexcept;
void invokeKeys(std::vector<std::string> args) noexcept;
void result(const std::string& value) noexcept;
void invokeAction(const std::string_view& line) noexcept;
void invokeDel(const std::vector<std::string>& args) noexcept;
void invokeSet(const std::vector<std::string>& args) noexcept;
void invokeGet(const std::vector<std::string>& args) noexcept;
void invokeAuth(const std::vector<std::string>& args) noexcept;
void invokeUse(const std::vector<std::string>& args) noexcept;
void invokeKeys(const std::vector<std::string>& args) noexcept;

Cache& cache_;
std::string data_;
UserEntities user;
ManagerCommands commands;
bool saveRunning_ = false;
std::function<void()> onDisconnect_;
boost::asio::ip::tcp::socket socket_;
ConfigConnect& ConfigConn_;
std::array<char, 1024> buffer_;
ManagerCommand Command;
std::array<char, 65536> buffer_;
std::unordered_map<std::string, void (Manager::*)(const std::vector<std::string>& args) noexcept> command_map;
};
#endif

0 comments on commit 9612232

Please sign in to comment.