#pragma once #include "public.h" #include "ref.h" #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// struct TDefaultChunkedMemoryPoolTag { }; // TAllocationHolder is polymorphic. So we cannot use TWithExtraSpace mixin // because it needs the most derived type as a template argument and // it would require GetExtraSpacePtr/GetRef methods to be virtual. class TAllocationHolder { public: TAllocationHolder(TMutableRef ref, TRefCountedTypeCookie cookie); TAllocationHolder(const TAllocationHolder&) = delete; TAllocationHolder(TAllocationHolder&&) = default; virtual ~TAllocationHolder(); void operator delete(void* ptr) noexcept; TMutableRef GetRef() const; template static TDerived* Allocate(size_t size, TRefCountedTypeCookie cookie); private: const TMutableRef Ref_; #ifdef YT_ENABLE_REF_COUNTED_TRACKING const TRefCountedTypeCookie Cookie_; #endif }; //////////////////////////////////////////////////////////////////////////////// struct IMemoryChunkProvider : public TRefCounted { virtual std::unique_ptr Allocate(size_t size, TRefCountedTypeCookie cookie) = 0; }; DEFINE_REFCOUNTED_TYPE(IMemoryChunkProvider) const IMemoryChunkProviderPtr& GetDefaultMemoryChunkProvider(); //////////////////////////////////////////////////////////////////////////////// class TChunkedMemoryPool : private TNonCopyable { public: static constexpr size_t DefaultStartChunkSize = 4_KB; static constexpr size_t RegularChunkSize = 36_KB - 512; TChunkedMemoryPool( TRefCountedTypeCookie tagCookie, IMemoryChunkProviderPtr chunkProvider, size_t startChunkSize = DefaultStartChunkSize); explicit TChunkedMemoryPool( TRefCountedTypeCookie tagCookie, size_t startChunkSize = DefaultStartChunkSize); TChunkedMemoryPool(); template explicit TChunkedMemoryPool( TTag, size_t startChunkSize = DefaultStartChunkSize); //! Allocates #sizes bytes without any alignment. char* AllocateUnaligned(size_t size); //! Allocates #size bytes aligned with 8-byte granularity. char* AllocateAligned(size_t size, int align = 8); //! Allocates #n uninitialized instances of #T. template T* AllocateUninitialized(int n, int align = alignof(T)); //! Allocates space and copies #src inside it. template TMutableRange Capture(TRange src, int align = alignof(T)); //! Frees memory range if possible: namely, if the free region is a suffix of last allocated region. void Free(char* from, char* to); //! Marks all previously allocated small chunks as free for subsequent allocations but //! does not deallocate them. //! Purges all large blocks. void Clear(); //! Purges all allocated memory, including small chunks. void Purge(); //! Returns the number of allocated bytes. size_t GetSize() const; //! Returns the number of reserved bytes. size_t GetCapacity() const; //! Returns the number of bytes that can be acquired in the current chunk //! without additional allocations. size_t GetCurrentChunkSpareSize() const; //! Moves all the allocated memory from other memory pool to the current one. //! The other pool becomes empty, like after Purge() call. void Absorb(TChunkedMemoryPool&& other); private: const TRefCountedTypeCookie TagCookie_; // A common usecase is to construct TChunkedMemoryPool with the default // memory chunk provider. The latter is ref-counted and is shared between // a multitude of TChunkedMemoryPool instances. This could potentially // lead to a contention over IMemoryChunkProvider's ref-counter. // To circumvent this, we keep both an owning (#ChunkProviderHolder_) and // a non-owning (#ChunkProvider_) reference to the underlying provider. // In case of the default chunk provider, the owning reference is not used. const IMemoryChunkProviderPtr ChunkProviderHolder_; IMemoryChunkProvider* const ChunkProvider_; int NextChunkIndex_ = 0; size_t NextSmallSize_; size_t Size_ = 0; size_t Capacity_ = 0; // Chunk memory layout: // |AAAA|....|UUUU| // Legend: // A aligned allocations // U unaligned allocations // . free zone char* FreeZoneBegin_; char* FreeZoneEnd_; std::vector> Chunks_; std::vector> OtherBlocks_; void Initialize(size_t startChunkSize); char* AllocateUnalignedSlow(size_t size); char* AllocateAlignedSlow(size_t size, int align); char* AllocateSlowCore(size_t size); }; //////////////////////////////////////////////////////////////////////////////// } // namespace NYT #define CHUNKED_MEMORY_POOL_INL_H_ #include "chunked_memory_pool-inl.h" #undef CHUNKED_MEMORY_POOL_INL_H_