From 7d33ec2ecc293428f76a5273a3a70d134e54a8e3 Mon Sep 17 00:00:00 2001 From: UnknownObject Date: Fri, 11 Sep 2026 17:25:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=80=80=E5=87=BA=E6=97=B6?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E5=B4=A9=E6=BA=83=E7=9A=84BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UNSWebServerCore/ServerCore.cpp | 64 ++++-- UNSWebServerCore/ServerCore.h | 2 +- UNSWebServerCore/TempFileManager.cpp | 304 +++++++++++++++------------ UNSWebServerCore/TempFileManager.h | 25 +-- 4 files changed, 224 insertions(+), 171 deletions(-) diff --git a/UNSWebServerCore/ServerCore.cpp b/UNSWebServerCore/ServerCore.cpp index 64a2b19..1f1b617 100644 --- a/UNSWebServerCore/ServerCore.cpp +++ b/UNSWebServerCore/ServerCore.cpp @@ -12,9 +12,10 @@ class ServerCore::Impl { public: int port = 0; - webcc::Server* ccServer = nullptr; - std::thread thServer; IPTable BlockedIPs; + std::thread thServer; + webcc::Server* ccServer = nullptr; + std::atomic_bool server_started = false; public: explicit Impl(int port) @@ -30,19 +31,28 @@ public: { if(ccServer != nullptr) { - if(ccServer->IsRunning()) - ccServer->Stop(); + // if(ccServer->IsRunning()) + // ccServer->Stop(); + // delete ccServer; + //Fix Crash + ccServer->Stop(); + if (thServer.joinable()) + thServer.join(); + delete ccServer; + ccServer = nullptr; } } public: - static void ServerThreadFunction(webcc::Server* server, int worker_thread, int loop_thread) + static void ServerThreadFunction(webcc::Server* server, int worker_thread, int loop_thread, std::atomic_bool* started_flag) { if (server == nullptr) return; server->set_buffer_size(65535); SCLOGF_INFO("ServerCore thread ready: {} Worker(s), {} Loop(s)", worker_thread, loop_thread); + if (started_flag) + started_flag->store(true, std::memory_order_release); server->Run(worker_thread, loop_thread); return; } @@ -88,17 +98,45 @@ void ServerCore::Run(int worker_thread, int loop_thread) return; } -void ServerCore::ThreadRun(int worker_thread, int loop_thread) +bool ServerCore::ThreadRun(int worker_thread, int loop_thread) { using namespace std::chrono; if (pimpl->ccServer == nullptr) - return; - pimpl->thServer = std::thread(Impl::ServerThreadFunction, pimpl->ccServer, worker_thread, loop_thread); - pimpl->thServer.detach(); - std::this_thread::sleep_for(100ms); - if (pimpl->ccServer->IsRunning()) + return false; + if (pimpl->thServer.joinable()) + { + SCLOG_ERROR("ServerCore::ThreadRun called while a server thread is already active"); + return false; // 或直接 return,视你采纳下面的返回值方案而定 + } + pimpl->server_started.store(false, std::memory_order_relaxed); + pimpl->thServer = std::thread(Impl::ServerThreadFunction, pimpl->ccServer, worker_thread, loop_thread, &pimpl->server_started); + bool reached_run = false; + for (int i = 0; i < 500; i++) + { + if (pimpl->server_started.load(std::memory_order_acquire)) + { + reached_run = true; + break; + } + std::this_thread::sleep_for(1ms); + } + if (!reached_run) + { + SCLOGF_FATAL("ServerCore thread failed to schedule within 500ms (port {})", pimpl->port); + // 尽力而为的安全收尾:即使线程迟迟没被调度起来,它终究会跑到 Run(), + // 而 Run() 会一直阻塞直到 Stop() 生效——所以这里调用 Stop()+join() + // 依然能把这个半启动状态收拾干净,不会遗留一个不受控的线程。 + pimpl->ccServer->Stop(); + if (pimpl->thServer.joinable()) + pimpl->thServer.join(); + return false; + } + bool running = pimpl->ccServer->IsRunning(); + if (running) SCLOG_INFO("ServerCore Running"); - return; + else + SCLOGF_ERROR("ServerCore failed to start listening on port {}", pimpl->port); + return running; } void ServerCore::Stop() @@ -106,6 +144,8 @@ void ServerCore::Stop() if (pimpl->ccServer == nullptr) return; pimpl->ccServer->Stop(); + if (pimpl->thServer.joinable()) + pimpl->thServer.join(); SCLOG_INFO("ServerCore Stopped"); return; } diff --git a/UNSWebServerCore/ServerCore.h b/UNSWebServerCore/ServerCore.h index 7ac1d21..c086370 100644 --- a/UNSWebServerCore/ServerCore.h +++ b/UNSWebServerCore/ServerCore.h @@ -31,7 +31,7 @@ public: public: void Run(int worker_thread = 1, int loop_thread = 1); - void ThreadRun(int worker_thread = 1, int loop_thread = 1); + bool ThreadRun(int worker_thread = 1, int loop_thread = 1); void Stop(); bool Running(); void UpdateProcessor(); diff --git a/UNSWebServerCore/TempFileManager.cpp b/UNSWebServerCore/TempFileManager.cpp index 17dc54f..db575c2 100644 --- a/UNSWebServerCore/TempFileManager.cpp +++ b/UNSWebServerCore/TempFileManager.cpp @@ -1,115 +1,147 @@ #include "TempFileManager.h" +#include #include +#include #include +#include #include "ServerLogger.h" -TempFileManager::TempFileManager() noexcept +class TempFileManager::Impl { -} - -// ================= 更新:核心析构函数实现 ================= -TempFileManager::~TempFileManager() noexcept -{ - // 1. 必须第一步:发送停止信号并阻塞等待后台清理线程彻底退出 - // 这样能确保后面遍历 file_map 时,绝对没有第二个线程在并发访问它 - SCLOG_INFO("TempFileManager Destruction Begin"); - cleanup_thread.request_stop(); - if (cleanup_thread.joinable()) - cleanup_thread.join(); - // 2. 此时属于单线程环境,无需加锁。遍历并销毁所有非永久文件 - std::error_code ec; - for (const auto& [_, fcb] : file_map) +public: + struct FileControlBlock + { + WebFileInfo info; + std::chrono::steady_clock::time_point expire_time; + std::chrono::steady_clock::time_point active_start_time; + std::chrono::seconds remaining_timeout; + std::chrono::seconds max_processing_timeout; + bool is_active = false; + bool is_permanent = false; // 是否永久保留 + bool is_invalid = false; + }; + + std::string base_dir; + std::unordered_map file_map; + mutable std::shared_mutex rw_mutex; + + // C++20 jthread + std::jthread cleanup_thread; + +public: + Impl() noexcept { - if (!fcb.is_permanent && !base_dir.empty()) - { - std::string path = fcb.info.MakePath(base_dir); - // 使用无异常重载版本,即使磁盘物理删除失败(如文件被外层强行独占锁死)也绝不抛出异常 - std::filesystem::remove(path, ec); - if (!ec) - SCLOGF_INFO("Temp File {} Deleted.", path); - else - SCLOGF_INFO("Temp File {} Delete Failed: {}({})", path, ec.value(), ec.message()); - } - // 如果 is_permanent 为 true(永久化文件),则跳过不处理,物理文件将安全留在磁盘上 } - // 3. 析构结束,file_map 内存控制块会自动退栈销毁 - SCLOG_INFO("TempFileManager Destruction Finished"); -} -// ================= 更新:高灵敏度的后台扫描逻辑 ================= -void TempFileManager::CleanupLoop(std::stop_token st) noexcept -{ - while (!st.stop_requested()) + ~Impl() noexcept { - // 改进:引入分段休眠(10次*100ms),让析构函数调用 join() 时能在最大 100ms 内瞬间响应退出 - // 避免传统的 sleep_for(1s) 导致服务器内核关闭时卡顿 1 秒 - for (int i = 0; i < 10; i++) + // 1. 必须第一步:发送停止信号并阻塞等待后台清理线程彻底退出 + // 这样能确保后面遍历 file_map 时,绝对没有第二个线程在并发访问它 + SCLOG_INFO("TempFileManager Destruction Begin"); + cleanup_thread.request_stop(); + if (cleanup_thread.joinable()) + cleanup_thread.join(); + // 2. 此时属于单线程环境,无需加锁。遍历并销毁所有非永久文件 + std::error_code ec; + for (const auto& [_, fcb] : file_map) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - if (st.stop_requested()) - return; // 随时收到终止信号随时退出 - } - std::unique_lock lock(rw_mutex); - if (base_dir.empty()) - continue; - auto now = std::chrono::steady_clock::now(); - for (auto it = file_map.begin(); it != file_map.end(); ) - { - bool should_delete = false; - if (it->second.is_invalid) - should_delete = true; //手动设置的无条件立即删除 - if (!it->second.is_permanent) + if (!fcb.is_permanent && !base_dir.empty()) { - if (it->second.is_active) - { - if ((it->second.max_processing_timeout > std::chrono::seconds(0)) && ((now - it->second.active_start_time) > it->second.max_processing_timeout)) - should_delete = true; - } - else - { - if (now > it->second.expire_time) - should_delete = true; - } - } - if (should_delete) - { - std::error_code ec; - std::string path = it->second.info.MakePath(base_dir); + std::string path = fcb.info.MakePath(base_dir); + // 使用无异常重载版本,即使磁盘物理删除失败(如文件被外层强行独占锁死)也绝不抛出异常 std::filesystem::remove(path, ec); if (!ec) - SCLOGF_INFO("Temp File {} {}, Deleted.", path, (it->second.is_invalid ? "Invalid" : "Expried")); + SCLOGF_INFO("Temp File {} Deleted.", path); else - SCLOGF_INFO("Temp File {} {}, Delete Failed: {}({})", path, (it->second.is_invalid ? "Invalid" : "Expried"), ec.value(), ec.message()); - it = file_map.erase(it); + SCLOGF_WARNING("Temp File {} Delete Failed: {}({})", path, ec.value(), ec.message()); + } + // 如果 is_permanent 为 true(永久化文件),则跳过不处理,物理文件将安全留在磁盘上 + } + // 3. 析构结束,file_map 内存控制块会自动退栈销毁 + SCLOG_INFO("TempFileManager Destruction Finished"); + } + +public: + void CleanupLoop(std::stop_token st) noexcept + { + while (!st.stop_requested()) + { + // 改进:引入分段休眠(10次*100ms),让析构函数调用 join() 时能在最大 100ms 内瞬间响应退出 + // 避免传统的 sleep_for(1s) 导致服务器内核关闭时卡顿 1 秒 + for (int i = 0; i < 10; i++) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (st.stop_requested()) + return; // 随时收到终止信号随时退出 + } + std::unique_lock lock(rw_mutex); + if (base_dir.empty()) + continue; + auto now = std::chrono::steady_clock::now(); + for (auto it = file_map.begin(); it != file_map.end(); ) + { + bool should_delete = false; + if (it->second.is_invalid) + should_delete = true; //手动设置的无条件立即删除 + if (!it->second.is_permanent) + { + if (it->second.is_active) + { + if ((it->second.max_processing_timeout > std::chrono::seconds(0)) && ((now - it->second.active_start_time) > it->second.max_processing_timeout)) + should_delete = true; + } + else + { + if (now > it->second.expire_time) + should_delete = true; + } + } + if (should_delete) + { + std::error_code ec; + std::string path = it->second.info.MakePath(base_dir); + std::filesystem::remove(path, ec); + if (!ec) + SCLOGF_INFO("Temp File {} {}, Deleted.", path, (it->second.is_invalid ? "Invalid" : "Expried")); + else + SCLOGF_WARNING("Temp File {} {}, Delete Failed: {}({})", path, (it->second.is_invalid ? "Invalid" : "Expried"), ec.value(), ec.message()); + it = file_map.erase(it); + } + else + ++it; } - else - ++it; } } +}; + +TempFileManager::TempFileManager() noexcept : pimpl(std::make_unique()) +{ } +TempFileManager::~TempFileManager() noexcept = default; + // ================= 以下其余基础业务接口保持不变 ================= bool TempFileManager::SetBaseDirectory(std::string dir) noexcept { - std::unique_lock lock(rw_mutex); // 加上写锁,防止与其他文件操作并发 - base_dir = std::move(dir); + std::unique_lock lock(pimpl->rw_mutex); // 加上写锁,防止与其他文件操作并发 + pimpl->base_dir = std::move(dir); std::error_code ec; // 物理创建目录(无异常版本) - std::filesystem::create_directories(base_dir, ec); + std::filesystem::create_directories(pimpl->base_dir, ec); if (ec) - SCLOGF_INFO("TempFileManager: create_directories error: {}({})", ec.value(), ec.message()); + SCLOGF_ERROR("TempFileManager: create_directories error: {}({})", ec.value(), ec.message()); // 只有在线程未启动时才启动后台清理线程,确保整个生命周期只启动一次 - if (!cleanup_thread.joinable() && !ec) + if (!pimpl->cleanup_thread.joinable() && !ec) { - cleanup_thread = std::jthread([this] (std::stop_token st) + pimpl->cleanup_thread = std::jthread([this] (std::stop_token st) { - this->CleanupLoop(st); + this->pimpl->CleanupLoop(st); }); SCLOGF_INFO("TempFileManager: Thread Started."); } else - SCLOGF_ERROR("TempFileManager: Failed To Start Thread (Thread Joinable: {}, Error: {})", cleanup_thread.joinable(), ec.message()); + SCLOGF_ERROR("TempFileManager: Failed To Start Thread (Thread Joinable: {}, Error: {})", pimpl->cleanup_thread.joinable(), ec.message()); return !ec; } @@ -117,36 +149,36 @@ bool TempFileManager::RegisterFile(const WebFileInfo& info, std::chrono::seconds { try { - std::unique_lock lock(rw_mutex); - if (file_map.contains(info.GetStorageFileName())) + std::unique_lock lock(pimpl->rw_mutex); + if (pimpl->file_map.contains(info.GetStorageFileName())) { - SCLOGF_INFO("RegisterFile Failed: File {} Already Exists", info.GetStorageFileName()); + SCLOGF_WARNING("RegisterFile Failed: File {} Already Exists", info.GetStorageFileName()); return false; } - FileControlBlock fcb + Impl::FileControlBlock fcb { .info = info, .expire_time = std::chrono::steady_clock::now() + timeout, .remaining_timeout = timeout, .max_processing_timeout = max_proc_timeout }; - file_map[info.GetStorageFileName()] = std::move(fcb); + pimpl->file_map[info.GetStorageFileName()] = std::move(fcb); SCLOGF_INFO("File {}({}) Registered", info.GetOriginalFileName(), info.GetStorageFileName()); return true; } catch (...) { - SCLOG_INFO("RegisterFile Failed: Exception"); + SCLOG_WARNING("RegisterFile Failed: Exception"); return false; } } bool TempFileManager::InvalidateFile(const WebFileInfo& info) { - std::unique_lock lock(rw_mutex); - if (file_map.contains(info.GetStorageFileName())) + std::unique_lock lock(pimpl->rw_mutex); + if (pimpl->file_map.contains(info.GetStorageFileName())) { - file_map[info.GetStorageFileName()].is_invalid = true; + pimpl->file_map[info.GetStorageFileName()].is_invalid = true; SCLOGF_INFO("File [{}]({}) Marked AS Invalid", info.GetStorageFileName(), info.GetOriginalFileName()); return true; } @@ -158,12 +190,12 @@ bool TempFileManager::InvalidateFile(const WebFileInfo& info) bool TempFileManager::InvalidateFile(const std::map& info) { size_t succ_cnt = 0; - std::unique_lock lock(rw_mutex); + std::unique_lock lock(pimpl->rw_mutex); for (const auto& [on, sn] : info) { - if (file_map.contains(sn)) + if (pimpl->file_map.contains(sn)) { - file_map[sn].is_invalid = true; + pimpl->file_map[sn].is_invalid = true; succ_cnt++; SCLOGF_INFO("File [{}]({}) Marked AS Invalid", sn, on); } @@ -175,16 +207,16 @@ bool TempFileManager::InvalidateFile(const std::map& i bool TempFileManager::CopyFileTo(const std::string& storage_name, const std::string& dest_absolute_path) noexcept { - std::shared_lock lock(rw_mutex); - auto it = file_map.find(storage_name); + std::shared_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); auto dest_file = std::filesystem::path(dest_absolute_path) / storage_name; - if (it == file_map.end()) + if (it == pimpl->file_map.end()) { - SCLOGF_INFO("CopyFileTo({}, {}) Failed: File Not Exists", storage_name, dest_file); + SCLOGF_WARNING("CopyFileTo({}, {}) Failed: File Not Exists", storage_name, dest_file); return false; } std::error_code ec; - std::filesystem::copy(it->second.info.MakePath(base_dir), dest_file, std::filesystem::copy_options::overwrite_existing, ec); + std::filesystem::copy(it->second.info.MakePath(pimpl->base_dir), dest_file, std::filesystem::copy_options::overwrite_existing, ec); if (ec) SCLOGF_WARNING("CopyFileTo({}, {}) Failed: {}({})", storage_name, dest_file, ec.value(), ec.message()); else @@ -194,23 +226,23 @@ bool TempFileManager::CopyFileTo(const std::string& storage_name, const std::str bool TempFileManager::CutFileTo(const std::string& storage_name, const std::string& dest_absolute_path) noexcept { - std::unique_lock lock(rw_mutex); - auto it = file_map.find(storage_name); + std::unique_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); auto dest_file = std::filesystem::path(dest_absolute_path) / storage_name; - if (it == file_map.end()) + if (it == pimpl->file_map.end()) { - SCLOGF_INFO("CutFileTo({}, {}) Failed: File Not Exists", storage_name, dest_file); + SCLOGF_WARNING("CutFileTo({}, {}) Failed: File Not Exists", storage_name, dest_file); return false; } std::error_code ec; - std::filesystem::rename(it->second.info.MakePath(base_dir), dest_file, ec); + std::filesystem::rename(it->second.info.MakePath(pimpl->base_dir), dest_file, ec); if (ec) SCLOGF_WARNING("CutFileTo({}, {}) Failed: {}({})", storage_name, dest_file, ec.value(), ec.message()); else SCLOGF_INFO("CutFileTo({}, {}) Success", storage_name, dest_file); if (ec) return false; - file_map.erase(it); + pimpl->file_map.erase(it); return true; } @@ -218,18 +250,18 @@ bool TempFileManager::RenameFile(const std::string& old_storage_name, const std: { try { - std::unique_lock lock(rw_mutex); - auto it = file_map.find(old_storage_name); - if ((it == file_map.end()) || file_map.contains(new_storage_name)) + std::unique_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(old_storage_name); + if ((it == pimpl->file_map.end()) || pimpl->file_map.contains(new_storage_name)) { - SCLOGF_INFO("RenameFile({}, {}) Failed: File Not Exists", old_storage_name, new_storage_name); + SCLOGF_WARNING("RenameFile({}, {}) Failed: File Not Exists", old_storage_name, new_storage_name); return false; } std::error_code ec; - std::string old_path = it->second.info.MakePath(base_dir); - FileControlBlock fcb = std::move(it->second); + std::string old_path = it->second.info.MakePath(pimpl->base_dir); + Impl::FileControlBlock fcb = std::move(it->second); fcb.info.SetStorageFileName(new_storage_name); - std::string new_path = fcb.info.MakePath(base_dir); + std::string new_path = fcb.info.MakePath(pimpl->base_dir); std::filesystem::rename(old_path, new_path, ec); if (ec) SCLOGF_WARNING("RenameFile({}, {}) Failed: {}({})", old_storage_name, new_storage_name, ec.value(), ec.message()); @@ -237,43 +269,43 @@ bool TempFileManager::RenameFile(const std::string& old_storage_name, const std: SCLOGF_INFO("RenameFile({}, {}) Success", old_storage_name, new_storage_name); if (ec) return false; - file_map.erase(it); - file_map[new_storage_name] = std::move(fcb); + pimpl->file_map.erase(it); + pimpl->file_map[new_storage_name] = std::move(fcb); return true; } catch (...) { - SCLOG_INFO("RenameFile Failed: Exception"); + SCLOG_WARNING("RenameFile Failed: Exception"); return false; } } bool TempFileManager::DeleteFile(const std::string& storage_name) noexcept { - std::unique_lock lock(rw_mutex); - auto it = file_map.find(storage_name); - if (it == file_map.end()) + std::unique_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); + if (it == pimpl->file_map.end()) { SCLOGF_WARNING("DeleteFile({}) Failed: File Not Exists", storage_name); return false; } std::error_code ec; - std::filesystem::remove(it->second.info.MakePath(base_dir), ec); + std::filesystem::remove(it->second.info.MakePath(pimpl->base_dir), ec); if (ec) SCLOGF_WARNING("DeleteFile({}) Failed: {}({})", storage_name, ec.value(), ec.message()); else SCLOGF_INFO("DeleteFile({}) Success", storage_name); if (ec) return false; - file_map.erase(it); + pimpl->file_map.erase(it); return true; } bool TempFileManager::ActiveFile(const std::string& storage_name) noexcept { - std::unique_lock lock(rw_mutex); - auto it = file_map.find(storage_name); - if ((it == file_map.end()) || it->second.is_active) + std::unique_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); + if ((it == pimpl->file_map.end()) || it->second.is_active) { SCLOGF_WARNING("ActiveFile({}) Failed: {}", storage_name, (it->second.is_active ? "Already Actived" : "File Not Exists")); return false; @@ -291,11 +323,11 @@ bool TempFileManager::ActiveFile(const std::string& storage_name) noexcept bool TempFileManager::DeactiveFile(const std::string& storage_name) noexcept { - std::unique_lock lock(rw_mutex); - auto it = file_map.find(storage_name); - if ((it == file_map.end()) || !it->second.is_active) + std::unique_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); + if ((it == pimpl->file_map.end()) || !it->second.is_active) { - SCLOGF_WARNING("DeactiveFile({}) Failed: {}", storage_name, ((it != file_map.end()) ? "Already Deactived" : "File Not Exists")); + SCLOGF_WARNING("DeactiveFile({}) Failed: {}", storage_name, ((it != pimpl->file_map.end()) ? "Already Deactived" : "File Not Exists")); return false; } it->second.is_active = false; @@ -306,9 +338,9 @@ bool TempFileManager::DeactiveFile(const std::string& storage_name) noexcept bool TempFileManager::SetPermanent(const std::string& storage_name, bool permanent) noexcept { - std::unique_lock lock(rw_mutex); - auto it = file_map.find(storage_name); - if (it == file_map.end()) + std::unique_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); + if (it == pimpl->file_map.end()) { SCLOGF_WARNING("SetPermanent({}) Failed: File Not Exists", storage_name); return false; @@ -320,31 +352,31 @@ bool TempFileManager::SetPermanent(const std::string& storage_name, bool permane bool TempFileManager::FileExists(const std::string& storage_name) const noexcept { - std::shared_lock lock(rw_mutex); - return file_map.contains(storage_name); + std::shared_lock lock(pimpl->rw_mutex); + return pimpl->file_map.contains(storage_name); } bool TempFileManager::GetFileInfo(const std::string& storage_name, WebFileInfo& out_info) const noexcept { try { - std::shared_lock lock(rw_mutex); - auto it = file_map.find(storage_name); - if (it == file_map.end()) + std::shared_lock lock(pimpl->rw_mutex); + auto it = pimpl->file_map.find(storage_name); + if (it == pimpl->file_map.end()) return false; out_info = it->second.info; return true; } catch (...) { - SCLOGF_INFO("GetFileInfo({}) Failed: Exception", storage_name); + SCLOGF_WARNING("GetFileInfo({}) Failed: Exception", storage_name); return false; } } size_t TempFileManager::GetFileCount() const noexcept { - return file_map.size(); + return pimpl->file_map.size(); } std::vector TempFileManager::GetAllFileInfos() const noexcept @@ -352,9 +384,9 @@ std::vector TempFileManager::GetAllFileInfos() const noexcept std::vector list; try { - std::shared_lock lock(rw_mutex); // 申请读锁,支持高并发并发读取 - list.reserve(file_map.size()); // 提前预留空间,减少内存重分配次数 - for (const auto& [_, fcb] : file_map) + std::shared_lock lock(pimpl->rw_mutex); // 申请读锁,支持高并发并发读取 + list.reserve(pimpl->file_map.size()); // 提前预留空间,减少内存重分配次数 + for (const auto& [_, fcb] : pimpl->file_map) list.push_back(fcb.info); // 拷贝文件元数据到外部 } catch (...) diff --git a/UNSWebServerCore/TempFileManager.h b/UNSWebServerCore/TempFileManager.h index b76c323..8122228 100644 --- a/UNSWebServerCore/TempFileManager.h +++ b/UNSWebServerCore/TempFileManager.h @@ -1,12 +1,10 @@ #pragma once #include #include -#include #include +#include #include "Export.h" -#include #include "WebFileInfo.h" -#include using std::chrono::operator""s; using std::chrono::operator""min; @@ -14,26 +12,9 @@ using std::chrono::operator""min; class UNSWSC_DLL_EXPORT TempFileManager { private: - struct FileControlBlock - { - WebFileInfo info; - std::chrono::steady_clock::time_point expire_time; - std::chrono::steady_clock::time_point active_start_time; - std::chrono::seconds remaining_timeout; - std::chrono::seconds max_processing_timeout; - bool is_active = false; - bool is_permanent = false; // 是否永久保留 - bool is_invalid = false; - }; + class Impl; - std::string base_dir; - std::unordered_map file_map; - mutable std::shared_mutex rw_mutex; - - // C++20 jthread - std::jthread cleanup_thread; - - void CleanupLoop(std::stop_token st) noexcept; + std::unique_ptr pimpl; public: TempFileManager() noexcept;