123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- #pragma once
- #include "public.h"
- #include "ref.h"
- #include <library/cpp/yt/misc/port.h>
- #include <util/generic/size_literals.h>
- 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 <class TDerived>
- 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<TAllocationHolder> 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 <class TTag>
- 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 <class T>
- T* AllocateUninitialized(int n, int align = alignof(T));
- //! Allocates space and copies #src inside it.
- template <class T>
- TMutableRange<T> Capture(TRange<T> 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 use case 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<std::unique_ptr<TAllocationHolder>> Chunks_;
- std::vector<std::unique_ptr<TAllocationHolder>> 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_
|