修复退出时可能崩溃的BUG

This commit is contained in:
UnknownObject
2026-09-11 17:25:36 +08:00
parent 0d50588ea7
commit 7d33ec2ecc
4 changed files with 224 additions and 171 deletions
+51 -11
View File
@@ -12,9 +12,10 @@ class ServerCore::Impl
{ {
public: public:
int port = 0; int port = 0;
webcc::Server* ccServer = nullptr;
std::thread thServer;
IPTable BlockedIPs; IPTable BlockedIPs;
std::thread thServer;
webcc::Server* ccServer = nullptr;
std::atomic_bool server_started = false;
public: public:
explicit Impl(int port) explicit Impl(int port)
@@ -30,19 +31,28 @@ public:
{ {
if(ccServer != nullptr) if(ccServer != nullptr)
{ {
if(ccServer->IsRunning()) // if(ccServer->IsRunning())
// ccServer->Stop();
// delete ccServer;
//Fix Crash
ccServer->Stop(); ccServer->Stop();
if (thServer.joinable())
thServer.join();
delete ccServer; delete ccServer;
ccServer = nullptr;
} }
} }
public: 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) if (server == nullptr)
return; return;
server->set_buffer_size(65535); server->set_buffer_size(65535);
SCLOGF_INFO("ServerCore thread ready: {} Worker(s), {} Loop(s)", worker_thread, loop_thread); 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); server->Run(worker_thread, loop_thread);
return; return;
} }
@@ -88,17 +98,45 @@ void ServerCore::Run(int worker_thread, int loop_thread)
return; return;
} }
void ServerCore::ThreadRun(int worker_thread, int loop_thread) bool ServerCore::ThreadRun(int worker_thread, int loop_thread)
{ {
using namespace std::chrono; using namespace std::chrono;
if (pimpl->ccServer == nullptr) if (pimpl->ccServer == nullptr)
return; return false;
pimpl->thServer = std::thread(Impl::ServerThreadFunction, pimpl->ccServer, worker_thread, loop_thread); if (pimpl->thServer.joinable())
pimpl->thServer.detach(); {
std::this_thread::sleep_for(100ms); SCLOG_ERROR("ServerCore::ThreadRun called while a server thread is already active");
if (pimpl->ccServer->IsRunning()) 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"); SCLOG_INFO("ServerCore Running");
return; else
SCLOGF_ERROR("ServerCore failed to start listening on port {}", pimpl->port);
return running;
} }
void ServerCore::Stop() void ServerCore::Stop()
@@ -106,6 +144,8 @@ void ServerCore::Stop()
if (pimpl->ccServer == nullptr) if (pimpl->ccServer == nullptr)
return; return;
pimpl->ccServer->Stop(); pimpl->ccServer->Stop();
if (pimpl->thServer.joinable())
pimpl->thServer.join();
SCLOG_INFO("ServerCore Stopped"); SCLOG_INFO("ServerCore Stopped");
return; return;
} }
+1 -1
View File
@@ -31,7 +31,7 @@ public:
public: public:
void Run(int worker_thread = 1, int loop_thread = 1); 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(); void Stop();
bool Running(); bool Running();
void UpdateProcessor(); void UpdateProcessor();
+105 -73
View File
@@ -1,14 +1,39 @@
#include "TempFileManager.h" #include "TempFileManager.h"
#include <thread>
#include <filesystem> #include <filesystem>
#include <shared_mutex>
#include <system_error> #include <system_error>
#include <unordered_map>
#include "ServerLogger.h" #include "ServerLogger.h"
TempFileManager::TempFileManager() noexcept class TempFileManager::Impl
{
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<std::string, FileControlBlock> file_map;
mutable std::shared_mutex rw_mutex;
// C++20 jthread
std::jthread cleanup_thread;
public:
Impl() noexcept
{ {
} }
// ================= 更新:核心析构函数实现 ================= ~Impl() noexcept
TempFileManager::~TempFileManager() noexcept
{ {
// 1. 必须第一步:发送停止信号并阻塞等待后台清理线程彻底退出 // 1. 必须第一步:发送停止信号并阻塞等待后台清理线程彻底退出
// 这样能确保后面遍历 file_map 时,绝对没有第二个线程在并发访问它 // 这样能确保后面遍历 file_map 时,绝对没有第二个线程在并发访问它
@@ -28,7 +53,7 @@ TempFileManager::~TempFileManager() noexcept
if (!ec) if (!ec)
SCLOGF_INFO("Temp File {} Deleted.", path); SCLOGF_INFO("Temp File {} Deleted.", path);
else else
SCLOGF_INFO("Temp File {} Delete Failed: {}({})", path, ec.value(), ec.message()); SCLOGF_WARNING("Temp File {} Delete Failed: {}({})", path, ec.value(), ec.message());
} }
// 如果 is_permanent 为 true(永久化文件),则跳过不处理,物理文件将安全留在磁盘上 // 如果 is_permanent 为 true(永久化文件),则跳过不处理,物理文件将安全留在磁盘上
} }
@@ -36,8 +61,8 @@ TempFileManager::~TempFileManager() noexcept
SCLOG_INFO("TempFileManager Destruction Finished"); SCLOG_INFO("TempFileManager Destruction Finished");
} }
// ================= 更新:高灵敏度的后台扫描逻辑 ================= public:
void TempFileManager::CleanupLoop(std::stop_token st) noexcept void CleanupLoop(std::stop_token st) noexcept
{ {
while (!st.stop_requested()) while (!st.stop_requested())
{ {
@@ -79,7 +104,7 @@ void TempFileManager::CleanupLoop(std::stop_token st) noexcept
if (!ec) if (!ec)
SCLOGF_INFO("Temp File {} {}, Deleted.", path, (it->second.is_invalid ? "Invalid" : "Expried")); SCLOGF_INFO("Temp File {} {}, Deleted.", path, (it->second.is_invalid ? "Invalid" : "Expried"));
else else
SCLOGF_INFO("Temp File {} {}, Delete Failed: {}({})", path, (it->second.is_invalid ? "Invalid" : "Expried"), ec.value(), ec.message()); SCLOGF_WARNING("Temp File {} {}, Delete Failed: {}({})", path, (it->second.is_invalid ? "Invalid" : "Expried"), ec.value(), ec.message());
it = file_map.erase(it); it = file_map.erase(it);
} }
else else
@@ -87,29 +112,36 @@ void TempFileManager::CleanupLoop(std::stop_token st) noexcept
} }
} }
} }
};
TempFileManager::TempFileManager() noexcept : pimpl(std::make_unique<Impl>())
{
}
TempFileManager::~TempFileManager() noexcept = default;
// ================= 以下其余基础业务接口保持不变 ================= // ================= 以下其余基础业务接口保持不变 =================
bool TempFileManager::SetBaseDirectory(std::string dir) noexcept bool TempFileManager::SetBaseDirectory(std::string dir) noexcept
{ {
std::unique_lock lock(rw_mutex); // 加上写锁,防止与其他文件操作并发 std::unique_lock lock(pimpl->rw_mutex); // 加上写锁,防止与其他文件操作并发
base_dir = std::move(dir); pimpl->base_dir = std::move(dir);
std::error_code ec; std::error_code ec;
// 物理创建目录(无异常版本) // 物理创建目录(无异常版本)
std::filesystem::create_directories(base_dir, ec); std::filesystem::create_directories(pimpl->base_dir, ec);
if (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."); SCLOGF_INFO("TempFileManager: Thread Started.");
} }
else 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; return !ec;
} }
@@ -117,36 +149,36 @@ bool TempFileManager::RegisterFile(const WebFileInfo& info, std::chrono::seconds
{ {
try try
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
if (file_map.contains(info.GetStorageFileName())) 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; return false;
} }
FileControlBlock fcb Impl::FileControlBlock fcb
{ {
.info = info, .info = info,
.expire_time = std::chrono::steady_clock::now() + timeout, .expire_time = std::chrono::steady_clock::now() + timeout,
.remaining_timeout = timeout, .remaining_timeout = timeout,
.max_processing_timeout = max_proc_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()); SCLOGF_INFO("File {}({}) Registered", info.GetOriginalFileName(), info.GetStorageFileName());
return true; return true;
} }
catch (...) catch (...)
{ {
SCLOG_INFO("RegisterFile Failed: Exception"); SCLOG_WARNING("RegisterFile Failed: Exception");
return false; return false;
} }
} }
bool TempFileManager::InvalidateFile(const WebFileInfo& info) bool TempFileManager::InvalidateFile(const WebFileInfo& info)
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
if (file_map.contains(info.GetStorageFileName())) 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()); SCLOGF_INFO("File [{}]({}) Marked AS Invalid", info.GetStorageFileName(), info.GetOriginalFileName());
return true; return true;
} }
@@ -158,12 +190,12 @@ bool TempFileManager::InvalidateFile(const WebFileInfo& info)
bool TempFileManager::InvalidateFile(const std::map<std::string, std::string>& info) bool TempFileManager::InvalidateFile(const std::map<std::string, std::string>& info)
{ {
size_t succ_cnt = 0; size_t succ_cnt = 0;
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
for (const auto& [on, sn] : info) 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++; succ_cnt++;
SCLOGF_INFO("File [{}]({}) Marked AS Invalid", sn, on); SCLOGF_INFO("File [{}]({}) Marked AS Invalid", sn, on);
} }
@@ -175,16 +207,16 @@ bool TempFileManager::InvalidateFile(const std::map<std::string, std::string>& i
bool TempFileManager::CopyFileTo(const std::string& storage_name, const std::string& dest_absolute_path) noexcept bool TempFileManager::CopyFileTo(const std::string& storage_name, const std::string& dest_absolute_path) noexcept
{ {
std::shared_lock lock(rw_mutex); std::shared_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
auto dest_file = std::filesystem::path(dest_absolute_path) / 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; return false;
} }
std::error_code ec; 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) if (ec)
SCLOGF_WARNING("CopyFileTo({}, {}) Failed: {}({})", storage_name, dest_file, ec.value(), ec.message()); SCLOGF_WARNING("CopyFileTo({}, {}) Failed: {}({})", storage_name, dest_file, ec.value(), ec.message());
else 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 bool TempFileManager::CutFileTo(const std::string& storage_name, const std::string& dest_absolute_path) noexcept
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
auto dest_file = std::filesystem::path(dest_absolute_path) / 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; return false;
} }
std::error_code ec; 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) if (ec)
SCLOGF_WARNING("CutFileTo({}, {}) Failed: {}({})", storage_name, dest_file, ec.value(), ec.message()); SCLOGF_WARNING("CutFileTo({}, {}) Failed: {}({})", storage_name, dest_file, ec.value(), ec.message());
else else
SCLOGF_INFO("CutFileTo({}, {}) Success", storage_name, dest_file); SCLOGF_INFO("CutFileTo({}, {}) Success", storage_name, dest_file);
if (ec) if (ec)
return false; return false;
file_map.erase(it); pimpl->file_map.erase(it);
return true; return true;
} }
@@ -218,18 +250,18 @@ bool TempFileManager::RenameFile(const std::string& old_storage_name, const std:
{ {
try try
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
auto it = file_map.find(old_storage_name); auto it = pimpl->file_map.find(old_storage_name);
if ((it == file_map.end()) || file_map.contains(new_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; return false;
} }
std::error_code ec; std::error_code ec;
std::string old_path = it->second.info.MakePath(base_dir); std::string old_path = it->second.info.MakePath(pimpl->base_dir);
FileControlBlock fcb = std::move(it->second); Impl::FileControlBlock fcb = std::move(it->second);
fcb.info.SetStorageFileName(new_storage_name); 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); std::filesystem::rename(old_path, new_path, ec);
if (ec) if (ec)
SCLOGF_WARNING("RenameFile({}, {}) Failed: {}({})", old_storage_name, new_storage_name, ec.value(), ec.message()); 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); SCLOGF_INFO("RenameFile({}, {}) Success", old_storage_name, new_storage_name);
if (ec) if (ec)
return false; return false;
file_map.erase(it); pimpl->file_map.erase(it);
file_map[new_storage_name] = std::move(fcb); pimpl->file_map[new_storage_name] = std::move(fcb);
return true; return true;
} }
catch (...) catch (...)
{ {
SCLOG_INFO("RenameFile Failed: Exception"); SCLOG_WARNING("RenameFile Failed: Exception");
return false; return false;
} }
} }
bool TempFileManager::DeleteFile(const std::string& storage_name) noexcept bool TempFileManager::DeleteFile(const std::string& storage_name) noexcept
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
if (it == file_map.end()) if (it == pimpl->file_map.end())
{ {
SCLOGF_WARNING("DeleteFile({}) Failed: File Not Exists", storage_name); SCLOGF_WARNING("DeleteFile({}) Failed: File Not Exists", storage_name);
return false; return false;
} }
std::error_code ec; 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) if (ec)
SCLOGF_WARNING("DeleteFile({}) Failed: {}({})", storage_name, ec.value(), ec.message()); SCLOGF_WARNING("DeleteFile({}) Failed: {}({})", storage_name, ec.value(), ec.message());
else else
SCLOGF_INFO("DeleteFile({}) Success", storage_name); SCLOGF_INFO("DeleteFile({}) Success", storage_name);
if (ec) if (ec)
return false; return false;
file_map.erase(it); pimpl->file_map.erase(it);
return true; return true;
} }
bool TempFileManager::ActiveFile(const std::string& storage_name) noexcept bool TempFileManager::ActiveFile(const std::string& storage_name) noexcept
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
if ((it == file_map.end()) || it->second.is_active) 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")); SCLOGF_WARNING("ActiveFile({}) Failed: {}", storage_name, (it->second.is_active ? "Already Actived" : "File Not Exists"));
return false; return false;
@@ -291,11 +323,11 @@ bool TempFileManager::ActiveFile(const std::string& storage_name) noexcept
bool TempFileManager::DeactiveFile(const std::string& storage_name) noexcept bool TempFileManager::DeactiveFile(const std::string& storage_name) noexcept
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
if ((it == file_map.end()) || !it->second.is_active) 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; return false;
} }
it->second.is_active = 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 bool TempFileManager::SetPermanent(const std::string& storage_name, bool permanent) noexcept
{ {
std::unique_lock lock(rw_mutex); std::unique_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
if (it == file_map.end()) if (it == pimpl->file_map.end())
{ {
SCLOGF_WARNING("SetPermanent({}) Failed: File Not Exists", storage_name); SCLOGF_WARNING("SetPermanent({}) Failed: File Not Exists", storage_name);
return false; 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 bool TempFileManager::FileExists(const std::string& storage_name) const noexcept
{ {
std::shared_lock lock(rw_mutex); std::shared_lock lock(pimpl->rw_mutex);
return file_map.contains(storage_name); return pimpl->file_map.contains(storage_name);
} }
bool TempFileManager::GetFileInfo(const std::string& storage_name, WebFileInfo& out_info) const noexcept bool TempFileManager::GetFileInfo(const std::string& storage_name, WebFileInfo& out_info) const noexcept
{ {
try try
{ {
std::shared_lock lock(rw_mutex); std::shared_lock lock(pimpl->rw_mutex);
auto it = file_map.find(storage_name); auto it = pimpl->file_map.find(storage_name);
if (it == file_map.end()) if (it == pimpl->file_map.end())
return false; return false;
out_info = it->second.info; out_info = it->second.info;
return true; return true;
} }
catch (...) catch (...)
{ {
SCLOGF_INFO("GetFileInfo({}) Failed: Exception", storage_name); SCLOGF_WARNING("GetFileInfo({}) Failed: Exception", storage_name);
return false; return false;
} }
} }
size_t TempFileManager::GetFileCount() const noexcept size_t TempFileManager::GetFileCount() const noexcept
{ {
return file_map.size(); return pimpl->file_map.size();
} }
std::vector<WebFileInfo> TempFileManager::GetAllFileInfos() const noexcept std::vector<WebFileInfo> TempFileManager::GetAllFileInfos() const noexcept
@@ -352,9 +384,9 @@ std::vector<WebFileInfo> TempFileManager::GetAllFileInfos() const noexcept
std::vector<WebFileInfo> list; std::vector<WebFileInfo> list;
try try
{ {
std::shared_lock lock(rw_mutex); // 申请读锁,支持高并发并发读取 std::shared_lock lock(pimpl->rw_mutex); // 申请读锁,支持高并发并发读取
list.reserve(file_map.size()); // 提前预留空间,减少内存重分配次数 list.reserve(pimpl->file_map.size()); // 提前预留空间,减少内存重分配次数
for (const auto& [_, fcb] : file_map) for (const auto& [_, fcb] : pimpl->file_map)
list.push_back(fcb.info); // 拷贝文件元数据到外部 list.push_back(fcb.info); // 拷贝文件元数据到外部
} }
catch (...) catch (...)
+3 -22
View File
@@ -1,12 +1,10 @@
#pragma once #pragma once
#include <map> #include <map>
#include <string> #include <string>
#include <thread>
#include <chrono> #include <chrono>
#include <memory>
#include "Export.h" #include "Export.h"
#include <shared_mutex>
#include "WebFileInfo.h" #include "WebFileInfo.h"
#include <unordered_map>
using std::chrono::operator""s; using std::chrono::operator""s;
using std::chrono::operator""min; using std::chrono::operator""min;
@@ -14,26 +12,9 @@ using std::chrono::operator""min;
class UNSWSC_DLL_EXPORT TempFileManager class UNSWSC_DLL_EXPORT TempFileManager
{ {
private: private:
struct FileControlBlock class Impl;
{
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::unique_ptr<Impl> pimpl;
std::unordered_map<std::string, FileControlBlock> file_map;
mutable std::shared_mutex rw_mutex;
// C++20 jthread
std::jthread cleanup_thread;
void CleanupLoop(std::stop_token st) noexcept;
public: public:
TempFileManager() noexcept; TempFileManager() noexcept;