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:
@@ -1,6 +1,18 @@
|
||||
#include "Pack.h"
|
||||
#include "EterLib/BufferPool.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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return GetFileWithPool(entry, result, nullptr);
|
||||
}
|
||||
|
||||
bool CPack::GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool)
|
||||
{
|
||||
result.resize(entry.file_size);
|
||||
|
||||
size_t offset = m_header.data_begin + entry.offset;
|
||||
ZSTD_DCtx* dctx = GetThreadLocalZSTDContext();
|
||||
|
||||
switch (entry.encryption)
|
||||
{
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
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);
|
||||
|
||||
m_decryption.Resynchronize(entry.iv, sizeof(entry.iv));
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
class CBufferPool;
|
||||
|
||||
class CPack : public std::enable_shared_from_this<CPack>
|
||||
{
|
||||
public:
|
||||
@@ -12,6 +14,7 @@ public:
|
||||
|
||||
bool Open(const std::string& path, TPackFileMap& entries);
|
||||
bool GetFile(const TPackFileEntry& entry, TPackFile& result);
|
||||
bool GetFileWithPool(const TPackFileEntry& entry, TPackFile& result, CBufferPool* pPool);
|
||||
|
||||
private:
|
||||
TPackFileHeader m_header;
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
#include "PackManager.h"
|
||||
#include "EterLib/BufferPool.h"
|
||||
#include <fstream>
|
||||
#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)
|
||||
{
|
||||
std::shared_ptr<CPack> pack = std::make_shared<CPack>();
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return pack->Open(path, m_entries);
|
||||
}
|
||||
|
||||
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;
|
||||
NormalizePath(path, buf);
|
||||
@@ -16,7 +40,7 @@ bool CPackManager::GetFile(std::string_view path, TPackFile& result)
|
||||
if (m_load_from_pack) {
|
||||
auto it = m_entries.find(buf);
|
||||
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 {
|
||||
@@ -25,7 +49,14 @@ bool CPackManager::GetFile(std::string_view path, TPackFile& result)
|
||||
ifs.seekg(0, std::ios::end);
|
||||
size_t size = ifs.tellg();
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
#include "EterBase/Singleton.h"
|
||||
#include "Pack.h"
|
||||
|
||||
class CBufferPool;
|
||||
|
||||
class CPackManager : public CSingleton<CPackManager>
|
||||
{
|
||||
public:
|
||||
CPackManager() = default;
|
||||
virtual ~CPackManager() = default;
|
||||
CPackManager();
|
||||
virtual ~CPackManager();
|
||||
|
||||
bool AddPack(const std::string& path);
|
||||
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;
|
||||
|
||||
void SetPackLoadMode() { m_load_from_pack = true; }
|
||||
void SetFileLoadMode() { m_load_from_pack = false; }
|
||||
|
||||
CBufferPool* GetBufferPool() { return m_pBufferPool; }
|
||||
|
||||
private:
|
||||
void NormalizePath(std::string_view in, std::string& out) const;
|
||||
|
||||
private:
|
||||
bool m_load_from_pack = true;
|
||||
TPackFileMap m_entries;
|
||||
CBufferPool* m_pBufferPool;
|
||||
mutable std::mutex m_mutex; // Thread safety for parallel pack loading
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user