diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/filemap.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/filemap.h')
-rw-r--r-- | util/system/filemap.h | 381 |
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); + } +}; |