blob: b65f4987276fb207fb393f42b27e43d3e375a408 (
plain) (
tree)
|
|
#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_
|