aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/filemap.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/filemap.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/filemap.h')
-rw-r--r--util/system/filemap.h381
1 files changed, 381 insertions, 0 deletions
diff --git a/util/system/filemap.h b/util/system/filemap.h
new file mode 100644
index 0000000000..11be64bff4
--- /dev/null
+++ b/util/system/filemap.h
@@ -0,0 +1,381 @@
+#pragma once
+
+#include "file.h"
+#include "align.h"
+#include "yassert.h"
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+#include <util/generic/flags.h>
+#include <util/generic/string.h>
+
+#include <new>
+#include <cstdio>
+
+namespace NPrivate {
+ // NB: use TFileMap::Precharge() and TFileMappedArray::Prechage()
+ void Precharge(const void* data, size_t dataSize, size_t offset, size_t size);
+}
+
+struct TMemoryMapCommon {
+ struct TMapResult {
+ inline size_t MappedSize() const noexcept {
+ return Size - Head;
+ }
+
+ inline void* MappedData() const noexcept {
+ return Ptr ? (void*)((char*)Ptr + Head) : nullptr;
+ }
+
+ inline bool IsMapped() const noexcept {
+ return Ptr != nullptr;
+ }
+
+ inline void Reset() noexcept {
+ Ptr = nullptr;
+ Size = 0;
+ Head = 0;
+ }
+
+ void* Ptr;
+ size_t Size;
+ i32 Head;
+
+ TMapResult(void) noexcept {
+ Reset();
+ }
+ };
+
+ enum EOpenModeFlag {
+ oRdOnly = 1,
+ oRdWr = 2,
+ oCopyOnWr = 4,
+
+ oAccessMask = 7,
+ oNotGreedy = 8,
+ oPrecharge = 16,
+ oPopulate = 32, // Populate page table entries (see mmap's MAP_POPULATE)
+ };
+ Y_DECLARE_FLAGS(EOpenMode, EOpenModeFlag)
+
+ /**
+ * Name that will be printed in exceptions if not specified.
+ * Overridden by name obtained from `TFile` if it's not empty.
+ */
+ static TString UnknownFileName();
+};
+Y_DECLARE_OPERATORS_FOR_FLAGS(TMemoryMapCommon::EOpenMode)
+
+class TMemoryMap: public TMemoryMapCommon {
+public:
+ explicit TMemoryMap(const TString& name);
+ explicit TMemoryMap(const TString& name, EOpenMode om);
+ TMemoryMap(const TString& name, i64 length, EOpenMode om);
+ TMemoryMap(FILE* f, TString dbgName = UnknownFileName());
+ TMemoryMap(FILE* f, EOpenMode om, TString dbgName = UnknownFileName());
+ TMemoryMap(const TFile& file, TString dbgName = UnknownFileName());
+ TMemoryMap(const TFile& file, EOpenMode om, TString dbgName = UnknownFileName());
+
+ ~TMemoryMap();
+
+ TMapResult Map(i64 offset, size_t size);
+ bool Unmap(TMapResult region);
+
+ void ResizeAndReset(i64 size);
+ TMapResult ResizeAndRemap(i64 offset, size_t size);
+
+ i64 Length() const noexcept;
+ bool IsOpen() const noexcept;
+ bool IsWritable() const noexcept;
+ EOpenMode GetMode() const noexcept;
+ TFile GetFile() const noexcept;
+
+ void SetSequential();
+ void Evict(void* ptr, size_t len);
+ void Evict();
+
+ /*
+ * deprecated
+ */
+ bool Unmap(void* ptr, size_t size);
+
+private:
+ class TImpl;
+ TSimpleIntrusivePtr<TImpl> Impl_;
+};
+
+class TFileMap: public TMemoryMapCommon {
+public:
+ TFileMap(const TMemoryMap& map) noexcept;
+ TFileMap(const TString& name);
+ TFileMap(const TString& name, EOpenMode om);
+ TFileMap(const TString& name, i64 length, EOpenMode om);
+ TFileMap(FILE* f, EOpenMode om = oRdOnly, TString dbgName = UnknownFileName());
+ TFileMap(const TFile& file, EOpenMode om = oRdOnly, TString dbgName = UnknownFileName());
+ TFileMap(const TFileMap& fm) noexcept;
+
+ ~TFileMap();
+
+ TMapResult Map(i64 offset, size_t size);
+ TMapResult ResizeAndRemap(i64 offset, size_t size);
+ void Unmap();
+
+ void Flush(void* ptr, size_t size) {
+ Flush(ptr, size, true);
+ }
+
+ void Flush() {
+ Flush(Ptr(), MappedSize());
+ }
+
+ void FlushAsync(void* ptr, size_t size) {
+ Flush(ptr, size, false);
+ }
+
+ void FlushAsync() {
+ FlushAsync(Ptr(), MappedSize());
+ }
+
+ inline i64 Length() const noexcept {
+ return Map_.Length();
+ }
+
+ inline bool IsOpen() const noexcept {
+ return Map_.IsOpen();
+ }
+
+ inline bool IsWritable() const noexcept {
+ return Map_.IsWritable();
+ }
+
+ EOpenMode GetMode() const noexcept {
+ return Map_.GetMode();
+ }
+
+ inline void* Ptr() const noexcept {
+ return Region_.MappedData();
+ }
+
+ inline size_t MappedSize() const noexcept {
+ return Region_.MappedSize();
+ }
+
+ TFile GetFile() const noexcept {
+ return Map_.GetFile();
+ }
+
+ void Precharge(size_t pos = 0, size_t size = (size_t)-1) const;
+
+ void SetSequential() {
+ Map_.SetSequential();
+ }
+
+ void Evict() {
+ Map_.Evict();
+ }
+
+private:
+ void Flush(void* ptr, size_t size, bool sync);
+
+ TMemoryMap Map_;
+ TMapResult Region_;
+};
+
+template <class T>
+class TFileMappedArray {
+private:
+ const T* Ptr_;
+ const T* End_;
+ size_t Size_;
+ char DummyData_[sizeof(T) + PLATFORM_DATA_ALIGN];
+ mutable THolder<T, TDestructor> Dummy_;
+ THolder<TFileMap> DataHolder_;
+
+public:
+ TFileMappedArray()
+ : Ptr_(nullptr)
+ , End_(nullptr)
+ , Size_(0)
+ {
+ }
+ ~TFileMappedArray() {
+ Ptr_ = nullptr;
+ End_ = nullptr;
+ }
+ void Init(const char* name) {
+ DataHolder_.Reset(new TFileMap(name));
+ DoInit(name);
+ }
+ void Init(const TFileMap& fileMap) {
+ DataHolder_.Reset(new TFileMap(fileMap));
+ DoInit(fileMap.GetFile().GetName());
+ }
+ void Term() {
+ DataHolder_.Destroy();
+ Ptr_ = nullptr;
+ Size_ = 0;
+ End_ = nullptr;
+ }
+ void Precharge() {
+ DataHolder_->Precharge();
+ }
+ const T& operator[](size_t pos) const {
+ Y_ASSERT(pos < size());
+ return Ptr_[pos];
+ }
+ /// for STL compatibility only, Size() usage is recommended
+ size_t size() const {
+ return Size_;
+ }
+ size_t Size() const {
+ return Size_;
+ }
+ const T& GetAt(size_t pos) const {
+ if (pos < Size_)
+ return Ptr_[pos];
+ return Dummy();
+ }
+ void SetDummy(const T& n_Dummy) {
+ Dummy_.Destroy();
+ Dummy_.Reset(new (DummyData()) T(n_Dummy));
+ }
+ inline char* DummyData() const noexcept {
+ return AlignUp((char*)DummyData_);
+ }
+ inline const T& Dummy() const {
+ if (!Dummy_) {
+ Dummy_.Reset(new (DummyData()) T());
+ }
+
+ return *Dummy_;
+ }
+ /// for STL compatibility only, Empty() usage is recommended
+ Y_PURE_FUNCTION bool empty() const noexcept {
+ return Empty();
+ }
+
+ Y_PURE_FUNCTION bool Empty() const noexcept {
+ return 0 == Size_;
+ }
+ /// for STL compatibility only, Begin() usage is recommended
+ const T* begin() const noexcept {
+ return Begin();
+ }
+ const T* Begin() const noexcept {
+ return Ptr_;
+ }
+ /// for STL compatibility only, End() usage is recommended
+ const T* end() const noexcept {
+ return End_;
+ }
+ const T* End() const noexcept {
+ return End_;
+ }
+
+private:
+ void DoInit(const TString& fileName) {
+ DataHolder_->Map(0, DataHolder_->Length());
+ if (DataHolder_->Length() % sizeof(T)) {
+ Term();
+ ythrow yexception() << "Incorrect size of file " << fileName.Quote();
+ }
+ Ptr_ = (const T*)DataHolder_->Ptr();
+ Size_ = DataHolder_->Length() / sizeof(T);
+ End_ = Ptr_ + Size_;
+ }
+};
+
+class TMappedAllocation: TMoveOnly {
+public:
+ TMappedAllocation(size_t size = 0, bool shared = false, void* addr = nullptr);
+ ~TMappedAllocation() {
+ Dealloc();
+ }
+ TMappedAllocation(TMappedAllocation&& other) {
+ this->swap(other);
+ }
+ TMappedAllocation& operator=(TMappedAllocation&& other) {
+ this->swap(other);
+ return *this;
+ }
+ void* Alloc(size_t size, void* addr = nullptr);
+ void Dealloc();
+ void* Ptr() const {
+ return Ptr_;
+ }
+ char* Data(ui32 pos = 0) const {
+ return (char*)(Ptr_ ? ((char*)Ptr_ + pos) : nullptr);
+ }
+ char* Begin() const noexcept {
+ return (char*)Ptr();
+ }
+ char* End() const noexcept {
+ return Begin() + MappedSize();
+ }
+ size_t MappedSize() const {
+ return Size_;
+ }
+ void swap(TMappedAllocation& with);
+
+private:
+ void* Ptr_ = nullptr;
+ size_t Size_ = 0;
+ bool Shared_ = false;
+#ifdef _win_
+ void* Mapping_ = nullptr;
+#endif
+};
+
+template <class T>
+class TMappedArray: private TMappedAllocation {
+public:
+ TMappedArray(size_t siz = 0)
+ : TMappedAllocation(0)
+ {
+ if (siz)
+ Create(siz);
+ }
+ ~TMappedArray() {
+ Destroy();
+ }
+ T* Create(size_t siz) {
+ Y_ASSERT(MappedSize() == 0 && Ptr() == nullptr);
+ T* arr = (T*)Alloc((sizeof(T) * siz));
+ if (!arr)
+ return nullptr;
+ Y_ASSERT(MappedSize() == sizeof(T) * siz);
+ for (size_t n = 0; n < siz; n++)
+ new (&arr[n]) T();
+ return arr;
+ }
+ void Destroy() {
+ T* arr = (T*)Ptr();
+ if (arr) {
+ for (size_t n = 0; n < size(); n++)
+ arr[n].~T();
+ Dealloc();
+ }
+ }
+ T& operator[](size_t pos) {
+ Y_ASSERT(pos < size());
+ return ((T*)Ptr())[pos];
+ }
+ const T& operator[](size_t pos) const {
+ Y_ASSERT(pos < size());
+ return ((T*)Ptr())[pos];
+ }
+ T* begin() {
+ return (T*)Ptr();
+ }
+ T* end() {
+ return (T*)((char*)Ptr() + MappedSize());
+ }
+ size_t size() const {
+ return MappedSize() / sizeof(T);
+ }
+ void swap(TMappedArray<T>& with) {
+ TMappedAllocation::swap(with);
+ }
+};