Skip to content

Add MMapAllocator for SSD-backed memory-mapped data allocation#302

Draft
ibhati wants to merge 7 commits intomainfrom
ib/ssd
Draft

Add MMapAllocator for SSD-backed memory-mapped data allocation#302
ibhati wants to merge 7 commits intomainfrom
ib/ssd

Conversation

@ibhati
Copy link
Copy Markdown
Member

@ibhati ibhati commented Mar 25, 2026

Add MMapAllocator that allocates memory via mmap-backed files on a configurable path (e.g. NVMe/SSD). This enables placing secondary data structures on SSD while keeping primary data in RAM, reducing heap memory usage for large-scale vector search.

  • include/svs/core/allocator_mmap.h: MMapAllocator with configurable base path, access hints (Sequential/Random/Normal), and automatic file cleanup on deallocation.
  • tests/svs/core/test_allocator_mmap.cpp: Unit tests for allocation, deallocation, file creation, and access hint propagation.
  • tests/CMakeLists.txt: Register mmap allocator test.

Add MMapAllocator that allocates memory via mmap-backed files on a
configurable path (e.g. NVMe/SSD). This enables placing secondary
data structures on SSD while keeping primary data in RAM, reducing
heap memory usage for large-scale vector search.

- include/svs/core/allocator_mmap.h: MMapAllocator with configurable
  base path, access hints (Sequential/Random/Normal), and automatic
  file cleanup on deallocation.
- tests/svs/core/test_allocator_mmap.cpp: Unit tests for allocation,
  deallocation, file creation, and access hint propagation.
- tests/CMakeLists.txt: Register mmap allocator test.
@ibhati ibhati requested review from razdoburdin and rfsaliev and removed request for razdoburdin and rfsaliev March 25, 2026 17:41
ibhati added 5 commits March 30, 2026 08:52
- Add map_existing_at_offset() to MMapAllocationManager for read-only
  file mapping with byte offset (skips file headers)
- Add use_existing_file() one-shot override to MMapAllocator so
  allocate() maps an existing binary file instead of creating a temp file
- Propagate override fields through copy constructor
- Enables zero-copy loading of saved index data without intermediate
  allocate-copy cycles, significantly reducing memory usage
Runtime API changes:
- SSDConfig: Add primary_on_ssd, secondary_on_ssd, and primary_only fields
  for flexible per-component data placement and primary-only LeanVec mode
- VamanaIndex::assemble_from_directory: Load pre-built indices with optional
  SSD-backed mmap for primary/secondary data components
- VamanaIndexLeanVec::build: Add primary_only parameter to skip secondary
  data allocation (reduces memory, disables reranking)
- DynamicVamanaIndex::assemble_from_directory: Same SSD support for mutable indices
- DynamicVamanaIndexLeanVec::build: Add primary_only via DynamicIndexParams overloads
- DynamicVamanaIndex::load: Add primary_only parameter for deserialization

Implementation:
- VamanaIndexImpl: SSD assembly with MMapAllocator, per-component on_ssd
  flags, and LeanVec primary_only loading via switch-case dispatch
- DynamicVamanaIndexImpl: RAM and SSD assembly paths with primary_only
  support for LeanVec storage kinds
- DynamicVamanaIndexLeanVecImpl: Store and forward primary_only through
  build and init paths
- StorageFactory<LeanVecStorageType>::init: Accept primary_only, forward
  to LeanDataset::reduce
- MMapAllocator: Add madvise(MADV_DONTNEED) eviction support

Tests:
- LeanVecPrimaryOnlyBuildAndSearch: Dynamic index build + self-recall
- LeanVecPrimaryOnlyStaticBuild: Static Vamana with LeanVec4x8 primary_only
- SSD assembly tests for FP32 and LVQ4x8 storage kinds
- MMapAllocator zero-copy and eviction tests
Copy link
Copy Markdown
Member

@rfsaliev rfsaliev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design suggestions

Comment thread include/svs/core/allocator_mmap.h Outdated
///
/// Performs default initialization of the object.
///
void construct(T* ptr) { ::new (static_cast<void*>(ptr)) T; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this code is incompatible with declared use_existing_file() behavior, which means "read-only".

Comment thread include/svs/core/allocator_mmap.h Outdated
/// @brief Allocate memory
///
/// Creates a memory-mapped file and returns a pointer to it.
/// If use_existing_file() was called, maps that file read-only instead.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like would be better to separate behavior for in-directory an 'existing file' allocations to different classes.

/// Tracks memory-mapped allocations by keeping MMapPtr objects alive.
/// Thread-safe for concurrent allocations.
///
class MMapAllocationManager {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this class is fully-static (all fields are static).
And actually behaves as hidden global variables + helper functions.
According to that, there is no reason to define non-static methods like allocate() and map_existing_at_offset().
Suggesting to make all methods static and delete .ctor
Or implement the Singleton pattern.

Address PR #302 review:
- MMapAllocator: writable temp-file backed only (used for build/save).
  construct() is a no-op + static_assert(is_trivially_default_constructible_v<T>):
  the mapped bytes are reinterpreted in place as already-valid T objects so
  load/save can round-trip without running constructors.
- MMapFileViewAllocator: new class for read-only zero-copy file views.
  construct() is also a no-op + static_assert(is_trivially_default_constructible_v<T>),
  but here the mapping is PROT_READ, so placement-new would actively fault;
  the existing on-disk bytes already represent valid T objects.
  Two construction modes:
    * bound (path + offset) for direct use, and
    * config-only with late binding via with_file(path, offset) so
      load_container can resolve the on-disk file by UUID.
- MMapAllocationManager: fully static (no instances; deleted ctor/dtor/copy).
- Add is_mmap_file_view_allocator_v type trait; consumers use this to
  detect the late-binding allocator.
- bindings/cpp SSD load paths (LVQ + LeanVec, both single and dual)
  switched to MMapFileViewAllocator without an explicit ssd_path arg
  (path resolved internally inside the load specialization).
@ibhati
Copy link
Copy Markdown
Member Author

ibhati commented Apr 20, 2026

Design suggestions

@rfsaliev I made the changes as per your suggestion. Please have another look
Here is the commit id: 07b3af0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants