MemStream is a high-performance inter-process key-value cache built using POSIX shared memory, a custom C backend, and Python bindings via ctypes. It enables zero-copy access to a central in-memory store across multiple processes without traditional socket or message-passing overhead.
Traditional key-value caches like Redis use networking and serialization even on local systems. MemStream bypasses this overhead by allowing all microservices to interact directly with shared memory. It’s designed to be fast, minimal, and extensible across C and Python environments.
At the heart of MemStream lies a shared memory segment (cache_t) that acts as the central cache. All client processes (writers, readers, analytics) attach to this memory via a small C shared library (libcache.so) and interact with it through defined APIs. Python services access these APIs through ctypes, enabling native shared-memory access from Python with no socket, file, or RPC overhead.
- Exposes
cache_connect,cache_put, andcache_getto client processes. - Built from
cache.c, handles all memory and locking logic internally.
- Implements the core shared-memory cache.
- Allocates a flat memory region storing both metadata (
entry_t[]) and data blobs (char data[]). - Uses
pthread_rwlock_tfor concurrent read-write access across processes.
- Uses
ctypesto loadlibcache.soand insert key-value pairs. - Supports arbitrary binary values.
- Queries keys from the shared cache using C library functions.
- Scans the shared cache to log access statistics like usage, frequency, and timestamps.
MemStream uses System V shared memory (shmget, shmat) to allocate and attach to a single cache region in RAM. Each process maps this region into its virtual address space, resulting in direct access to the same physical memory. All services operate on the same cache_t instance in memory.
All cache operations are synchronized using a process-shared pthread_rwlock_t embedded inside the shared memory. This allows:
- Multiple concurrent readers
- Exclusive writers
- Prevents race conditions and corruption even with overlapping access
Shared memory layout:
[ pthread_rwlock_t lock ] [ size_t max_memory ] [ size_t used_memory ] [ cache_stats_t stats ] [ entry_t entries[] ] <- Fixed metadata for each key [ char data[] ] <- Flexible region for raw values
Each entry_t tracks:
key,value_sizedata_offset: offset intodata[]last_access,created_at,access_countis_valid: used/free marker
Values are manually stored at cache->data + offset. This enables flexible binary data storage but requires explicit memory management and fragmentation control.
Python services use ctypes to bind to libcache.so:
- Dynamically loads and links C functions at runtime
- Passes keys, values, and lengths from Python directly into the C layer
- Enables fast cross-language memory access with minimal overhead
Example:
from ctypes import *
lib = CDLL('./libcache.so')
lib.cache_connect()
lib.cache_put(b"key", b"value", len(b"value"))-
writer.pycalls lib.cache_connect() → maps shared memory -
Inserts key foo → value "bar" stored at offset 0
-
reader.pyconnects, retrieves value from same memory -
analytics.pyreports hit count and timestamps