Python API¶
MaruHandler¶
The main client interface for Maru. Handles storing, retrieving, and deleting KV cache entries in CXL shared memory via MaruServer.
from maru import MaruConfig, MaruHandler
Usage¶
config = MaruConfig(server_url="tcp://localhost:5555", pool_size=1024 * 1024 * 100)
with MaruHandler(config) as handler:
data = b"hello world"
# Store: alloc → write → register
handle = handler.alloc(size=len(data))
handle.buf[:len(data)] = data
handler.store(key=12345, handle=handle)
# Retrieve (zero-copy memoryview into CXL memory)
result = handler.retrieve(key=12345)
# Check existence
handler.exists(key=12345)
# Delete
handler.delete(key=12345)
Key Behaviors¶
Auto-connect: Connects automatically on init when
auto_connect=True(default)Auto-expand: Automatically allocates new memory regions when current ones are full
Deduplication: Skips store if the key already exists
Zero-copy retrieve: Returns memoryview pointing directly into mmap region
Thread-safe: Read operations (retrieve, exists) are lock-free; write operations (store, delete) are serialized by an internal write lock
Methods¶
- class maru_handler.MaruHandler(config: MaruConfig | None = None)[source]
Bases:
objectInitialize MaruHandler.
- Parameters:
config – Configuration object. If None, uses defaults.
- property mapper: DaxMapper
Use get_buffer_view() instead.
- Type:
Deprecated
- get_buffer_view(region_id: int, offset: int, size: int) memoryview | None[source]
Get a memoryview slice from a mapped region.
- Parameters:
region_id – The region ID (owned or shared).
offset – Byte offset within the region.
size – Number of bytes to view.
- Returns:
Writable memoryview, or None if region not mapped.
- get_region_page_count(region_id: int) int | None[source]
Get page count for a region (owned or shared).
- Parameters:
region_id – The region ID.
- Returns:
Number of pages, or None if region not found.
- get_owned_region_ids() list[int][source]
Get list of currently owned region IDs.
- Returns:
List of region IDs. Empty if not connected.
- get_chunk_size() int[source]
Get the configured chunk size in bytes.
- Returns:
Chunk size in bytes.
- set_on_region_added(callback: Callable[[int, int], None] | None) None[source]
Register callback invoked with (region_id, page_count) after region added.
On registration, replays callback for all existing owned regions so the caller doesn’t need separate init-time logic.
- Parameters:
callback – Called with (region_id, page_count), or None to unregister.
- connect() bool[source]
Connect to the server and request a memory allocation.
- Returns:
True if successful
- close() None[source]
Close the connection and return all allocations.
Sets
_closingevent to reject new operations, then acquires_write_lockto wait for in-flight writes before teardown.
- alloc(size: int) AllocHandle[source]
Allocate a page and return a handle with a writable memoryview.
The caller writes directly to
handle.buf, then passes the handle tostore(key, handle)to register without copying.- Parameters:
size – Required bytes (must be <= chunk_size)
- Returns:
AllocHandle with writable memoryview and allocation metadata
- Raises:
RuntimeError – If not connected or closing
ValueError – If size exceeds chunk_size or allocation fails
- free(handle: AllocHandle) None[source]
Free a page previously obtained via alloc().
Can be called before store() (discard) or after (eviction).
- Parameters:
handle – AllocHandle from alloc()
- Raises:
ValueError – If handle is not tracked (already freed or invalid)
- store(key: str, handle: AllocHandle) bool[source]
Register a pre-written page in the KV cache (zero-copy).
Data must already be written to the page via
handle.buf. This method only performs duplicate check + metadata registration.- Parameters:
key – The chunk key string
handle – AllocHandle from alloc()
- Returns:
True if successful
- retrieve(key: str) MemoryInfo | None[source]
Retrieve a zero-copy MemoryInfo from the KV cache.
Returns a MemoryInfo with a memoryview slice of the mmap region. Works for both owned (RW) and shared (RO) regions.
WARNING: The returned memoryview is only valid while the region remains mapped. Do not use after calling close().
- Parameters:
key – The chunk key string
- Returns:
MemoryInfo with memoryview, or None if not found
- exists(key: str) bool[source]
Check if a key exists.
- Parameters:
key – The chunk key string
- Returns:
True if exists
- pin(key: str) bool[source]
Check if a key exists and pin it atomically.
If the key exists, increments pin_count to protect from eviction.
- Parameters:
key – The chunk key string
- Returns:
True if exists (and was pinned)
- unpin(key: str) bool[source]
Unpin a KV entry, making it eligible for eviction.
- Parameters:
key – The chunk key string
- Returns:
True if unpinned successfully
- delete(key: str) bool[source]
Delete a key and free the corresponding page.
- Parameters:
key – The chunk key string
- Returns:
True if deleted
- healthcheck() bool[source]
Check if the handler and MaruServer are healthy.
Verifies local connection state and sends a heartbeat RPC to confirm the MaruServer is responsive.
- Returns:
True if connected and server responded to heartbeat
- get_stats() dict[source]
Get server statistics.
- batch_retrieve(keys: list[str]) list[MemoryInfo | None][source]
Retrieve multiple values as MemoryInfo in batch.
Uses a single batch RPC call for lookup, returns zero-copy memoryview slices for both owned (RW) and shared (RO) regions.
WARNING: Returned memoryviews are only valid while regions remain mapped.
On RPC failure, allocated pages are freed but data already written to those pages is not zeroed. This is safe because the pages are never registered with the server and will be overwritten on reuse.
- Parameters:
keys – List of chunk key strings
- Returns:
List of MemoryInfo (None for keys not found)
- batch_store(keys: list[str], handles: list[AllocHandle]) list[bool][source]
Register multiple pre-written pages in batch (zero-copy).
Data must already be written to each page via
handle.buf. Uses a single batch RPC call for metadata registration.- Parameters:
keys – List of chunk key strings
handles – List of AllocHandle from alloc()
- Returns:
List of booleans indicating success for each key
- batch_exists(keys: list[str]) list[bool][source]
Check if multiple keys exist.
Uses a single batch RPC call instead of N individual calls.
- Parameters:
keys – List of chunk key strings
- Returns:
List of booleans indicating existence for each key
- batch_pin(keys: list[str]) list[bool][source]
Check existence and pin multiple keys in a single RPC call.
- Parameters:
keys – List of chunk key strings
- Returns:
List of booleans — True if key exists (and was pinned).
- batch_unpin(keys: list[str]) list[bool][source]
Unpin multiple keys in a single RPC call.
- Parameters:
keys – List of chunk key strings
- Returns:
List of booleans — True if successfully unpinned.
- property pool_handle: _MockModule.MaruHandle | None
Get initial pool handle (backward compat).
- property allocator: PagedMemoryAllocator | None
Get the first region’s allocator (backward compat).
- property owned_region_manager: OwnedRegionManager | None
Use get_owned_region_ids(), get_region_page_count() instead.
- Type:
Deprecated
- property instance_id: str
Get instance ID.
- property connected: bool
Check if connected.
AllocHandle¶
Handle returned by alloc() for zero-copy writes. The caller writes data directly to buf (a writable memoryview into CXL shared memory), then passes the handle to store() to register the key.
# 1. Allocate a page
handle = handler.alloc(size=1024 * 1024)
# 2. Write directly to CXL memory (zero-copy)
handle.buf[:len(data)] = data
# 3. Register the key (only metadata is sent)
handler.store(key=42, handle=handle)
Property |
Type |
Description |
|---|---|---|
|
|
Writable view into the allocated CXL memory page |
|
|
Requested allocation size in bytes |
|
|
Region ID of the allocated page |
|
|
Page index within the region |
- class maru_handler.memory.AllocHandle(buf: memoryview, _region_id: int, _page_index: int, _size: int)[source]¶
Bases:
objectHandle returned by MaruHandler.alloc() for zero-copy writes.
Contains a writable memoryview into CXL mmap memory and allocation metadata. The caller writes directly to
buf, then passes the handle tostore(key, handle)to register without copying.Typical zero-copy flow:
handle = handler.alloc(size=len(data)) handle.buf[:len(data)] = data handler.store(key=key, handle=handle)
- property region_id: int¶
Region ID of the allocated page.
- property page_index: int¶
Page index within the region.
- property size: int¶
Requested allocation size in bytes.
MemoryInfo¶
Zero-copy view into CXL shared memory, returned by retrieve(). Wraps a memoryview pointing directly into an mmap’d CXL region.
result = handler.retrieve(key=42)
if result is not None:
# result.view is a memoryview into CXL shared memory
data = bytes(result.view)
length = len(result.view)
Property |
Type |
Description |
|---|---|---|
|
|
Zero-copy view into the CXL memory region (read-only for cross-instance retrieves) |
- class maru_handler.memory.MemoryInfo(view: memoryview, region_id: int = 0, page_index: int = 0)[source]¶
Bases:
objectZero-copy data descriptor using memoryview.
Interface type between LMCache (MemoryObj) and Maru (mmap region). Supports both RW and RO regions via a single memoryview field.
- PUT: connector creates MemoryInfo(view=memory_obj.byte_array)
handler writes via memoryview slice assignment (buf[off:off+n] = view)
- GET: handler returns MemoryInfo(view=memoryview_slice)
connector creates tensor via torch.frombuffer(info.view)
Data size is available via len(view) or view.nbytes.