Refactor concurrency handling and file operations for improved performance and thread safety
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
#include "sweepstore/utils/file_handle.h"
|
||||
|
||||
// Constructor
|
||||
// Constructor - just stores path and mode, actual stream is created per-thread
|
||||
SweepstoreFileHandle::SweepstoreFileHandle(const std::string& p, std::ios::openmode mode)
|
||||
: path(p)
|
||||
, openMode(mode)
|
||||
#ifdef WITH_UNREAL
|
||||
{
|
||||
IPlatformFile& platformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
@@ -24,11 +25,30 @@ SweepstoreFileHandle::SweepstoreFileHandle(const std::string& p, std::ios::openm
|
||||
}
|
||||
}
|
||||
#else
|
||||
, stream(std::make_unique<std::fstream>(p, mode))
|
||||
{
|
||||
if (!stream->is_open()) {
|
||||
throw std::runtime_error("Failed to open file: " + path);
|
||||
// Thread-local streams created on demand in getThreadStream()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WITH_UNREAL
|
||||
// Get or create the fstream for this thread
|
||||
std::fstream& SweepstoreFileHandle::getThreadStream() {
|
||||
auto it = streamCache.find(path);
|
||||
if (it == streamCache.end() || !it->second || !it->second->is_open()) {
|
||||
// Create new stream for this thread
|
||||
auto stream = std::make_unique<std::fstream>(path, openMode);
|
||||
if (!stream->is_open()) {
|
||||
throw std::runtime_error("Failed to open file: " + path);
|
||||
}
|
||||
streamCache[path] = std::move(stream);
|
||||
return *streamCache[path];
|
||||
}
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
const std::fstream& SweepstoreFileHandle::getThreadStream() const {
|
||||
// Use const_cast to reuse the non-const version
|
||||
return const_cast<SweepstoreFileHandle*>(this)->getThreadStream();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -37,7 +57,8 @@ bool SweepstoreFileHandle::isOpen() const {
|
||||
#ifdef WITH_UNREAL
|
||||
return unrealHandle != nullptr;
|
||||
#else
|
||||
return stream && stream->is_open();
|
||||
auto it = streamCache.find(path);
|
||||
return it != streamCache.end() && it->second && it->second->is_open();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -49,8 +70,10 @@ void SweepstoreFileHandle::close() {
|
||||
unrealHandle = nullptr;
|
||||
}
|
||||
#else
|
||||
if (stream) {
|
||||
stream->close();
|
||||
// Close this thread's stream if it exists
|
||||
auto it = streamCache.find(path);
|
||||
if (it != streamCache.end() && it->second && it->second->is_open()) {
|
||||
it->second->close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -63,11 +86,10 @@ void SweepstoreFileHandle::flush() {
|
||||
unrealHandle->Flush();
|
||||
}
|
||||
#else
|
||||
if (stream) {
|
||||
stream->flush();
|
||||
// On Windows, also sync to ensure data hits disk
|
||||
stream->sync();
|
||||
}
|
||||
auto& stream = getThreadStream();
|
||||
stream.flush();
|
||||
// On Windows, also sync to ensure data hits disk
|
||||
stream.sync();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -85,13 +107,14 @@ void SweepstoreFileHandle::readSeek(std::streampos pos, std::ios::seekdir dir) {
|
||||
}
|
||||
#else
|
||||
// Windows
|
||||
auto& stream = getThreadStream();
|
||||
// On Windows, flush and sync to disk, then invalidate buffers
|
||||
stream->flush();
|
||||
stream->sync();
|
||||
stream->clear();
|
||||
stream.flush();
|
||||
stream.sync();
|
||||
stream.clear();
|
||||
// Sync both pointers to same position
|
||||
stream->seekp(pos, dir);
|
||||
stream->seekg(pos, dir);
|
||||
stream.seekp(pos, dir);
|
||||
stream.seekg(pos, dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -102,9 +125,10 @@ void SweepstoreFileHandle::writeSeek(std::streampos pos, std::ios::seekdir dir)
|
||||
readSeek(pos, dir);
|
||||
#else
|
||||
// Windows
|
||||
stream->flush();
|
||||
stream->sync();
|
||||
stream->seekp(pos, dir);
|
||||
auto& stream = getThreadStream();
|
||||
stream.flush();
|
||||
stream.sync();
|
||||
stream.seekp(pos, dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -114,10 +138,11 @@ void SweepstoreFileHandle::readBytes(char* buffer, std::streamsize size) {
|
||||
unrealHandle->Read(reinterpret_cast<uint8*>(buffer), size);
|
||||
#else
|
||||
// Windows
|
||||
stream->read(buffer, size);
|
||||
auto& stream = getThreadStream();
|
||||
stream.read(buffer, size);
|
||||
// Check for read errors on Windows
|
||||
if (stream->fail() && !stream->eof()) {
|
||||
stream->clear();
|
||||
if (stream.fail() && !stream.eof()) {
|
||||
stream.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -129,10 +154,11 @@ void SweepstoreFileHandle::writeBytes(const char* buffer, std::streamsize size)
|
||||
unrealHandle->Flush(); // Unreal requires explicit flush
|
||||
#else
|
||||
// Windows
|
||||
stream->write(buffer, size);
|
||||
auto& stream = getThreadStream();
|
||||
stream.write(buffer, size);
|
||||
// Check for write errors on Windows
|
||||
if (stream->fail()) {
|
||||
stream->clear();
|
||||
if (stream.fail()) {
|
||||
stream.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user