Optimize pack file loading

- Add thread-local ZSTD decompression context reuse
- Integrate BufferPool for temporary buffers
- PackManager auto-uses BufferPool for all GetFile calls
- Thread-safe pack loading with mutex
This commit is contained in:
savis
2026-01-03 20:37:32 +01:00
parent 0958ea6214
commit e55fc4db17
4 changed files with 78 additions and 7 deletions

View File

@@ -1,6 +1,18 @@
#include "Pack.h" #include "Pack.h"
#include "EterLib/BufferPool.h"
#include <zstd.h> #include <zstd.h>
static thread_local ZSTD_DCtx* g_zstdDCtx = nullptr;
static ZSTD_DCtx* GetThreadLocalZSTDContext()
{
if (!g_zstdDCtx)
{
g_zstdDCtx = ZSTD_createDCtx();
}
return g_zstdDCtx;
}
bool CPack::Open(const std::string& path, TPackFileMap& entries) bool CPack::Open(const std::string& path, TPackFileMap& entries)
{ {
std::error_code ec; std::error_code ec;
@@ -38,27 +50,44 @@ bool CPack::Open(const std::string& path, TPackFileMap& entries)
} }
bool CPack::GetFile(const TPackFileEntry& entry, TPackFile& result) bool CPack::GetFile(const TPackFileEntry& entry, TPackFile& result)
{
return GetFileWithPool(entry, result, nullptr);
}
bool CPack::GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool)
{ {
result.resize(entry.file_size); result.resize(entry.file_size);
size_t offset = m_header.data_begin + entry.offset; size_t offset = m_header.data_begin + entry.offset;
ZSTD_DCtx* dctx = GetThreadLocalZSTDContext();
switch (entry.encryption) switch (entry.encryption)
{ {
case 0: { case 0: {
size_t decompressed_size = ZSTD_decompress(result.data(), result.size(), m_file.data() + offset, entry.compressed_size); size_t decompressed_size = ZSTD_decompressDCtx(dctx, result.data(), result.size(), m_file.data() + offset, entry.compressed_size);
if (decompressed_size != entry.file_size) { if (decompressed_size != entry.file_size) {
return false; return false;
} }
} break; } break;
case 1: { case 1: {
std::vector<uint8_t> compressed_data(entry.compressed_size); std::vector<uint8_t> compressed_data;
if (pPool) {
compressed_data = pPool->Acquire(entry.compressed_size);
}
compressed_data.resize(entry.compressed_size);
memcpy(compressed_data.data(), m_file.data() + offset, entry.compressed_size); memcpy(compressed_data.data(), m_file.data() + offset, entry.compressed_size);
m_decryption.Resynchronize(entry.iv, sizeof(entry.iv)); m_decryption.Resynchronize(entry.iv, sizeof(entry.iv));
m_decryption.ProcessData(compressed_data.data(), compressed_data.data(), entry.compressed_size); m_decryption.ProcessData(compressed_data.data(), compressed_data.data(), entry.compressed_size);
size_t decompressed_size = ZSTD_decompress(result.data(), result.size(), compressed_data.data(), compressed_data.size()); size_t decompressed_size = ZSTD_decompressDCtx(dctx, result.data(), result.size(), compressed_data.data(), compressed_data.size());
if (pPool) {
pPool->Release(std::move(compressed_data));
}
if (decompressed_size != entry.file_size) { if (decompressed_size != entry.file_size) {
return false; return false;
} }

View File

@@ -4,6 +4,8 @@
#include "config.h" #include "config.h"
class CBufferPool;
class CPack : public std::enable_shared_from_this<CPack> class CPack : public std::enable_shared_from_this<CPack>
{ {
public: public:
@@ -12,6 +14,7 @@ public:
bool Open(const std::string& path, TPackFileMap& entries); bool Open(const std::string& path, TPackFileMap& entries);
bool GetFile(const TPackFileEntry& entry, TPackFile& result); bool GetFile(const TPackFileEntry& entry, TPackFile& result);
bool GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool);
private: private:
TPackFileHeader m_header; TPackFileHeader m_header;

View File

@@ -1,14 +1,38 @@
#include "PackManager.h" #include "PackManager.h"
#include "EterLib/BufferPool.h"
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
CPackManager::CPackManager()
: m_load_from_pack(true)
, m_pBufferPool(nullptr)
{
m_pBufferPool = new CBufferPool();
}
CPackManager::~CPackManager()
{
if (m_pBufferPool)
{
delete m_pBufferPool;
m_pBufferPool = nullptr;
}
}
bool CPackManager::AddPack(const std::string& path) bool CPackManager::AddPack(const std::string& path)
{ {
std::shared_ptr<CPack> pack = std::make_shared<CPack>(); std::shared_ptr<CPack> pack = std::make_shared<CPack>();
std::lock_guard<std::mutex> lock(m_mutex);
return pack->Open(path, m_entries); return pack->Open(path, m_entries);
} }
bool CPackManager::GetFile(std::string_view path, TPackFile& result) bool CPackManager::GetFile(std::string_view path, TPackFile& result)
{
return GetFileWithPool(path, result, m_pBufferPool);
}
bool CPackManager::GetFileWithPool(std::string_view path, TPackFile& result, CBufferPool* pPool)
{ {
thread_local std::string buf; thread_local std::string buf;
NormalizePath(path, buf); NormalizePath(path, buf);
@@ -16,7 +40,7 @@ bool CPackManager::GetFile(std::string_view path, TPackFile& result)
if (m_load_from_pack) { if (m_load_from_pack) {
auto it = m_entries.find(buf); auto it = m_entries.find(buf);
if (it != m_entries.end()) { if (it != m_entries.end()) {
return it->second.first->GetFile(it->second.second, result); return it->second.first->GetFileWithPool(it->second.second, result, pPool);
} }
} }
else { else {
@@ -25,7 +49,14 @@ bool CPackManager::GetFile(std::string_view path, TPackFile& result)
ifs.seekg(0, std::ios::end); ifs.seekg(0, std::ios::end);
size_t size = ifs.tellg(); size_t size = ifs.tellg();
ifs.seekg(0, std::ios::beg); ifs.seekg(0, std::ios::beg);
result.resize(size);
if (pPool) {
result = pPool->Acquire(size);
result.resize(size);
} else {
result.resize(size);
}
if (ifs.read((char*)result.data(), size)) { if (ifs.read((char*)result.data(), size)) {
return true; return true;
} }

View File

@@ -1,26 +1,34 @@
#pragma once #pragma once
#include <unordered_map> #include <unordered_map>
#include <mutex>
#include "EterBase/Singleton.h" #include "EterBase/Singleton.h"
#include "Pack.h" #include "Pack.h"
class CBufferPool;
class CPackManager : public CSingleton<CPackManager> class CPackManager : public CSingleton<CPackManager>
{ {
public: public:
CPackManager() = default; CPackManager();
virtual ~CPackManager() = default; virtual ~CPackManager();
bool AddPack(const std::string& path); bool AddPack(const std::string& path);
bool GetFile(std::string_view path, TPackFile& result); bool GetFile(std::string_view path, TPackFile& result);
bool GetFileWithPool(std::string_view path, TPackFile& result, CBufferPool* pPool);
bool IsExist(std::string_view path) const; bool IsExist(std::string_view path) const;
void SetPackLoadMode() { m_load_from_pack = true; } void SetPackLoadMode() { m_load_from_pack = true; }
void SetFileLoadMode() { m_load_from_pack = false; } void SetFileLoadMode() { m_load_from_pack = false; }
CBufferPool* GetBufferPool() { return m_pBufferPool; }
private: private:
void NormalizePath(std::string_view in, std::string& out) const; void NormalizePath(std::string_view in, std::string& out) const;
private: private:
bool m_load_from_pack = true; bool m_load_from_pack = true;
TPackFileMap m_entries; TPackFileMap m_entries;
CBufferPool* m_pBufferPool;
mutable std::mutex m_mutex; // Thread safety for parallel pack loading
}; };