diff --git a/CMakeLists.txt b/CMakeLists.txt
index 085d0ed..bce5289 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,6 +66,8 @@ add_executable(sharedMemoryKeyDB
core/UDB.h
core/DatabaseManager.cpp
core/DatabaseManager.h
+ utils/config/GlobalConfig.h
+ utils/config/GlobalConfig.cpp
)
add_executable(sharedMemoryKeyDB_client
diff --git a/README.md b/README.md
index 29b7789..a704399 100644
--- a/README.md
+++ b/README.md
@@ -210,4 +210,53 @@ response = read_bytes(ptr, offset + 1050, response_size)
- После обработки команды — инкрементировать `tail` мод capacity.
- Ответ через `response` + `response_size` + `response_ready` только для `FIND`.
----
\ No newline at end of file
+---
+
+# Конфиг
+Пример:
+```toml
+# Список баз данных
+[[database]]
+name = "rates1"
+
+[[database]]
+name = "test"
+
+# Настройки базы rates1
+[databases.rates1]
+shm_queue_capacity = 2048 # Размер очереди команд в shared memory (количество команд)
+max_memtable_size = 2097152 # Максимальный размер активной Memtable в байтах (до сброса на диск)
+l0_queue_capacity = 2048 # Размер очереди для фоновой компакции L0 SSTables
+estimated_element_size = 256 # Оценка среднего размера одного элемента в Memtable в байтах
+
+# Настройки базы test
+[databases.test]
+shm_queue_capacity = 1024
+max_memtable_size = 1048576
+l0_queue_capacity = 1024
+estimated_element_size = 128
+```
+
+## Замечания:
+Если параметры не заданы для конкретной базы, используются значения по умолчанию:
+```cpp
+shm_queue_capacity = 1024
+max_memtable_size = 1048576
+l0_queue_capacity = 1024
+estimated_element_size = 128
+```
+
+> Все размеры (max_memtable_size, estimated_element_size) указываются в байтах.
+
+> Shared Memory для каждой базы будет создана с именем /shm_<имя_базы>.
+
+> Очереди (l0_queue, shm_queue) построены на lock-free кольцевых буферах.
+
+## Полное описание параметров конфига
+
+| Параметр | Тип | Описание |
+| :----------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `shm_queue_capacity` | `size_t` | **Размер очереди команд в shared memory**.
Это количество слотов команд (PUT/DELETE/FIND), которые могут одновременно находиться в памяти. Если очередь заполнится — новые команды временно не смогут быть отправлены.
**Важно**: shared memory выделяется исходя из этого размера, поэтому очередь большого размера требует больше памяти. |
+| `max_memtable_size` | `size_t` | **Максимальный размер активной Memtable в байтах**.
Когда объем данных в Memtable превышает это значение, Memtable сбрасывается на диск в SSTable-файл.
**Если значение маленькое** — будет много мелких SSTable-файлов.
**Если значение большое** — реже будет происходить сброс, но потребление оперативной памяти будет выше. |
+| `l0_queue_capacity` | `size_t` | **Размер очереди файлов для компакции L0 уровня**.
Когда Memtable сбрасывается в SSTable, файл ставится в очередь на компакцию. Этот параметр задает максимальное количество файлов, которые можно держать в очереди одновременно.
**Если значение маленькое** — компакция будет происходить чаще.
**Если большое** — будет задержка в обработке компакции при большом потоке вставок. |
+| `estimated_element_size` | `size_t` | **Оценка среднего размера одного элемента в Memtable**.
Используется для **приближенного** расчета реального размера Memtable. Нужно, чтобы **не замерять точно каждый вставленный элемент**, а быстро определять когда пора сбрасывать Memtable.
**Типичный случай**: текстовые значения без больших вложений имеют размер 64-256 байт. |
\ No newline at end of file
diff --git a/core/DatabaseManager.cpp b/core/DatabaseManager.cpp
index 0c5b75b..6e71fa0 100644
--- a/core/DatabaseManager.cpp
+++ b/core/DatabaseManager.cpp
@@ -4,7 +4,6 @@
#include "DatabaseManager.h"
-
namespace usub::core
{
DatabaseManager::DatabaseManager(const std::string& config_path)
@@ -34,8 +33,10 @@ namespace usub::core
{
throw std::runtime_error("Database entry must be a table");
}
+ utils::load_global_config(config);
+ auto& database_settings = utils::database_settings_map.at(db_name);
bool create_new = !SharedMemoryManager::exists("shm_" + db_name);
- auto udb = std::make_unique(db_name, "shm_" + db_name, 1024, 1024 * 1024, create_new);
+ auto udb = std::make_unique(db_name, "shm_" + db_name, database_settings, create_new);
this->databases_.push_back(DatabaseInstance{std::move(udb), {}});
}
}
diff --git a/core/Memtable.h b/core/Memtable.h
index c8d6a0a..4367c2b 100644
--- a/core/Memtable.h
+++ b/core/Memtable.h
@@ -10,6 +10,7 @@
#include
#include "utils/io/Wal.h"
#include "utils/io/VersionManager.h"
+#include "utils/config/GlobalConfig.h"
namespace usub::shared_storage
{
@@ -19,7 +20,7 @@ namespace usub::shared_storage
class MemTableManager
{
public:
- MemTableManager(const std::string& wal_file, size_t max_size, utils::VersionManager& vm);
+ MemTableManager(const std::string& wal_file, size_t max_size, size_t estimated_element_size, utils::VersionManager& vm);
~MemTableManager();
@@ -41,6 +42,7 @@ namespace usub::shared_storage
std::vector> write_batch;
std::atomic flushing{false};
VersionManager& version_manager;
+ size_t estimated_element_size;
private:
size_t estimate_memtable_size() const;
@@ -49,7 +51,7 @@ namespace usub::shared_storage
};
template
- MemTableManager::MemTableManager(const std::string& wal_file, size_t max_size, VersionManager& vm)
+ MemTableManager::MemTableManager(const std::string& wal_file, size_t max_size, size_t estimated_element_size, VersionManager& vm)
: wal(wal_file), max_memtable_size(max_size), version_manager(vm)
{
this->active_memtable.store(new SkipList(this->version_manager));
diff --git a/core/UDB.cpp b/core/UDB.cpp
index 05cab13..0e1a77e 100644
--- a/core/UDB.cpp
+++ b/core/UDB.cpp
@@ -7,14 +7,14 @@
namespace usub::core
{
UDB::UDB(const std::string& db_name, const std::string& shm_name,
- size_t shm_queue_capacity, size_t max_memtable_size, bool create_new)
+ utils::DatabaseSettings settings, bool create_new)
: db_name_(db_name),
shm_name_(shm_name),
- shm_queue_capacity_(shm_queue_capacity),
- max_memtable_size_(max_memtable_size),
+ shm_queue_capacity_(settings.shm_queue_capacity),
+ max_memtable_size_(settings.max_memtable_size),
shm_manager_(shm_name, sizeof(SharedCommandQueue), create_new),
version_manager_(db_name),
- memtable_manager_(db_name + "_wal", max_memtable_size, this->version_manager_),
+ memtable_manager_(db_name + "_wal", settings.max_memtable_size, settings.estimated_element_size, this->version_manager_),
compactor_(this->version_manager_),
running_(true)
{
diff --git a/core/UDB.h b/core/UDB.h
index 8a85fab..ac5a3d7 100644
--- a/core/UDB.h
+++ b/core/UDB.h
@@ -25,14 +25,14 @@
#include "Memtable.h"
#include "utils/io/RecoveryLog.h"
#include "utils/io/Compactor.h"
+#include "utils/config/GlobalConfig.h"
namespace usub::core
{
class UDB
{
public:
- UDB(const std::string& db_name, const std::string& shm_name, size_t shm_queue_capacity = 1024,
- size_t max_memtable_size = 1024 * 1024, bool create_new = true);
+ UDB(const std::string& db_name, const std::string& shm_name, utils::DatabaseSettings settings, bool create_new = true);
~UDB();
@@ -65,4 +65,3 @@ namespace usub::core
}
#endif // UDB_H
-
diff --git a/utils/config/GlobalConfig.cpp b/utils/config/GlobalConfig.cpp
new file mode 100644
index 0000000..b86c492
--- /dev/null
+++ b/utils/config/GlobalConfig.cpp
@@ -0,0 +1,58 @@
+//
+// Created by Kirill Zhukov on 21.04.2025.
+//
+#include "GlobalConfig.h"
+#include
+#include "utils/toml/toml.hpp"
+
+namespace usub::utils
+{
+ std::unordered_map database_settings_map;
+
+ void load_global_config(toml::parse_result& path)
+ {
+ try
+ {
+ if (auto databases = path["databases"].as_table())
+ {
+ for (const auto& db : *databases)
+ {
+ const auto& db_name = db.first;
+ const auto& db_config = db.second;
+
+ if (!db_config.is_table())
+ continue;
+
+ DatabaseSettings settings;
+
+ const auto& table = *db_config.as_table();
+
+ if (auto val = table[toml::path("shm_queue_capacity")].value())
+ settings.shm_queue_capacity = *val;
+
+ if (auto val = table[toml::path("max_memtable_size")].value())
+ settings.max_memtable_size = *val;
+
+ if (auto val = table[toml::path("l0_queue_capacity")].value())
+ settings.l0_queue_capacity = *val;
+
+ if (auto val = table[toml::path("estimated_element_size")].value())
+ settings.estimated_element_size = *val;
+
+ database_settings_map.emplace(db_name.str(), settings);
+
+ std::cout << "[Config] Loaded for DB '" << db_name << "': "
+ << "shm_queue_capacity=" << settings.shm_queue_capacity
+ << ", max_memtable_size=" << settings.max_memtable_size
+ << ", l0_queue_capacity=" << settings.l0_queue_capacity
+ << ", estimated_element_size=" << settings.estimated_element_size
+ << "\n";
+ }
+ }
+ }
+ catch (const std::exception& ex)
+ {
+ std::cerr << "[Config] Failed to load config: " << ex.what() << "\n";
+ }
+ }
+}
diff --git a/utils/config/GlobalConfig.h b/utils/config/GlobalConfig.h
new file mode 100644
index 0000000..a49f43f
--- /dev/null
+++ b/utils/config/GlobalConfig.h
@@ -0,0 +1,29 @@
+//
+// Created by Kirill Zhukov on 21.04.2025.
+//
+
+#ifndef GLOBAL_CONFIG_H
+#define GLOBAL_CONFIG_H
+
+#include
+#include
+#include
+
+#include "utils/toml/toml.hpp"
+
+namespace usub::utils
+{
+ struct DatabaseSettings
+ {
+ size_t shm_queue_capacity = 1024;
+ size_t max_memtable_size = 1024 * 1024;
+ size_t l0_queue_capacity = 1024;
+ size_t estimated_element_size = 128;
+ };
+
+ extern std::unordered_map database_settings_map;
+
+ void load_global_config(toml::parse_result& path);
+}
+
+#endif //GLOBAL_CONFIG_H