From 630935826294f2f7aaa4760330dbdeca16003ccd Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Sun, 9 Aug 2026 20:20:36 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=F0=9F=9A=A7=20=E5=86=99=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E5=8D=8A=E4=BA=86memdb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memdb/include/memdb.hpp | 15 +++++++----- memdb/src/main/memdb.cpp | 52 ++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/memdb/include/memdb.hpp b/memdb/include/memdb.hpp index 8985a60..7b57367 100644 --- a/memdb/include/memdb.hpp +++ b/memdb/include/memdb.hpp @@ -35,16 +35,19 @@ private: std::list db; std::unordered_map keys; std::priority_queue time_touch; - size_t __size; + size_t __size = 0; + int MAX_TIME = 60 * 10; // 10分钟 void flush(); public: using key_t = T; using value_t = U; - static constexpr int npos = -1; + static constexpr bool fail = false; + static constexpr bool succ = true; Memdb(); + Memdb(int max_time); Memdb& operator=(const Memdb& to_be_cp_memdb); ~Memdb(); @@ -53,8 +56,8 @@ public: const std::list & get_db() const; const std::priority_queue & get_time_touch() const; - void insert(key_t to_be_ins_k, value_t ins_v); //TODO 要加返回值 - void remove(key_t to_be_del_k); //TODO 要加返回值 - void update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false);//TODO 要加返回值 - value_t search(key_t to_be_sch_k) const; + bool insert(key_t to_be_ins_k, value_t ins_v); + bool remove(key_t to_be_del_k); + bool update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false); + std::optional search(key_t to_be_sch_k); }; \ No newline at end of file diff --git a/memdb/src/main/memdb.cpp b/memdb/src/main/memdb.cpp index 9209ec6..d2e3e53 100644 --- a/memdb/src/main/memdb.cpp +++ b/memdb/src/main/memdb.cpp @@ -5,21 +5,27 @@ template bool Memdb ::index_timestamp::operator<(const index_timestamp& a) const { - return this -> item -> timestamp > a.item -> timestamp; + return this -> item -> timestamp < a.item -> timestamp; } template void Memdb ::flush() { + if (this -> time_touch.empty() == true) { + return; + } std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); std::list ::iterator it = this -> time_touch.front().item; while (now_time > it -> timestamp || it -> be_del == true) { - this -> keys.erase(it -> key); this -> db.erase(it); this -> time_touch.pop(); this -> __size--; + + if (this -> time_touch.empty() == true) { + return; + } it = this -> time_touch.front().item; now_time = std::chrono::system_clock::now(); } @@ -30,6 +36,11 @@ template Memdb ::Memdb() = default; +template + +Memdb ::Memdb(int max_time) : MAX_TIME(max_time) {} + + template Memdb & Memdb ::operator=(const Memdb & to_be_cp_memdb) = default; @@ -70,15 +81,18 @@ const std::priority_queue ::index_timestamp>& Memdb template -void Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { +bool Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { this -> flush(); + if (this -> keys.find(to_be_ins_k) != this -> keys.end()) { + return this -> fail; + } std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); Memdb::memdb_column new_column; new_column.key = to_be_ins_k; new_column.value = ins_v; - new_column.timestamp = now_time; + new_column.timestamp = now_time + std::chrono::seconds(MAX_TIME); this -> db.push_back(new_column); Memdb::index_keys new_key; @@ -89,38 +103,56 @@ void Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { Memdb::index_timestamp new_time_touch; new_time_touch.item = std::prev(this -> db.end()); this -> time_touch.push(new_time_touch); + + this -> __size++; + + return this -> succ; } template -void Memdb ::remove(key_t to_be_del_k) { +bool Memdb ::remove(key_t to_be_del_k) { this -> flush(); + if (this -> keys.find(to_be_del_k) == this -> keys.end()) { + return this -> fail; + } std::list ::iterator it = this -> keys[to_be_del_k].item; it -> be_del = true; + this -> keys.erase(it -> key); + + return this -> succ; } template -void Memdb ::update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false) { +bool Memdb ::update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch) { this -> flush(); + if (this -> keys.find(to_be_udt_k) == this -> keys.end()) { + return this -> fail; + } - std::list ::iterator it = this -> keys[to_be_udt_k]; //! 这边会默认插入 + std::list ::iterator it = this -> keys[to_be_udt_k].item; it -> value = udt_v; if (need_to_udt_timetouch == true) { std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - it -> timestamp = now_time; + it -> timestamp = now_time + std::chrono::seconds(MAX_TIME); //! 排序失效 } + + return this -> succ; } template -Memdb ::value_t Memdb ::search(key_t to_be_sch_k) const { +std::optional Memdb ::search(key_t to_be_sch_k){ this -> flush(); + if (this -> keys.find(to_be_sch_k) == this -> keys.end()) { + return std::nullopt; + } - std::list ::iterator it = this -> keys[to_be_sch_k]; //! 这边会默认插入 + std::list ::iterator it = this -> keys[to_be_sch_k].item; return it -> value; } From 4b7773daecf19772f4ff789621e7558f4a9af230 Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Mon, 10 Aug 2026 11:14:56 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=99=88=20=E6=B7=BB=E5=8A=A0memdb?= =?UTF-8?q?=E7=9A=84.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memdb/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 memdb/.gitignore diff --git a/memdb/.gitignore b/memdb/.gitignore new file mode 100644 index 0000000..ec6b25a --- /dev/null +++ b/memdb/.gitignore @@ -0,0 +1,3 @@ +*.bin +*.obj +build/ \ No newline at end of file From 8fe2afdfdec721dcef30195cf6cd074ec1bf8898 Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Mon, 10 Aug 2026 11:15:26 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=9A=A7=20=E8=83=BD=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E4=BA=86=EF=BC=8Cmakefile=E8=BF=98=E6=B2=A1=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memdb/Makefile | 0 memdb/include/memdb.hpp | 1 + memdb/src/main/memdb.cpp | 33 +++++++++++++++++++++++++-------- 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 memdb/Makefile diff --git a/memdb/Makefile b/memdb/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/memdb/include/memdb.hpp b/memdb/include/memdb.hpp index 7b57367..e5528cc 100644 --- a/memdb/include/memdb.hpp +++ b/memdb/include/memdb.hpp @@ -38,6 +38,7 @@ private: size_t __size = 0; int MAX_TIME = 60 * 10; // 10分钟 void flush(); + void update_queue(); public: diff --git a/memdb/src/main/memdb.cpp b/memdb/src/main/memdb.cpp index d2e3e53..2c0d3b6 100644 --- a/memdb/src/main/memdb.cpp +++ b/memdb/src/main/memdb.cpp @@ -16,21 +16,36 @@ void Memdb ::flush() { return; } std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - std::list ::iterator it = this -> time_touch.front().item; + typename std::list ::iterator it = this -> time_touch.top().item; while (now_time > it -> timestamp || it -> be_del == true) { + if (it -> be_del != true) this -> __size--; + key_t to_be_del_k = it -> key; this -> db.erase(it); + this -> keys.erase(to_be_del_k); this -> time_touch.pop(); - this -> __size--; if (this -> time_touch.empty() == true) { return; } - it = this -> time_touch.front().item; + it = this -> time_touch.top().item; now_time = std::chrono::system_clock::now(); } } + +template + +void Memdb ::update_queue() { + std::priority_queue new_time_touch; + while (this -> time_touch.empty() == false) { + new_time_touch.push(this -> time_touch.top()); + this -> time_touch.pop(); + } + this -> time_touch = new_time_touch; +} + + template Memdb ::Memdb() = default; @@ -98,7 +113,7 @@ bool Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { Memdb::index_keys new_key; new_key.key = to_be_ins_k; new_key.item = std::prev(this -> db.end()); - this -> keys.insert(new_key); + this -> keys[to_be_ins_k] = new_key; Memdb::index_timestamp new_time_touch; new_time_touch.item = std::prev(this -> db.end()); @@ -118,9 +133,10 @@ bool Memdb ::remove(key_t to_be_del_k) { return this -> fail; } - std::list ::iterator it = this -> keys[to_be_del_k].item; + typename std::list ::iterator it = this -> keys[to_be_del_k].item; it -> be_del = true; this -> keys.erase(it -> key); + this -> __size--; return this -> succ; } @@ -134,11 +150,12 @@ bool Memdb ::update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_tim return this -> fail; } - std::list ::iterator it = this -> keys[to_be_udt_k].item; + typename std::list ::iterator it = this -> keys[to_be_udt_k].item; it -> value = udt_v; if (need_to_udt_timetouch == true) { std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - it -> timestamp = now_time + std::chrono::seconds(MAX_TIME); //! 排序失效 + it -> timestamp = now_time + std::chrono::seconds(MAX_TIME); + this -> update_queue(); } return this -> succ; @@ -153,6 +170,6 @@ std::optional Memdb ::search(key_t to_be_sch_k){ return std::nullopt; } - std::list ::iterator it = this -> keys[to_be_sch_k].item; + typename std::list ::iterator it = this -> keys[to_be_sch_k].item; return it -> value; } From 4d6e1e1fd465901b3ab1f1b5928fb5039804a58b Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Wed, 12 Aug 2026 09:57:55 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=94=A8=20=E6=9B=B4=E6=96=B0=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E7=9B=B4=E6=8E=A5=E4=BD=BF=E7=94=A8=5Finst.sh?= =?UTF-8?q?=E7=9A=84=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _inst.sh | 41 +++++++++++++++++++++-------------------- db2/create_sqlite3.sql | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 db2/create_sqlite3.sql diff --git a/_inst.sh b/_inst.sh index f85d375..7486413 100755 --- a/_inst.sh +++ b/_inst.sh @@ -2,27 +2,27 @@ set -euo pipefail run_if_exists() { - local script="$1" - echo "---- run ${script} ----" + local script="$1" + echo "---- run ${script} ----" - if [ -f "$script" ]; then - bash "$script" - fi + if [ -f "$script" ]; then + bash "$script" + fi } inst_module() { - local module="$1" - echo "======== Install ${module} ========" + local module="$1" + echo "======== Install ${module} ========" - local set_file="./${module}/_set.sh" + local set_file="./${module}/_set.sh" - if [ -f "$set_file" ]; then - run_if_exists "$set_file" - return 0 - else - echo "Failed" >&2 - return 1 - fi + if [ -f "$set_file" ]; then + run_if_exists "$set_file" + return 0 + else + echo "Failed" >&2 + return 1 + fi } inst_module "libth" @@ -31,7 +31,7 @@ inst_module "libcrypt" inst_module "libsqlite3" inst_module "libmsg" inst_module "gateway" -inst_module "waf" # waf 在 gateway 之前编译,部署时由 core 先拉起 waf 再拉起 gateway +inst_module "waf" # waf 在 gateway 之前编译,部署时由 core 先拉起 waf 再拉起 gateway inst_module "static" inst_module "fsys" inst_module "dnfs" @@ -40,8 +40,9 @@ inst_module "db" inst_module "db2" inst_module "smtp" inst_module "captcha" +inst_module "captcha2" inst_module "confs" -inst_module "ai_review" # 需联网拉 chromadb onnx 模型(_fetch_onnx_model.sh 走 ModelScope 镜像) -inst_module "aibox" # 需 ~/.cert/deepseek.key(见 _setenv.sh) -inst_module "redirect80" # 80 端口重定向,依赖 ../pymsg -inst_module "core" # core last +inst_module "ai_review" # 需联网拉 chromadb onnx 模型(_fetch_onnx_model.sh 走 ModelScope 镜像) +inst_module "aibox" # 需 ~/.cert/deepseek.key(见 _setenv.sh) +inst_module "redirect80" # 80 端口重定向,依赖 ../pymsg +inst_module "core" # core last diff --git a/db2/create_sqlite3.sql b/db2/create_sqlite3.sql new file mode 100644 index 0000000..e43a1d3 --- /dev/null +++ b/db2/create_sqlite3.sql @@ -0,0 +1,39 @@ +-- Users 表创建脚本 +-- 数据库类型: SQLite + +CREATE TABLE IF NOT EXISTS Users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + create_at DATETIME DEFAULT CURRENT_TIMESTAMP, + last_login DATETIME, + is_active BOOLEAN DEFAULT 1 +); + +CREATE TABLE IF NOT EXISTS Notes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + pid INTEGER NOT NULL, + owner VARCHAR(128) DEFAULT 'Unknow', + title VARCHAR(128) NOT NULL, + content TEXT NOT NULL +); + +-- 旧版增量 +-- ALTER TABLE Notes ADD COLUMN owner VARCHAR(128) DEFAULT 'Unknow'; + +-- ── 日志表(db 内置日志模块)───────────────────────────────────────── + +CREATE TABLE IF NOT EXISTS Logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + ts TEXT NOT NULL, + service TEXT NOT NULL, + level TEXT NOT NULL, + message TEXT NOT NULL, + trace_id TEXT, + extra TEXT +); + +CREATE INDEX IF NOT EXISTS idx_logs_service_ts ON Logs(service, ts); +CREATE INDEX IF NOT EXISTS idx_logs_level_ts ON Logs(level, ts); +CREATE INDEX IF NOT EXISTS idx_logs_ts ON Logs(ts); +CREATE INDEX IF NOT EXISTS idx_logs_trace ON Logs(trace_id); From 82875b3021f4178c0c0595779e13479e311697d7 Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Wed, 12 Aug 2026 11:10:19 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E2=9C=85=20=E5=86=85=E6=B5=8B=E7=89=88?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memdb/Makefile | 2 + memdb/include/memdb.hpp | 13 ++++ memdb/src/main.cpp | 13 ++++ memdb/src/main/memdb.cpp | 125 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 149 insertions(+), 4 deletions(-) diff --git a/memdb/Makefile b/memdb/Makefile index e69de29..141e76d 100644 --- a/memdb/Makefile +++ b/memdb/Makefile @@ -0,0 +1,2 @@ +test: src/main.cpp src/main/memdb.cpp include/memdb.hpp + g++ src/main.cpp -o test.bin -I include/ -std=c++20 -O3 -g \ No newline at end of file diff --git a/memdb/include/memdb.hpp b/memdb/include/memdb.hpp index e5528cc..6fc4964 100644 --- a/memdb/include/memdb.hpp +++ b/memdb/include/memdb.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include @@ -35,11 +37,15 @@ private: std::list db; std::unordered_map keys; std::priority_queue time_touch; + std::multiset time_touch_; size_t __size = 0; int MAX_TIME = 60 * 10; // 10分钟 void flush(); void update_queue(); + // 内测版 + void flush_(); + public: using key_t = T; @@ -61,4 +67,11 @@ public: bool remove(key_t to_be_del_k); bool update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false); std::optional search(key_t to_be_sch_k); + + // 内测版 + const std::multiset & get_time_touch_() const; + bool insert_(key_t to_be_ins_k, value_t ins_v); + bool remove_(key_t to_be_del_k); + bool update_(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false); + std::optional search_(key_t to_be_sch_k); }; \ No newline at end of file diff --git a/memdb/src/main.cpp b/memdb/src/main.cpp index e69de29..23e8a44 100644 --- a/memdb/src/main.cpp +++ b/memdb/src/main.cpp @@ -0,0 +1,13 @@ +#include +#include "main/memdb.cpp" +using namespace std; +Memdb testdb(10); +int main(){ + testdb.insert_("key1","value1"); + auto pack=testdb.search_("key1"); + cout<<(pack==nullopt?"未找到":pack.value())< bool Memdb ::index_timestamp::operator<(const index_timestamp& a) const { - return this -> item -> timestamp < a.item -> timestamp; + return this -> item -> timestamp > a.item -> timestamp; } @@ -20,10 +20,9 @@ void Memdb ::flush() { while (now_time > it -> timestamp || it -> be_del == true) { if (it -> be_del != true) this -> __size--; - key_t to_be_del_k = it -> key; - this -> db.erase(it); - this -> keys.erase(to_be_del_k); + this -> keys.erase(it -> key); this -> time_touch.pop(); + this -> db.erase(it); if (this -> time_touch.empty() == true) { return; @@ -94,6 +93,7 @@ const std::priority_queue ::index_timestamp>& Memdb } + template bool Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { @@ -173,3 +173,120 @@ std::optional Memdb ::search(key_t to_be_sch_k){ typename std::list ::iterator it = this -> keys[to_be_sch_k].item; return it -> value; } + + +/* +内测版 +*/ + + +template + +void Memdb ::flush_() { + if (this -> time_touch_.empty() == true) { + return; + } + std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); + typename std::list ::iterator it = this -> time_touch_.begin() -> item; + + while (now_time > it -> timestamp || it -> be_del == true) { + if (it -> be_del != true) this -> __size--; + key_t to_be_del_k = it -> key; + this -> db.erase(it); + this -> keys.erase(to_be_del_k); + this -> time_touch_.erase(this -> time_touch_.begin()); + + if (this -> time_touch_.empty() == true) { + return; + } + it = this -> time_touch_.begin() -> item; + now_time = std::chrono::system_clock::now(); + } +} + + +template + +const std::multiset ::index_timestamp>& Memdb ::get_time_touch_() const { + return this -> time_touch_; +} + + +template + +bool Memdb ::insert_(key_t to_be_ins_k, value_t ins_v) { + this -> flush_(); + if (this -> keys.find(to_be_ins_k) != this -> keys.end()) { + return this -> fail; + } + + std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); + + Memdb::memdb_column new_column; + new_column.key = to_be_ins_k; + new_column.value = ins_v; + new_column.timestamp = now_time + std::chrono::seconds(MAX_TIME); + this -> db.push_back(new_column); + + Memdb::index_keys new_key; + new_key.key = to_be_ins_k; + new_key.item = std::prev(this -> db.end()); + this -> keys[to_be_ins_k] = new_key; + + Memdb::index_timestamp new_time_touch; + new_time_touch.item = std::prev(this -> db.end()); + this -> time_touch_.insert(new_time_touch); + + this -> __size++; + + return this -> succ; +} + + +template + +bool Memdb ::remove_(key_t to_be_del_k) { + this -> flush_(); + if (this -> keys.find(to_be_del_k) == this -> keys.end()) { + return this -> fail; + } + + typename std::list ::iterator it = this -> keys[to_be_del_k].item; + it -> be_del = true; + this -> keys.erase(it -> key); + this -> __size--; + + return this -> succ; +} + + +template + +bool Memdb ::update_(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch) { + this -> flush_(); + if (this -> keys.find(to_be_udt_k) == this -> keys.end()) { + return this -> fail; + } + + typename std::list ::iterator it = this -> keys[to_be_udt_k].item; + it -> value = udt_v; + if (need_to_udt_timetouch == true) { + std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); + it -> timestamp = now_time + std::chrono::seconds(MAX_TIME); + } + + return this -> succ; +} + + +template + +std::optional Memdb ::search_(key_t to_be_sch_k){ + this -> flush_(); + if (this -> keys.find(to_be_sch_k) == this -> keys.end()) { + return std::nullopt; + } + + typename std::list ::iterator it = this -> keys[to_be_sch_k].item; + return it -> value; +} \ No newline at end of file From 02d95a2bd984e4d0d4c5c9bd2e0525e5728c8911 Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Wed, 12 Aug 2026 20:11:07 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20=E5=B0=86queue?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E4=B8=BAset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memdb/include/memdb.hpp | 25 ++--- memdb/src/main/memdb.cpp | 203 +++++++++------------------------------ 2 files changed, 51 insertions(+), 177 deletions(-) diff --git a/memdb/include/memdb.hpp b/memdb/include/memdb.hpp index 6fc4964..26c6ed0 100644 --- a/memdb/include/memdb.hpp +++ b/memdb/include/memdb.hpp @@ -1,14 +1,15 @@ #pragma once -#include #include #include #include -#include #include #include +#include +namespace shufeng2012 { + template class Memdb { @@ -18,7 +19,6 @@ struct memdb_column { T key; U value; std::chrono::system_clock::time_point timestamp; - bool be_del = false; }; struct index_keys { @@ -36,15 +36,10 @@ struct index_timestamp { private: std::list db; std::unordered_map keys; - std::priority_queue time_touch; - std::multiset time_touch_; + std::multiset time_touch; size_t __size = 0; int MAX_TIME = 60 * 10; // 10分钟 void flush(); - void update_queue(); - - // 内测版 - void flush_(); public: @@ -61,17 +56,11 @@ public: size_t size() const; const std::unordered_map & get_keys() const; const std::list & get_db() const; - const std::priority_queue & get_time_touch() const; + const std::multiset ::index_timestamp>& get_time_touch() const; bool insert(key_t to_be_ins_k, value_t ins_v); bool remove(key_t to_be_del_k); bool update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false); std::optional search(key_t to_be_sch_k); - - // 内测版 - const std::multiset & get_time_touch_() const; - bool insert_(key_t to_be_ins_k, value_t ins_v); - bool remove_(key_t to_be_del_k); - bool update_(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false); - std::optional search_(key_t to_be_sch_k); -}; \ No newline at end of file +}; +} \ No newline at end of file diff --git a/memdb/src/main/memdb.cpp b/memdb/src/main/memdb.cpp index bdc7490..3ba1e09 100644 --- a/memdb/src/main/memdb.cpp +++ b/memdb/src/main/memdb.cpp @@ -2,46 +2,11 @@ +namespace shufeng2012 { template bool Memdb ::index_timestamp::operator<(const index_timestamp& a) const { - return this -> item -> timestamp > a.item -> timestamp; -} - - -template - -void Memdb ::flush() { - if (this -> time_touch.empty() == true) { - return; - } - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - typename std::list ::iterator it = this -> time_touch.top().item; - - while (now_time > it -> timestamp || it -> be_del == true) { - if (it -> be_del != true) this -> __size--; - this -> keys.erase(it -> key); - this -> time_touch.pop(); - this -> db.erase(it); - - if (this -> time_touch.empty() == true) { - return; - } - it = this -> time_touch.top().item; - now_time = std::chrono::system_clock::now(); - } -} - - -template - -void Memdb ::update_queue() { - std::priority_queue new_time_touch; - while (this -> time_touch.empty() == false) { - new_time_touch.push(this -> time_touch.top()); - this -> time_touch.pop(); - } - this -> time_touch = new_time_touch; + return this -> item -> timestamp < a.item -> timestamp; } @@ -52,7 +17,7 @@ Memdb ::Memdb() = default; template -Memdb ::Memdb(int max_time) : MAX_TIME(max_time) {} +Memdb ::Memdb(int max_time) : MAX_TIME(std::max(0, max_time)) {} template @@ -86,13 +51,42 @@ const std::list ::memdb_column>& Memdb ::get_db() co } +/* +内测版 +*/ + + template -const std::priority_queue ::index_timestamp>& Memdb ::get_time_touch() const { - return this -> time_touch; +void Memdb ::flush() { + if (this -> time_touch.empty() == true) { + return; + } + std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); + typename std::list ::iterator it = this -> time_touch.begin() -> item; + + while (now_time >= it -> timestamp) { + this -> __size--; + key_t to_be_del_k = it -> key; + this -> db.erase(it); + this -> keys.erase(to_be_del_k); + this -> time_touch.erase(this -> time_touch.begin()); + + if (this -> time_touch.empty() == true) { + return; + } + it = this -> time_touch.begin() -> item; + now_time = std::chrono::system_clock::now(); + } } +template + +const std::multiset ::index_timestamp>& Memdb ::get_time_touch() const { + return this -> time_touch; +} + template @@ -117,7 +111,7 @@ bool Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { Memdb::index_timestamp new_time_touch; new_time_touch.item = std::prev(this -> db.end()); - this -> time_touch.push(new_time_touch); + this -> time_touch.insert(new_time_touch); this -> __size++; @@ -128,14 +122,17 @@ bool Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { template bool Memdb ::remove(key_t to_be_del_k) { + //! 直接删除,不要lazy this -> flush(); if (this -> keys.find(to_be_del_k) == this -> keys.end()) { return this -> fail; } typename std::list ::iterator it = this -> keys[to_be_del_k].item; - it -> be_del = true; + // it -> be_del = true; this -> keys.erase(it -> key); + this -> time_touch.erase({it}); + this -> db.erase(it); this -> __size--; return this -> succ; @@ -145,6 +142,7 @@ bool Memdb ::remove(key_t to_be_del_k) { template bool Memdb ::update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch) { + //! 先删再加 this -> flush(); if (this -> keys.find(to_be_udt_k) == this -> keys.end()) { return this -> fail; @@ -154,8 +152,10 @@ bool Memdb ::update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_tim it -> value = udt_v; if (need_to_udt_timetouch == true) { std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - it -> timestamp = now_time + std::chrono::seconds(MAX_TIME); - this -> update_queue(); + T copy_k = it -> key; + U copy_v = it -> value; + this -> remove(copy_k); + this -> insert(copy_k, copy_v); } return this -> succ; @@ -174,119 +174,4 @@ std::optional Memdb ::search(key_t to_be_sch_k){ return it -> value; } - -/* -内测版 -*/ - - -template - -void Memdb ::flush_() { - if (this -> time_touch_.empty() == true) { - return; - } - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - typename std::list ::iterator it = this -> time_touch_.begin() -> item; - - while (now_time > it -> timestamp || it -> be_del == true) { - if (it -> be_del != true) this -> __size--; - key_t to_be_del_k = it -> key; - this -> db.erase(it); - this -> keys.erase(to_be_del_k); - this -> time_touch_.erase(this -> time_touch_.begin()); - - if (this -> time_touch_.empty() == true) { - return; - } - it = this -> time_touch_.begin() -> item; - now_time = std::chrono::system_clock::now(); - } -} - - -template - -const std::multiset ::index_timestamp>& Memdb ::get_time_touch_() const { - return this -> time_touch_; -} - - -template - -bool Memdb ::insert_(key_t to_be_ins_k, value_t ins_v) { - this -> flush_(); - if (this -> keys.find(to_be_ins_k) != this -> keys.end()) { - return this -> fail; - } - - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - - Memdb::memdb_column new_column; - new_column.key = to_be_ins_k; - new_column.value = ins_v; - new_column.timestamp = now_time + std::chrono::seconds(MAX_TIME); - this -> db.push_back(new_column); - - Memdb::index_keys new_key; - new_key.key = to_be_ins_k; - new_key.item = std::prev(this -> db.end()); - this -> keys[to_be_ins_k] = new_key; - - Memdb::index_timestamp new_time_touch; - new_time_touch.item = std::prev(this -> db.end()); - this -> time_touch_.insert(new_time_touch); - - this -> __size++; - - return this -> succ; -} - - -template - -bool Memdb ::remove_(key_t to_be_del_k) { - this -> flush_(); - if (this -> keys.find(to_be_del_k) == this -> keys.end()) { - return this -> fail; - } - - typename std::list ::iterator it = this -> keys[to_be_del_k].item; - it -> be_del = true; - this -> keys.erase(it -> key); - this -> __size--; - - return this -> succ; -} - - -template - -bool Memdb ::update_(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch) { - this -> flush_(); - if (this -> keys.find(to_be_udt_k) == this -> keys.end()) { - return this -> fail; - } - - typename std::list ::iterator it = this -> keys[to_be_udt_k].item; - it -> value = udt_v; - if (need_to_udt_timetouch == true) { - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - it -> timestamp = now_time + std::chrono::seconds(MAX_TIME); - } - - return this -> succ; -} - - -template - -std::optional Memdb ::search_(key_t to_be_sch_k){ - this -> flush_(); - if (this -> keys.find(to_be_sch_k) == this -> keys.end()) { - return std::nullopt; - } - - typename std::list ::iterator it = this -> keys[to_be_sch_k].item; - return it -> value; } \ No newline at end of file From f606f7ec56f422e678627260e19c6e6473daae9f Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Wed, 12 Aug 2026 20:11:33 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E2=9C=85=20=E9=80=9A=E8=BF=87=E9=BB=91?= =?UTF-8?q?=E7=9B=92=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memdb/Makefile | 4 +- memdb/src/blackbox_test.cpp | 291 ++++++++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 memdb/src/blackbox_test.cpp diff --git a/memdb/Makefile b/memdb/Makefile index 141e76d..f51dc0b 100644 --- a/memdb/Makefile +++ b/memdb/Makefile @@ -1,2 +1,2 @@ -test: src/main.cpp src/main/memdb.cpp include/memdb.hpp - g++ src/main.cpp -o test.bin -I include/ -std=c++20 -O3 -g \ No newline at end of file +test: src/blackbox_test.cpp src/main/memdb.cpp include/memdb.hpp + g++ src/blackbox_test.cpp -o test.bin -I include/ -std=c++20 -O3 -g \ No newline at end of file diff --git a/memdb/src/blackbox_test.cpp b/memdb/src/blackbox_test.cpp new file mode 100644 index 0000000..8a98e7e --- /dev/null +++ b/memdb/src/blackbox_test.cpp @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// 使用 C++20 的时间字面量 +using namespace std::chrono_literals; +using namespace shufeng2012; + +#include "main/memdb.cpp" + +// ----- 简易测试框架 ----- +static int g_test_passed = 0; +static int g_test_failed = 0; + +#define TEST(name) \ + void test_##name(); \ + struct TestReg_##name { \ + TestReg_##name() { register_test(#name, test_##name); } \ + } reg_##name; \ + void test_##name() + +using TestFunc = std::function; +std::vector> tests; + +void register_test(const std::string& name, TestFunc fn) { + tests.push_back({name, fn}); +} + +// 断言宏(支持 C++20 的 constexpr 字符串,但这里不变) +#define EXPECT_TRUE(expr) \ + do { if (!(expr)) { std::cerr << " [FAIL] " #expr << " is false\n"; ++g_test_failed; return; } } while(0) + +#define EXPECT_FALSE(expr) EXPECT_TRUE(!(expr)) + +#define EXPECT_EQ(expected, actual) \ + do { if ((expected) != (actual)) { std::cerr << " [FAIL] Expected: " << (expected) << ", Actual: " << (actual) << "\n"; ++g_test_failed; return; } } while(0) + +#define EXPECT_OPTIONAL_EQ(expected, opt) \ + do { \ + if (!(opt).has_value()) { std::cerr << " [FAIL] optional has no value\n"; ++g_test_failed; return; } \ + if ((expected) != (opt).value()) { std::cerr << " [FAIL] Expected: " << (expected) << ", Actual: " << (opt).value() << "\n"; ++g_test_failed; return; } \ + } while(0) + +#define EXPECT_NO_VALUE(opt) \ + do { if ((opt).has_value()) { std::cerr << " [FAIL] optional should have no value, but has: " << (opt).value() << "\n"; ++g_test_failed; return; } } while(0) + +// ----- 测试用例 ----- + +// 1. 默认构造 +TEST(DefaultConstruction) { + Memdb db; + EXPECT_EQ(0u, db.size()); + EXPECT_TRUE(db.get_db().empty()); + EXPECT_TRUE(db.get_keys().empty()); + EXPECT_TRUE(db.get_time_touch().empty()); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 2. 插入与查询 +TEST(InsertAndSearch) { + Memdb db(10); + EXPECT_TRUE(db.insert(1, "one")); + EXPECT_EQ(1u, db.size()); + auto opt = db.search(1); + EXPECT_OPTIONAL_EQ("one", opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 3. 重复插入失败 +TEST(InsertDuplicateFails) { + Memdb db; + EXPECT_TRUE(db.insert(1, "one")); + EXPECT_FALSE(db.insert(1, "another")); + EXPECT_EQ(1u, db.size()); + auto opt = db.search(1); + EXPECT_OPTIONAL_EQ("one", opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 4. 查询不存在的键 +TEST(SearchNonExistent) { + Memdb db; + auto opt = db.search(42); + EXPECT_NO_VALUE(opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 5. 删除存在的键 +TEST(RemoveExisting) { + Memdb db; + db.insert(1, "one"); + EXPECT_TRUE(db.remove(1)); + EXPECT_EQ(0u, db.size()); + auto opt = db.search(1); + EXPECT_NO_VALUE(opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 6. 删除不存在的键 +TEST(RemoveNonExistentFails) { + Memdb db; + EXPECT_FALSE(db.remove(99)); + EXPECT_EQ(0u, db.size()); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 7. 删除后重新插入 +TEST(RemoveThenReinsert) { + Memdb db; + db.insert(1, "one"); + db.remove(1); + EXPECT_TRUE(db.insert(1, "new")); + EXPECT_EQ(1u, db.size()); + auto opt = db.search(1); + EXPECT_OPTIONAL_EQ("new", opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 8. 更新(不触摸) +TEST(UpdateWithoutTouch) { + Memdb db(10); + db.insert(1, "one"); + EXPECT_TRUE(db.update(1, "updated", false)); + EXPECT_EQ(1u, db.size()); + auto opt = db.search(1); + EXPECT_OPTIONAL_EQ("updated", opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 9. 更新(触摸)延长寿命 —— 使用 C++20 字面量 +TEST(UpdateWithTouchExtendsLifetime) { + const int TTL = 3; + Memdb db(TTL); + db.insert(1, "one"); + + // 等待 1.5 秒(剩余寿命约 1.5 秒) + std::this_thread::sleep_for(1500ms); + + // 触摸更新,重置寿命为从当前起 TTL 秒 + EXPECT_TRUE(db.update(1, "touched", true)); + + // 再等待 2.5 秒(从触摸起 2.5 < TTL,应存活) + std::this_thread::sleep_for(2500ms); + + db.search(999); // 触发 flush + auto opt = db.search(1); + EXPECT_TRUE(opt.has_value()); + EXPECT_OPTIONAL_EQ("touched", opt); + EXPECT_EQ(1u, db.size()); + + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 10. 更新不存在的键 +TEST(UpdateNonExistentFails) { + Memdb db; + EXPECT_FALSE(db.update(2, "nope")); + EXPECT_EQ(0u, db.size()); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 11. 过期后自动清除 +TEST(ExpirationAfterTimeout) { + const int TTL = 2; + Memdb db(TTL); + db.insert(1, "expire"); + + // 等待 TTL + 1 秒(保证超过) + std::this_thread::sleep_for(std::chrono::seconds(TTL + 1)); + + db.search(999); // 触发 flush + EXPECT_EQ(0u, db.size()); + EXPECT_NO_VALUE(db.search(1)); + + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 12. 未过期前可查询 +TEST(NotExpiredBeforeTimeout) { + const int TTL = 2; + Memdb db(TTL); + db.insert(1, "alive"); + std::this_thread::sleep_for(1s); + EXPECT_EQ(1u, db.size()); + auto opt = db.search(1); + EXPECT_OPTIONAL_EQ("alive", opt); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 13. 更新不触摸不延长寿命 +TEST(UpdateWithoutTouchDoesNotExtend) { + const int TTL = 3; + Memdb db(TTL); + db.insert(1, "one"); + + // 等待 1.5 秒(剩余 1.5 秒) + std::this_thread::sleep_for(1500ms); + + // 更新但不触摸,过期时间不变 + EXPECT_TRUE(db.update(1, "updated", false)); + + // 再等待 2 秒(总休眠 3.5 > TTL,应过期) + std::this_thread::sleep_for(2000ms); + + db.search(999); + EXPECT_EQ(0u, db.size()); + EXPECT_NO_VALUE(db.search(1)); + + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 14. 生存时间为 0,立即过期 +TEST(ZeroLifetimeExpiresImmediately) { + Memdb db(0); + db.insert(1, "zero"); + std::this_thread::sleep_for(10ms); + db.search(999); + EXPECT_EQ(0u, db.size()); + EXPECT_NO_VALUE(db.search(1)); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 15. 混合操作一致性 +TEST(MixedInsertDeleteSize) { + Memdb db; + db.insert(1, "a"); + db.insert(2, "b"); + db.insert(3, "c"); + db.remove(2); + db.insert(4, "d"); + EXPECT_EQ(3u, db.size()); + EXPECT_TRUE(db.search(1).has_value()); + EXPECT_FALSE(db.search(2).has_value()); + EXPECT_TRUE(db.search(3).has_value()); + EXPECT_TRUE(db.search(4).has_value()); + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// 16. 批量过期 +TEST(BulkExpirationClearsSize) { + const int TTL = 1; + Memdb db(TTL); + for (int i = 0; i < 100; ++i) { + db.insert(i, std::to_string(i)); + } + EXPECT_EQ(100u, db.size()); + std::this_thread::sleep_for(std::chrono::seconds(TTL + 1)); + db.search(-1); + EXPECT_EQ(0u, db.size()); + for (int i = 0; i < 100; ++i) { + EXPECT_FALSE(db.search(i).has_value()); + } + std::cout << " [PASS]\n"; + ++g_test_passed; +} + +// ----- 程序入口 ----- +int main() { + std::cout << "Memdb Black-box Tests (C++20, no external libs)\n"; + std::cout << "================================================\n"; + + for (auto& [name, fn] : tests) { + std::cout << "Test: " << name << "\n"; + fn(); + } + + std::cout << "================================================\n"; + std::cout << "Passed: " << g_test_passed << ", Failed: " << g_test_failed << "\n"; + + return g_test_failed > 0 ? 1 : 0; +} \ No newline at end of file From 96d9f96e6d4d6c7e7f33c1f58e079d63da3d603d Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Wed, 12 Aug 2026 20:40:48 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=F0=9F=8E=A8=20=E6=9B=B4=E6=94=B9=E4=B8=BAl?= =?UTF-8?q?ibmemdb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libmemdb/.gitignore | 69 +++++++++ libmemdb/Makefile | 25 ++++ libmemdb/README.md | 5 + libmemdb/_set.sh | 3 + libmemdb/inc/us/memdb.hpp | 156 +++++++++++++++++++ memdb/.gitignore | 3 - memdb/Makefile | 2 - memdb/include/memdb.hpp | 66 -------- memdb/src/blackbox_test.cpp | 291 ------------------------------------ memdb/src/main.cpp | 13 -- memdb/src/main/memdb.cpp | 177 ---------------------- 11 files changed, 258 insertions(+), 552 deletions(-) create mode 100644 libmemdb/.gitignore create mode 100644 libmemdb/Makefile create mode 100644 libmemdb/README.md create mode 100644 libmemdb/_set.sh create mode 100644 libmemdb/inc/us/memdb.hpp delete mode 100644 memdb/.gitignore delete mode 100644 memdb/Makefile delete mode 100644 memdb/include/memdb.hpp delete mode 100644 memdb/src/blackbox_test.cpp delete mode 100644 memdb/src/main.cpp delete mode 100644 memdb/src/main/memdb.cpp diff --git a/libmemdb/.gitignore b/libmemdb/.gitignore new file mode 100644 index 0000000..f152158 --- /dev/null +++ b/libmemdb/.gitignore @@ -0,0 +1,69 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Linker files +*.ilk + +# Debugger Files +*.pdb + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll +*.so.* + + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Build directories +build/ +Build/ +build-*/ + +# CMake generated files +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +#Makefile +install_manifest.txt +compile_commands.json + +# Temporary files +*.tmp +*.log +*.bak +*.swp + +# vcpkg +vcpkg_installed/ + +# debug information files +*.dwo + +# test output & cache +Testing/ +.cache/ diff --git a/libmemdb/Makefile b/libmemdb/Makefile new file mode 100644 index 0000000..43ecf59 --- /dev/null +++ b/libmemdb/Makefile @@ -0,0 +1,25 @@ +VERSION := 1.0.0 +FRAMEWORK_NAME := us +LIB_NAME := libus_memdb +INSTL_TDIR := /lib +INCLU_TDIR := /usr/include +INCLU_SDIR := inc +CPP := g++ +INCS := -I inc +CPPFLAGS := --std=c++20 -O3 -pipe -Wall -Werror +LIBS := +BUILD_TDIR := build +$(shell mkdir -p $(BUILD_TDIR)) + + + +install: + @echo "install UniServe_libmemdb..." + @mkdir -vp $(INCLU_TDIR)/${FRAMEWORK_NAME} + @cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/memdb.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/ + @echo "done." + +uninstall: + @echo "uninstall UniServe_libmemdb..." + @rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/memdb.hpp + @echo "done." \ No newline at end of file diff --git a/libmemdb/README.md b/libmemdb/README.md new file mode 100644 index 0000000..f6805f9 --- /dev/null +++ b/libmemdb/README.md @@ -0,0 +1,5 @@ +# UniServe_libmemdb +UniServe Framework memdb Library + +# Dependancy +libmemdb-dev diff --git a/libmemdb/_set.sh b/libmemdb/_set.sh new file mode 100644 index 0000000..d3c371b --- /dev/null +++ b/libmemdb/_set.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +make install \ No newline at end of file diff --git a/libmemdb/inc/us/memdb.hpp b/libmemdb/inc/us/memdb.hpp new file mode 100644 index 0000000..cc8b48a --- /dev/null +++ b/libmemdb/inc/us/memdb.hpp @@ -0,0 +1,156 @@ +#pragma once +#include +#include +#include +#include +#include +#include + + + +namespace shufeng2012 { + + + +template + +class Memdb { + + +struct memdb_column { + T key; + U value; + std::chrono::system_clock::time_point timestamp; +}; + +struct index_keys { + T key; + std::list ::iterator item; +}; + +struct index_timestamp { + std::list ::iterator item; + + bool operator<(const index_timestamp& a) const { + return this -> item -> timestamp < a.item -> timestamp; + } +}; + + +private: + std::list db; + std::unordered_map keys; + std::multiset time_touch; + size_t __size = 0; + int MAX_TIME = 60 * 10; // 10分钟 + void flush(); + + + +public: + using key_t = T; + using value_t = U; + static constexpr bool fail = false; + static constexpr bool succ = true; + + + + Memdb() = default; + Memdb(int max_time) : MAX_TIME(std::max(0, max_time)) {} + Memdb& operator=(const Memdb& to_be_cp_memdb) = default; + ~Memdb() = default; + + + size_t size() const { + return this -> __size; + } + + const std::unordered_map & get_keys() const { + return this -> keys; + } + + const std::list & get_db() const { + return this -> db; + } + + const std::multiset ::index_timestamp>& get_time_touch() const { + return this -> time_touch; + } + + + bool insert(key_t to_be_ins_k, value_t ins_v) { + this -> flush(); + if (this -> keys.find(to_be_ins_k) != this -> keys.end()) { + return this -> fail; + } + + std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); + + Memdb::memdb_column new_column; + new_column.key = to_be_ins_k; + new_column.value = ins_v; + new_column.timestamp = now_time + std::chrono::seconds(MAX_TIME); + this -> db.push_back(new_column); + + Memdb::index_keys new_key; + new_key.key = to_be_ins_k; + new_key.item = std::prev(this -> db.end()); + this -> keys[to_be_ins_k] = new_key; + + Memdb::index_timestamp new_time_touch; + new_time_touch.item = std::prev(this -> db.end()); + this -> time_touch.insert(new_time_touch); + + this -> __size++; + + return this -> succ; + } + + bool remove(key_t to_be_del_k) { + this -> flush(); + if (this -> keys.find(to_be_del_k) == this -> keys.end()) { + return this -> fail; + } + + typename std::list ::iterator it = this -> keys[to_be_del_k].item; + this -> keys.erase(it -> key); + this -> time_touch.erase({it}); + this -> db.erase(it); + this -> __size--; + + return this -> succ; + } + + bool update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false) { + this -> flush(); + if (this -> keys.find(to_be_udt_k) == this -> keys.end()) { + return this -> fail; + } + + typename std::list ::iterator it = this -> keys[to_be_udt_k].item; + it -> value = udt_v; + if (need_to_udt_timetouch == true) { + std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); + T copy_k = it -> key; + U copy_v = it -> value; + this -> remove(copy_k); + this -> insert(copy_k, copy_v); + } + + return this -> succ; + } + + std::optional search(key_t to_be_sch_k) { + this -> flush(); + if (this -> keys.find(to_be_sch_k) == this -> keys.end()) { + return std::nullopt; + } + + typename std::list ::iterator it = this -> keys[to_be_sch_k].item; + return it -> value; + } +}; + + + +} \ No newline at end of file diff --git a/memdb/.gitignore b/memdb/.gitignore deleted file mode 100644 index ec6b25a..0000000 --- a/memdb/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.bin -*.obj -build/ \ No newline at end of file diff --git a/memdb/Makefile b/memdb/Makefile deleted file mode 100644 index f51dc0b..0000000 --- a/memdb/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: src/blackbox_test.cpp src/main/memdb.cpp include/memdb.hpp - g++ src/blackbox_test.cpp -o test.bin -I include/ -std=c++20 -O3 -g \ No newline at end of file diff --git a/memdb/include/memdb.hpp b/memdb/include/memdb.hpp deleted file mode 100644 index 26c6ed0..0000000 --- a/memdb/include/memdb.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - - - -namespace shufeng2012 { - -template - -class Memdb { - - -struct memdb_column { - T key; - U value; - std::chrono::system_clock::time_point timestamp; -}; - -struct index_keys { - T key; - std::list ::iterator item; -}; - -struct index_timestamp { - std::list ::iterator item; - - bool operator<(const index_timestamp& a) const; -}; - - -private: - std::list db; - std::unordered_map keys; - std::multiset time_touch; - size_t __size = 0; - int MAX_TIME = 60 * 10; // 10分钟 - void flush(); - - -public: - using key_t = T; - using value_t = U; - static constexpr bool fail = false; - static constexpr bool succ = true; - - Memdb(); - Memdb(int max_time); - Memdb& operator=(const Memdb& to_be_cp_memdb); - ~Memdb(); - - size_t size() const; - const std::unordered_map & get_keys() const; - const std::list & get_db() const; - const std::multiset ::index_timestamp>& get_time_touch() const; - - bool insert(key_t to_be_ins_k, value_t ins_v); - bool remove(key_t to_be_del_k); - bool update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch=false); - std::optional search(key_t to_be_sch_k); -}; -} \ No newline at end of file diff --git a/memdb/src/blackbox_test.cpp b/memdb/src/blackbox_test.cpp deleted file mode 100644 index 8a98e7e..0000000 --- a/memdb/src/blackbox_test.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -// 使用 C++20 的时间字面量 -using namespace std::chrono_literals; -using namespace shufeng2012; - -#include "main/memdb.cpp" - -// ----- 简易测试框架 ----- -static int g_test_passed = 0; -static int g_test_failed = 0; - -#define TEST(name) \ - void test_##name(); \ - struct TestReg_##name { \ - TestReg_##name() { register_test(#name, test_##name); } \ - } reg_##name; \ - void test_##name() - -using TestFunc = std::function; -std::vector> tests; - -void register_test(const std::string& name, TestFunc fn) { - tests.push_back({name, fn}); -} - -// 断言宏(支持 C++20 的 constexpr 字符串,但这里不变) -#define EXPECT_TRUE(expr) \ - do { if (!(expr)) { std::cerr << " [FAIL] " #expr << " is false\n"; ++g_test_failed; return; } } while(0) - -#define EXPECT_FALSE(expr) EXPECT_TRUE(!(expr)) - -#define EXPECT_EQ(expected, actual) \ - do { if ((expected) != (actual)) { std::cerr << " [FAIL] Expected: " << (expected) << ", Actual: " << (actual) << "\n"; ++g_test_failed; return; } } while(0) - -#define EXPECT_OPTIONAL_EQ(expected, opt) \ - do { \ - if (!(opt).has_value()) { std::cerr << " [FAIL] optional has no value\n"; ++g_test_failed; return; } \ - if ((expected) != (opt).value()) { std::cerr << " [FAIL] Expected: " << (expected) << ", Actual: " << (opt).value() << "\n"; ++g_test_failed; return; } \ - } while(0) - -#define EXPECT_NO_VALUE(opt) \ - do { if ((opt).has_value()) { std::cerr << " [FAIL] optional should have no value, but has: " << (opt).value() << "\n"; ++g_test_failed; return; } } while(0) - -// ----- 测试用例 ----- - -// 1. 默认构造 -TEST(DefaultConstruction) { - Memdb db; - EXPECT_EQ(0u, db.size()); - EXPECT_TRUE(db.get_db().empty()); - EXPECT_TRUE(db.get_keys().empty()); - EXPECT_TRUE(db.get_time_touch().empty()); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 2. 插入与查询 -TEST(InsertAndSearch) { - Memdb db(10); - EXPECT_TRUE(db.insert(1, "one")); - EXPECT_EQ(1u, db.size()); - auto opt = db.search(1); - EXPECT_OPTIONAL_EQ("one", opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 3. 重复插入失败 -TEST(InsertDuplicateFails) { - Memdb db; - EXPECT_TRUE(db.insert(1, "one")); - EXPECT_FALSE(db.insert(1, "another")); - EXPECT_EQ(1u, db.size()); - auto opt = db.search(1); - EXPECT_OPTIONAL_EQ("one", opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 4. 查询不存在的键 -TEST(SearchNonExistent) { - Memdb db; - auto opt = db.search(42); - EXPECT_NO_VALUE(opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 5. 删除存在的键 -TEST(RemoveExisting) { - Memdb db; - db.insert(1, "one"); - EXPECT_TRUE(db.remove(1)); - EXPECT_EQ(0u, db.size()); - auto opt = db.search(1); - EXPECT_NO_VALUE(opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 6. 删除不存在的键 -TEST(RemoveNonExistentFails) { - Memdb db; - EXPECT_FALSE(db.remove(99)); - EXPECT_EQ(0u, db.size()); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 7. 删除后重新插入 -TEST(RemoveThenReinsert) { - Memdb db; - db.insert(1, "one"); - db.remove(1); - EXPECT_TRUE(db.insert(1, "new")); - EXPECT_EQ(1u, db.size()); - auto opt = db.search(1); - EXPECT_OPTIONAL_EQ("new", opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 8. 更新(不触摸) -TEST(UpdateWithoutTouch) { - Memdb db(10); - db.insert(1, "one"); - EXPECT_TRUE(db.update(1, "updated", false)); - EXPECT_EQ(1u, db.size()); - auto opt = db.search(1); - EXPECT_OPTIONAL_EQ("updated", opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 9. 更新(触摸)延长寿命 —— 使用 C++20 字面量 -TEST(UpdateWithTouchExtendsLifetime) { - const int TTL = 3; - Memdb db(TTL); - db.insert(1, "one"); - - // 等待 1.5 秒(剩余寿命约 1.5 秒) - std::this_thread::sleep_for(1500ms); - - // 触摸更新,重置寿命为从当前起 TTL 秒 - EXPECT_TRUE(db.update(1, "touched", true)); - - // 再等待 2.5 秒(从触摸起 2.5 < TTL,应存活) - std::this_thread::sleep_for(2500ms); - - db.search(999); // 触发 flush - auto opt = db.search(1); - EXPECT_TRUE(opt.has_value()); - EXPECT_OPTIONAL_EQ("touched", opt); - EXPECT_EQ(1u, db.size()); - - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 10. 更新不存在的键 -TEST(UpdateNonExistentFails) { - Memdb db; - EXPECT_FALSE(db.update(2, "nope")); - EXPECT_EQ(0u, db.size()); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 11. 过期后自动清除 -TEST(ExpirationAfterTimeout) { - const int TTL = 2; - Memdb db(TTL); - db.insert(1, "expire"); - - // 等待 TTL + 1 秒(保证超过) - std::this_thread::sleep_for(std::chrono::seconds(TTL + 1)); - - db.search(999); // 触发 flush - EXPECT_EQ(0u, db.size()); - EXPECT_NO_VALUE(db.search(1)); - - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 12. 未过期前可查询 -TEST(NotExpiredBeforeTimeout) { - const int TTL = 2; - Memdb db(TTL); - db.insert(1, "alive"); - std::this_thread::sleep_for(1s); - EXPECT_EQ(1u, db.size()); - auto opt = db.search(1); - EXPECT_OPTIONAL_EQ("alive", opt); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 13. 更新不触摸不延长寿命 -TEST(UpdateWithoutTouchDoesNotExtend) { - const int TTL = 3; - Memdb db(TTL); - db.insert(1, "one"); - - // 等待 1.5 秒(剩余 1.5 秒) - std::this_thread::sleep_for(1500ms); - - // 更新但不触摸,过期时间不变 - EXPECT_TRUE(db.update(1, "updated", false)); - - // 再等待 2 秒(总休眠 3.5 > TTL,应过期) - std::this_thread::sleep_for(2000ms); - - db.search(999); - EXPECT_EQ(0u, db.size()); - EXPECT_NO_VALUE(db.search(1)); - - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 14. 生存时间为 0,立即过期 -TEST(ZeroLifetimeExpiresImmediately) { - Memdb db(0); - db.insert(1, "zero"); - std::this_thread::sleep_for(10ms); - db.search(999); - EXPECT_EQ(0u, db.size()); - EXPECT_NO_VALUE(db.search(1)); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 15. 混合操作一致性 -TEST(MixedInsertDeleteSize) { - Memdb db; - db.insert(1, "a"); - db.insert(2, "b"); - db.insert(3, "c"); - db.remove(2); - db.insert(4, "d"); - EXPECT_EQ(3u, db.size()); - EXPECT_TRUE(db.search(1).has_value()); - EXPECT_FALSE(db.search(2).has_value()); - EXPECT_TRUE(db.search(3).has_value()); - EXPECT_TRUE(db.search(4).has_value()); - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// 16. 批量过期 -TEST(BulkExpirationClearsSize) { - const int TTL = 1; - Memdb db(TTL); - for (int i = 0; i < 100; ++i) { - db.insert(i, std::to_string(i)); - } - EXPECT_EQ(100u, db.size()); - std::this_thread::sleep_for(std::chrono::seconds(TTL + 1)); - db.search(-1); - EXPECT_EQ(0u, db.size()); - for (int i = 0; i < 100; ++i) { - EXPECT_FALSE(db.search(i).has_value()); - } - std::cout << " [PASS]\n"; - ++g_test_passed; -} - -// ----- 程序入口 ----- -int main() { - std::cout << "Memdb Black-box Tests (C++20, no external libs)\n"; - std::cout << "================================================\n"; - - for (auto& [name, fn] : tests) { - std::cout << "Test: " << name << "\n"; - fn(); - } - - std::cout << "================================================\n"; - std::cout << "Passed: " << g_test_passed << ", Failed: " << g_test_failed << "\n"; - - return g_test_failed > 0 ? 1 : 0; -} \ No newline at end of file diff --git a/memdb/src/main.cpp b/memdb/src/main.cpp deleted file mode 100644 index 23e8a44..0000000 --- a/memdb/src/main.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include "main/memdb.cpp" -using namespace std; -Memdb testdb(10); -int main(){ - testdb.insert_("key1","value1"); - auto pack=testdb.search_("key1"); - cout<<(pack==nullopt?"未找到":pack.value())< - -bool Memdb ::index_timestamp::operator<(const index_timestamp& a) const { - return this -> item -> timestamp < a.item -> timestamp; -} - - -template - -Memdb ::Memdb() = default; - - -template - -Memdb ::Memdb(int max_time) : MAX_TIME(std::max(0, max_time)) {} - - -template - -Memdb & Memdb ::operator=(const Memdb & to_be_cp_memdb) = default; - - -template - -Memdb ::~Memdb() = default; - - -template - -size_t Memdb ::size() const { - return this -> __size; -} - - -template - -const std::unordered_map ::index_keys>& Memdb ::get_keys() const { - return this -> keys; -} - - -template - -const std::list ::memdb_column>& Memdb ::get_db() const { - return this -> db; -} - - -/* -内测版 -*/ - - -template - -void Memdb ::flush() { - if (this -> time_touch.empty() == true) { - return; - } - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - typename std::list ::iterator it = this -> time_touch.begin() -> item; - - while (now_time >= it -> timestamp) { - this -> __size--; - key_t to_be_del_k = it -> key; - this -> db.erase(it); - this -> keys.erase(to_be_del_k); - this -> time_touch.erase(this -> time_touch.begin()); - - if (this -> time_touch.empty() == true) { - return; - } - it = this -> time_touch.begin() -> item; - now_time = std::chrono::system_clock::now(); - } -} - - -template - -const std::multiset ::index_timestamp>& Memdb ::get_time_touch() const { - return this -> time_touch; -} - - -template - -bool Memdb ::insert(key_t to_be_ins_k, value_t ins_v) { - this -> flush(); - if (this -> keys.find(to_be_ins_k) != this -> keys.end()) { - return this -> fail; - } - - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - - Memdb::memdb_column new_column; - new_column.key = to_be_ins_k; - new_column.value = ins_v; - new_column.timestamp = now_time + std::chrono::seconds(MAX_TIME); - this -> db.push_back(new_column); - - Memdb::index_keys new_key; - new_key.key = to_be_ins_k; - new_key.item = std::prev(this -> db.end()); - this -> keys[to_be_ins_k] = new_key; - - Memdb::index_timestamp new_time_touch; - new_time_touch.item = std::prev(this -> db.end()); - this -> time_touch.insert(new_time_touch); - - this -> __size++; - - return this -> succ; -} - - -template - -bool Memdb ::remove(key_t to_be_del_k) { - //! 直接删除,不要lazy - this -> flush(); - if (this -> keys.find(to_be_del_k) == this -> keys.end()) { - return this -> fail; - } - - typename std::list ::iterator it = this -> keys[to_be_del_k].item; - // it -> be_del = true; - this -> keys.erase(it -> key); - this -> time_touch.erase({it}); - this -> db.erase(it); - this -> __size--; - - return this -> succ; -} - - -template - -bool Memdb ::update(key_t to_be_udt_k, value_t udt_v, bool need_to_udt_timetouch) { - //! 先删再加 - this -> flush(); - if (this -> keys.find(to_be_udt_k) == this -> keys.end()) { - return this -> fail; - } - - typename std::list ::iterator it = this -> keys[to_be_udt_k].item; - it -> value = udt_v; - if (need_to_udt_timetouch == true) { - std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now(); - T copy_k = it -> key; - U copy_v = it -> value; - this -> remove(copy_k); - this -> insert(copy_k, copy_v); - } - - return this -> succ; -} - - -template - -std::optional Memdb ::search(key_t to_be_sch_k){ - this -> flush(); - if (this -> keys.find(to_be_sch_k) == this -> keys.end()) { - return std::nullopt; - } - - typename std::list ::iterator it = this -> keys[to_be_sch_k].item; - return it -> value; -} - -} \ No newline at end of file From 9bbbc3fdf4ce09d6e4170d07aae2ea6208d5b5f2 Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Fri, 14 Aug 2026 19:39:06 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E5=95=A5=E9=83=BD=E6=B2=A1=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libmemdb/inc/us/memdb.hpp | 18 +++------ memdb/.gitignore | 72 ++++++++++++++++++++++++++++++++++++ memdb/Makefile | 0 memdb/README.md | 0 memdb/_run.sh | 0 memdb/_set.sh | 0 memdb/src/memdb.cpp | 78 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 memdb/.gitignore create mode 100644 memdb/Makefile create mode 100644 memdb/README.md create mode 100644 memdb/_run.sh create mode 100644 memdb/_set.sh create mode 100644 memdb/src/memdb.cpp diff --git a/libmemdb/inc/us/memdb.hpp b/libmemdb/inc/us/memdb.hpp index cc8b48a..ec3873a 100644 --- a/libmemdb/inc/us/memdb.hpp +++ b/libmemdb/inc/us/memdb.hpp @@ -8,10 +8,6 @@ -namespace shufeng2012 { - - - template class Memdb { @@ -55,10 +51,10 @@ public: - Memdb() = default; - Memdb(int max_time) : MAX_TIME(std::max(0, max_time)) {} - Memdb& operator=(const Memdb& to_be_cp_memdb) = default; - ~Memdb() = default; + explicit Memdb() = default; + explicit Memdb(int max_time) : MAX_TIME(std::max(0, max_time)) {} + explicit Memdb& operator=(const Memdb& to_be_cp_memdb) = default; + explicit ~Memdb() = default; size_t size() const { @@ -149,8 +145,4 @@ public: typename std::list ::iterator it = this -> keys[to_be_sch_k].item; return it -> value; } -}; - - - -} \ No newline at end of file +}; \ No newline at end of file diff --git a/memdb/.gitignore b/memdb/.gitignore new file mode 100644 index 0000000..839a556 --- /dev/null +++ b/memdb/.gitignore @@ -0,0 +1,72 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Linker files +*.ilk + +# Debugger Files +*.pdb + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll +*.so.* + + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Build directories +build/ +Build/ +build-*/ + +# CMake generated files +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +#Makefile +install_manifest.txt +compile_commands.json + +# Temporary files +*.tmp +*.log +*.bak +*.swp + +# vcpkg +vcpkg_installed/ + +# debug information files +*.dwo + +# test output & cache +Testing/ +.cache/ + +# Databases +*.db* \ No newline at end of file diff --git a/memdb/Makefile b/memdb/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/memdb/README.md b/memdb/README.md new file mode 100644 index 0000000..e69de29 diff --git a/memdb/_run.sh b/memdb/_run.sh new file mode 100644 index 0000000..e69de29 diff --git a/memdb/_set.sh b/memdb/_set.sh new file mode 100644 index 0000000..e69de29 diff --git a/memdb/src/memdb.cpp b/memdb/src/memdb.cpp new file mode 100644 index 0000000..55720a8 --- /dev/null +++ b/memdb/src/memdb.cpp @@ -0,0 +1,78 @@ +#include +#include + +#include + +#include + +#include +#include + +namespace json = boost::json; + + + +struct ClientConfig { + std::string connected_host = "127.0.0.1"; + int connected_port = 8005; + std::string service_name = "db2"; + double timeout = 10.0; + bool retry_on_refused = true; +}; + +struct ServerConfig { + std::string listen_host = "127.0.0.1"; + int listen_port = 8011; + int workers = 4; + std::string db_url = "sqlite:///database.db"; +}; + +static std::string get_db_path(const std::string url) { + const std::string prefix = "sqlite:///"; + if (url.rfind(prefix, 0) == 0) { + return url.substr(prefix.size()); + } + return url; +} + + + +class DBConnection { +private: + ClientConfig __cfg; + + +public: + explicit DBConnection(const ClientConfig& cfg) : + __cfg(cfg) {} + ~DBConnection() = default; + + std::string get_from_sql(const std::string& sql_name) { + pmc::net::RpcClient client(__cfg.connected_host, __cfg.connected_port, __cfg.service_name, __cfg.timeout, __cfg.retry_on_refused); + + try { + auto data = client.call("execute", {{"action", "select"}, {"table", "memdb"}, {"where", {"sql_name", sql_name}}}); + + } catch (const std::exception& err) { + std::cerr << "[memdb] Error: 连接失败: " << err.what() << std::endl; + std::exit(1); + } + } +}; + + +class MemdbServer { + + +private: + ServerConfig __cfg; + + +public: + explicit MemdbServer(const ServerConfig& cfg) : + __cfg(cfg) {} + + void start() { + //TODO 编写 + } +}; \ No newline at end of file