website/docs/dev/tsavorite/object-allocator.md
The ObjectAllocator replaces the GenericAllocator to provide two important improvements:
ReadOnlySpan<byte> keys. With this change Tsavorite now uses only ReadOnlySpan<byte> keys; the Garnet processing layer uses PinnedSpanByte keys initially, which are converted to ReadOnlySpan<byte> at the GarnetApi/StorageSession boundary. (The GenericAllocator did not support SpanByte keys.)GenericAllocator with native allocations for the log pages, exactly like SpanByteAllocator.Tsavorite provides two primary allocators:
TsavoriteKV that uses a SpanByteAllocator.TsavoriteKV that uses an ObjectAllocator. This is also the "unified allocator" used by Garnet.The former BlittableAllocator is now the TsavoriteLogAllocator, used only by the TsavoriteLog.
One big difference between the two is that SpanByteAllocator allows larger pages for strings, while ObjectAllocator allows using a smaller page size because objects use only 4 byte identifiers in the inline log record. Thus, the page size can be much smaller, allowing finer control over Object size tracking and memory-budget enforcement. Either allocator can also set the Key and Value max inline sizes to cause the field to be stored in an overflow allocation, although this is less performant.
ObjectAllocator supports two log files simlarly to GenericAllocator. However, GenericAllocator was limited to a fixed 100MB buffer size for object serialization. ObjectAllocator uses a circular buffer system, currently 4 buffers of 4MB each, and writes one to disk while populating the next (or reads the following buffers from disk while processing the current one, e.g. deserializing objects.
The key points in the code here are AsyncWrite, AsyncRead, AsyncGetFromDisk, and iterators. The basic flow is:
When we serialize a LogRecord to disk, as we write the object log file we also modify the disk-image of the LogRecord (but, importantly, do not modify the length of the logRecord, to keep the LogicalAddress space consistent) to maintain a "pointer" and length in the ObjectLog file:
ObjectLogPosition field, giving a total of 40 bits or 1 TB of address for a single object, and 72 PB for the entire object log.The ObjectAllocator carries a second ObjectIdMap, a transient one intended for IO and iterator and pending operations. (These are the same scenarios that embed a LogRecord into a DiskLogRecord.) In these cases we remap the ObjectIds in the temporary image to use the TransientObjectIdMap, so pages can be evicted and their ObjectIdMaps reused.