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: object

Initialize 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 _closing event to reject new operations, then acquires _write_lock to 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 to store(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

buf

memoryview

Writable view into the allocated CXL memory page

size

int

Requested allocation size in bytes

region_id

int

Region ID of the allocated page

page_index

int

Page index within the region

class maru_handler.memory.AllocHandle(buf: memoryview, _region_id: int, _page_index: int, _size: int)[source]

Bases: object

Handle 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 to store(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

view

memoryview

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: object

Zero-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.