Chunked mapped memory writer.
This commit is contained in:
parent
499bed21c0
commit
a38b05db24
|
@ -31,6 +31,8 @@ class MappedMemory {
|
||||||
uint8_t* data() const { return reinterpret_cast<uint8_t*>(data_); }
|
uint8_t* data() const { return reinterpret_cast<uint8_t*>(data_); }
|
||||||
size_t size() const { return size_; }
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
|
virtual void Flush() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MappedMemory(const std::wstring& path, Mode mode)
|
MappedMemory(const std::wstring& path, Mode mode)
|
||||||
: path_(path), mode_(mode), data_(nullptr), size_(0) {}
|
: path_(path), mode_(mode), data_(nullptr), size_(0) {}
|
||||||
|
@ -41,6 +43,25 @@ class MappedMemory {
|
||||||
size_t size_;
|
size_t size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ChunkedMappedMemoryWriter {
|
||||||
|
public:
|
||||||
|
virtual ~ChunkedMappedMemoryWriter() = default;
|
||||||
|
|
||||||
|
static std::unique_ptr<ChunkedMappedMemoryWriter> Open(
|
||||||
|
const std::wstring& path, size_t chunk_size);
|
||||||
|
|
||||||
|
virtual uint8_t* Allocate(size_t length) = 0;
|
||||||
|
virtual void Flush() = 0;
|
||||||
|
virtual void FlushNew() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ChunkedMappedMemoryWriter(const std::wstring& path, size_t chunk_size)
|
||||||
|
: path_(path), chunk_size_(chunk_size) {}
|
||||||
|
|
||||||
|
std::wstring path_;
|
||||||
|
size_t chunk_size_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
#endif // XENIA_BASE_MAPPED_MEMORY_H_
|
#endif // XENIA_BASE_MAPPED_MEMORY_H_
|
||||||
|
|
|
@ -11,6 +11,12 @@
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
class Win32MappedMemory : public MappedMemory {
|
class Win32MappedMemory : public MappedMemory {
|
||||||
|
@ -32,6 +38,10 @@ class Win32MappedMemory : public MappedMemory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Flush() override {
|
||||||
|
FlushViewOfFile(data(), size());
|
||||||
|
}
|
||||||
|
|
||||||
HANDLE file_handle;
|
HANDLE file_handle;
|
||||||
HANDLE mapping_handle;
|
HANDLE mapping_handle;
|
||||||
};
|
};
|
||||||
|
@ -61,11 +71,11 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(const std::wstring& path,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSTEM_INFO systemInfo;
|
SYSTEM_INFO system_info;
|
||||||
GetSystemInfo(&systemInfo);
|
GetSystemInfo(&system_info);
|
||||||
|
|
||||||
const size_t aligned_offset =
|
const size_t aligned_offset =
|
||||||
offset & ~static_cast<size_t>(systemInfo.dwAllocationGranularity - 1);
|
offset & ~static_cast<size_t>(system_info.dwAllocationGranularity - 1);
|
||||||
const size_t aligned_length = length + (offset - aligned_offset);
|
const size_t aligned_length = length + (offset - aligned_offset);
|
||||||
|
|
||||||
auto mm = std::make_unique<Win32MappedMemory>(path, mode);
|
auto mm = std::make_unique<Win32MappedMemory>(path, mode);
|
||||||
|
@ -102,4 +112,139 @@ std::unique_ptr<MappedMemory> MappedMemory::Open(const std::wstring& path,
|
||||||
return std::move(mm);
|
return std::move(mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Win32ChunkedMappedMemoryWriter : public ChunkedMappedMemoryWriter {
|
||||||
|
public:
|
||||||
|
Win32ChunkedMappedMemoryWriter(const std::wstring& path, size_t chunk_size)
|
||||||
|
: ChunkedMappedMemoryWriter(path, chunk_size) {}
|
||||||
|
|
||||||
|
~Win32ChunkedMappedMemoryWriter() override {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
chunks_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Allocate(size_t length) override {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
if (!chunks_.empty()) {
|
||||||
|
uint8_t* result = chunks_.back()->Allocate(length);
|
||||||
|
if (result != nullptr) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto chunk = std::make_unique<Chunk>(chunk_size_);
|
||||||
|
auto chunk_path = path_ + L"." + std::to_wstring(chunks_.size());
|
||||||
|
if (!chunk->Open(chunk_path)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
uint8_t* result = chunk->Allocate(length);
|
||||||
|
chunks_.push_back(std::move(chunk));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush() override {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
for (auto& chunk : chunks_) {
|
||||||
|
chunk->Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushNew() override {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
for (auto& chunk : chunks_) {
|
||||||
|
chunk->FlushNew();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Chunk {
|
||||||
|
public:
|
||||||
|
Chunk(size_t capacity)
|
||||||
|
: file_handle_(0),
|
||||||
|
mapping_handle_(0),
|
||||||
|
data_(nullptr),
|
||||||
|
offset_(0),
|
||||||
|
capacity_(capacity),
|
||||||
|
last_flush_offset_(0) {}
|
||||||
|
|
||||||
|
~Chunk() {
|
||||||
|
if (data_) {
|
||||||
|
UnmapViewOfFile(data_);
|
||||||
|
}
|
||||||
|
if (mapping_handle_) {
|
||||||
|
CloseHandle(mapping_handle_);
|
||||||
|
}
|
||||||
|
if (file_handle_) {
|
||||||
|
CloseHandle(file_handle_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Open(const std::wstring& path) {
|
||||||
|
DWORD file_access = GENERIC_READ | GENERIC_WRITE;
|
||||||
|
DWORD file_share = 0;
|
||||||
|
DWORD create_mode = OPEN_EXISTING;
|
||||||
|
DWORD mapping_protect = PAGE_READWRITE;
|
||||||
|
DWORD view_access = FILE_MAP_READ | FILE_MAP_WRITE;
|
||||||
|
|
||||||
|
file_handle_ = CreateFile(path.c_str(), file_access, file_share, nullptr,
|
||||||
|
create_mode, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (!file_handle_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping_handle_ =
|
||||||
|
CreateFileMapping(file_handle_, nullptr, mapping_protect, 0,
|
||||||
|
static_cast<DWORD>(capacity_), nullptr);
|
||||||
|
if (!mapping_handle_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_ = reinterpret_cast<uint8_t*>(
|
||||||
|
MapViewOfFile(mapping_handle_, view_access, 0, 0, capacity_));
|
||||||
|
if (!data_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Allocate(size_t length) {
|
||||||
|
if (capacity_ - offset_ < length) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
uint8_t* result = data_ + offset_;
|
||||||
|
offset_ += length;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush() {
|
||||||
|
FlushViewOfFile(data_, offset_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushNew() {
|
||||||
|
FlushViewOfFile(data_ + last_flush_offset_, offset_ - last_flush_offset_);
|
||||||
|
last_flush_offset_ = offset_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HANDLE file_handle_;
|
||||||
|
HANDLE mapping_handle_;
|
||||||
|
uint8_t* data_;
|
||||||
|
size_t offset_;
|
||||||
|
size_t capacity_;
|
||||||
|
size_t last_flush_offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::vector<std::unique_ptr<Chunk>> chunks_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<ChunkedMappedMemoryWriter> ChunkedMappedMemoryWriter::Open(
|
||||||
|
const std::wstring& path, size_t chunk_size) {
|
||||||
|
SYSTEM_INFO system_info;
|
||||||
|
GetSystemInfo(&system_info);
|
||||||
|
size_t aligned_chunk_size =
|
||||||
|
xe::round_up(chunk_size, system_info.dwAllocationGranularity);
|
||||||
|
return std::make_unique<Win32ChunkedMappedMemoryWriter>(path,
|
||||||
|
aligned_chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
Loading…
Reference in New Issue