This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
# Compile the project (all modules)
mvn clean compile
# Run all tests (all modules)
mvn test
# Run tests for a specific module
mvn test -pl roguemap-core
mvn test -pl roguemap-memory
mvn test -pl roguemap-memory-pro
mvn test -pl roguemap-embedding
# Run a specific test class
mvn test -Dtest=MapFunctionalTest
# Run multiple test classes
mvn test -Dtest=LinkedQueueFreeListTest,QueueCrashRecoveryTest
# Run tests by pattern
mvn test -Dtest=*ComparisonTest
# Release build (GPG signing + publish to Maven Central)
mvn clean deploy -P releaseThis is a multi-module Maven project:
| Module | Java | Description |
|---|---|---|
roguemap-core |
8+ | Core off-heap storage library (zero mandatory deps) |
roguemap-embedding |
8+ | Universal EmbeddingProvider implementation; zero extra deps |
roguemap-memory |
8+ | AI memory layer; HNSW vector index via jelmerk/hnswlib-core |
roguemap-memory-pro |
11+ | AI memory layer; higher-performance HNSW via datastax/jvector |
roguemap-memory and roguemap-memory-pro are structurally identical except for the vector index backend (HnswVectorIndex vs JVectorIndex). Both depend on roguemap-core.
roguemap-embedding provides UniversalEmbeddingProvider — a single class that works with any OpenAI /v1/embeddings-compatible service (OpenAI, Mistral, Jina, Voyage, Ollama in OpenAI-compat mode, Alibaba DashScope, Zhipu GLM, etc.) using only HttpURLConnection. The older OpenAIEmbeddingProvider and OllamaEmbeddingProvider in the memory modules are @deprecated in favor of this class.
RogueMap is a high-performance embedded storage library using memory-mapped files for off-heap storage. Java 8+, zero mandatory dependencies. Provides four data structures: RogueMap (key-value store), RogueList (doubly-linked list), RogueSet (concurrent set), and RogueQueue (FIFO queue with linked/circular modes).
API Layer (RogueMap, RogueList, RogueSet, RogueQueue)
↓
Index Layer (key → address mapping, or position tracking)
↓
Storage Engine (read/write byte data)
↓
Memory Allocator (MmapAllocator)
↓
UnsafeOps (sun.misc.Unsafe for direct memory access)
↓
Memory-Mapped Files (persistent or temporary)
RogueMap<K,V> - Key-value store:
RogueMap.mmap().temporary()- Temporary file mode (auto-deleted on JVM exit)RogueMap.mmap().persistent(path)- Persistent file mode (data survives restart)- Index options:
basicIndex(),segmentedIndex(64),primitiveIndex(),lowHeapIndex() forEach(BiConsumer<K,V>)- Iterate over all key-value pairs- TTL support:
defaultTTL(ttl, unit)in builder; data stored as[expireTime(8 bytes)][actual data] - Transactions:
beginTransaction()returns AutoCloseableTransaction<K,V>
RogueList - Doubly-linked list with O(1) random access:
- Maintains position index array for fast random access via
get(index) - Head/tail operations:
addFirst(),addLast(),removeFirst(),removeLast() - Warning:
addFirst()andremoveFirst()are O(n) due to position index shift; preferaddLast()/removeLast()for large lists - Supports bidirectional iteration via
ListIterator<E>
RogueSet - Concurrent set:
- 64-segment design with StampedLock for high concurrency
- Optimistic read support for improved read performance
- Standard operations:
add(),contains(),remove() SetIteratoruses lazy segment loading (O(N/64) heap peak instead of O(N))- Low-heap mode:
lowHeapIndex()for String-key-only off-heap index
RogueQueue - FIFO queue with two storage modes:
- Linked mode (unbounded):
RogueQueue.mmap().linked() - Circular mode (bounded):
RogueQueue.mmap().circular(capacity, maxElementSize) - Standard operations:
offer(),poll(),peek(),isFull() - LinkedQueue: snapshots head/tail/size to header on every offer/poll for crash recovery
- CircularQueue: recalculates count from headIdx/tailIdx on recovery
StorageMetrics - Monitoring storage health:
getMetrics()returns fragmentation ratio, used/available bytes, entry count, dead bytesshouldCompact(threshold)indicates when compaction is needed- All four data structures support this API
compact(allocSize) - Space reclamation for persistent mode:
- Creates new file with only live data, eliminating fragmentation
- Returns new instance; old instance is closed
- Supported by RogueMap, RogueList, RogueSet, RogueQueue(linked)
- Not supported: temporary mode, CircularQueue
checkpoint() - Explicit crash recovery point:
- Forces index/metadata to disk for durable recovery
- Use when you need guaranteed recoverability between close() calls
- All four data structures support this in persistent mode
AutoCheckpointManager - Automatic checkpoint triggering:
- Time-interval mode:
autoCheckpoint(long interval, TimeUnit unit)in builder - Operation-count mode:
autoCheckpoint(int operationCount)in builder - Both modes can be enabled simultaneously; either condition triggers checkpoint
- Uses scheduled daemon thread pool; CAS-based operation counter to avoid duplicate triggers
- All four data structures support auto-checkpoint via builder
Fail-fast Iterators:
- RogueSet and RogueList iterators throw
ConcurrentModificationExceptionif collection is modified during iteration - Tracks modification count; detects structural changes (add/remove/clear)
Auto-Expansion - Dynamic file growth:
autoExpand(true)in builder enables automatic file growth when space runs outexpandFactor(double)controls growth multiplier (default 2.0);maxFileSize(long)sets optional cap- Expansion only maps new region; existing segment base addresses are unchanged
- Thread-safe: normal
allocate()holds read lock (CAS),expand()holds exclusive write lock tryAllocate()skips segment tail bytes to avoid cross-segment allocations (SIGSEGV prevention)saveMmapIndex()usesallocate()for index placement;getFileOffsetForAddress()converts to file offset for header
Transactions - Atomic multi-key operations for RogueMap:
map.beginTransaction()returnsTransaction<K,V>(AutoCloseable)txn.put(key, val)/txn.remove(key)buffer operations;txn.commit()applies atomicallyclose()withoutcommit()auto-rolls back;rollback()also explicit- Isolation: Read Committed (reads see committed data, not own pending writes)
- Deadlock prevention: locks acquired in ascending segment-index order
- Not supported with
lowHeapIndex()
TTL (Time-To-Live) - Data expiration (all four data structures):
- Builder:
.defaultTTL(ttl, TimeUnit)sets default TTL for all entries - RogueMap also supports per-entry TTL:
put(key, value, ttl, TimeUnit) - Storage format:
[expireTime(8 bytes)][actual data]— expiration timestamp prefix in mmap TTLUtilshelper:calculateExpireTime(),isExpired(),readExpireTime(),writeExpireTime()- TTL header size is 8 bytes;
getDataAddress()skips header to reach actual data
index/ - Map indexing:
HashIndex- Basic ConcurrentHashMap-based indexSegmentedHashIndex- 64 segments with StampedLock (default for RogueMap)LongPrimitiveIndex/IntPrimitiveIndex- Primitive array indexesLowHeapStringIndex- Ultra-low heap String-only index (slot table + key bytes stored off-heap in mmap, only segment metadata/locks on JVM heap; 32-byte slots with EMPTY/USED/DELETED states; configured viaLowHeapOptions)BatchEntry- Transaction batch operation entry
list/ - List-specific components:
ListIndex- Manages head/tail pointers + position index arrayRogueListIterator- Bidirectional ListIterator implementation
set/ - Set-specific components:
SetIndex- Segmented hash set index (64 segments)LowHeapStringSetIndex- Low-heap variant usingLowHeapStringIndexas delegateSetIterator- Iterator implementation
queue/ - Queue storage implementations:
LinkedQueueStorage- Unbounded linked queue with free list for node recyclingCircularQueueStorage- Bounded ring buffer queue
storage/ - Storage engine:
MmapStorage- Memory-mapped file storageMmapFileHeader- 4KB header with metadata, supports data types: MAP(0), LIST(1), SET(2), QUEUE_LINKED(3), QUEUE_CIRCULAR(4)
memory/ - Memory management:
MmapAllocator- Allocates space in mmap files, supports >2GB via segmentationUnsafeOps- Low-level Unsafe operations
serialization/ - Codec implementations:
Codec<T>- Interface for encoding/decoding valuesPrimitiveCodecs- Zero-copy codecs for Long, Integer, Double, Float, Short, Byte, BooleanStringCodec- UTF-8 string codecKryoObjectCodec- Object serialization via Kryo (optional dependency)TypeReference<T>- Preserves complex generic type info at runtime for Kryo (e.g.,new TypeReference<List<User>>() {})
util/ - Utilities:
TempFileManager- Temporary file management withforceUnmap()(tries Java 9+invokeCleanerfirst)TTLUtils- TTL header read/write, expiration calculation
- Builder Pattern - All four data structures use fluent builders (
MmapBuilder) - Segmented Locking - 64 independent StampedLocks minimize contention
- Linear Allocation - CAS-based offset allocation, append-only (no free list except LinkedQueue)
- Zero-Copy Primitives - PrimitiveCodecs write directly to memory
- Copy-on-Compact -
compact()creates new file with live data only (append-only creates fragmentation over time)
On close() or checkpoint(), persistent mode saves:
- Current data offset to file header
- Serialized index/metadata to end of file
- File header metadata (magic, version, data type, entry count)
On reopening, builders detect existing files and restore state from disk. Use checkpoint() for explicit durability between close() calls.
src/main/java/com/yomahub/roguemap/
├── RogueMap.java # Map class + MmapBuilder + Transaction inner class
├── RogueList.java # Doubly-linked list
├── RogueSet.java # Concurrent set
├── RogueQueue.java # FIFO queue
├── RogueMapTransaction.java # Transaction implementation (commit/rollback)
├── AutoCheckpointManager.java # Time/operation-count auto-checkpoint
├── StorageMetrics.java # Storage health metrics (fragmentation, usage)
├── index/ # Map index implementations (Hash, Segmented, Primitive, LowHeap)
├── list/ # List index + iterator
├── set/ # Set index + iterator (including LowHeapStringSetIndex)
├── queue/ # Queue storage implementations
├── storage/ # MmapStorage + MmapFileHeader
├── memory/ # MmapAllocator + UnsafeOps
├── serialization/ # Codec implementations + TypeReference
├── util/ # TempFileManager + TTLUtils
└── btree/ # Placeholder (future B-tree implementation)
src/test/java/com/yomahub/roguemap/
├── map/ # RogueMap tests (functional, temporary, TTL, transaction, expansion, concurrency, low-heap index)
├── list/ # RogueList tests (functional, concurrent)
├── set/ # RogueSet tests (functional, concurrent, low-heap)
├── queue/ # RogueQueue tests (functional, concurrent, crash recovery, free list)
├── common/ # Cross-structure tests (checkpoint, compaction, metrics, fail-fast iterators, P0 fixes)
├── memory/ # UnsafeOps tests
├── serialization/ # KryoObjectCodec tests
└── benchmark/ # Performance comparison tests + TestValueObject fixture
AI memory layer built on roguemap-core. Supports hybrid retrieval (vector + BM25) with mmap-backed persistence.
RogueMemory mem = RogueMemory.builder()
.path("data/mem")
.searchMode(SearchMode.HYBRID) // HYBRID | VECTOR_ONLY | KEYWORD_ONLY
.embeddingProvider(new UniversalEmbeddingProvider(apiKey))
.build();
String id = mem.add("content", metadata, "namespace");
List<MemoryResult> results = mem.search(SearchOptions.builder()
.query("query text").topK(10).namespace("namespace").build());
mem.delete(id);
mem.close();SearchMode:
HYBRID(default) — vector search + BM25, merged via RRF; requiresEmbeddingProviderVECTOR_ONLY— ANN only; requiresEmbeddingProviderKEYWORD_ONLY— BM25 only; noEmbeddingProviderneeded
roguemap-memory(HnswVectorIndex) —jelmerk/hnswlib-core 1.2.1; Java 8+; cosine similarity; M=16, efConstruction=200, ef=50roguemap-memory-pro(JVectorIndex) —datastax/jvector 3.0.1; Java 11+; usesGraphIndexBuilderwith ordinal→id mapping for ANN
Both implement VectorIndex: add(id, vector), search(vector, topK), markDeleted(id), serialize(DataOutput), deserialize(DataInput).
Implement EmbeddingProvider to plug in any embedding source. Preferred: UniversalEmbeddingProvider from roguemap-embedding:
// OpenAI (default model text-embedding-3-small)
new UniversalEmbeddingProvider(apiKey)
// Any OpenAI-compatible service (Mistral, Jina, Voyage, Ollama, DashScope, etc.)
new UniversalEmbeddingProvider(baseUrl, apiKey, model, dimension)
// Pass dimension=0 to auto-detect on first embed() callKnown models (dimension auto-populated): text-embedding-3-small (1536), text-embedding-3-large (3072), mistral-embed (1024), nomic-embed-text (768), jina-embeddings-v3 (1024), and others — see KNOWN_MODELS map in the class.
OpenAIEmbeddingProvider and OllamaEmbeddingProvider in the memory modules are @deprecated; use UniversalEmbeddingProvider instead.
[expireTime: 8B][id: 16B UUID][ns_len: 2B][namespace bytes]
[content_len: 4B][content bytes][meta_len: 4B][metadata bytes]
[vector_len: 4B][vector floats (4B each)][deleted: 1B][createdAt: 8B]
Metadata encoding: [pair_count: 2B][key_len: 2B][key bytes][val_len: 2B][val bytes]...
com.yomahub.roguemap.memory/
├── RogueMemory.java # Main API (Builder, add/search/delete/compact/close)
├── OrdinalRegistry.java # int-ordinal → UUID mapping for vector index entries
├── SearchMode.java # HYBRID | VECTOR_ONLY | KEYWORD_ONLY
├── SearchOptions.java # Query builder (query, topK, namespace, filter, minScore)
├── MemoryResult.java # Search result (id, content, score, metadata)
├── MemoryEntry.java # Internal entry model
├── embedding/
│ ├── EmbeddingProvider.java # SPI interface
│ ├── OpenAIEmbeddingProvider.java # @deprecated — use UniversalEmbeddingProvider
│ └── OllamaEmbeddingProvider.java # @deprecated — use UniversalEmbeddingProvider
├── index/
│ ├── VectorIndex.java # ANN index interface
│ ├── ScoredOrdinal.java # (ordinal, score) pair for index results
│ ├── HnswVectorIndex.java # (roguemap-memory only)
│ ├── JVectorIndex.java # (roguemap-memory-pro only)
│ └── BM25Index.java # BM25 keyword index (shared pattern)
└── util/
└── Tokenizer.java # Simple whitespace/punctuation tokenizer for BM25
- Java 8+ - Uses
sun.misc.Unsafefor direct memory operations; Java 9+ tests use--add-opens(auto-activated via Maven profile) - Thread Safety - All operations are thread-safe via segmented locking
- Resource Management - Always use try-with-resources to ensure proper cleanup
- File Pre-allocation - Mmap mode pre-allocates disk space via
allocateSize() - Close Ordering -
storage.close()internally callsallocator.close(). Never callallocator.close()separately afterstorage.close()(double-close bug) - Optional Dependencies - Kryo (
KryoObjectCodec) and SLF4J are optional. Core library has zero mandatory dependencies - Fragmentation - Append-only allocator creates dead bytes on updates/deletes; use
getMetrics()to monitor andcompact()when fragmentation ratio > 0.5 - Auto-Expansion -
autoExpand(true)in builder allows file to grow;tryAllocate()skips segment tail bytes to avoid cross-boundary writes; usegetAddressForOffset()/getFileOffsetForAddress()for safe multi-segment address translation - Transaction -
map.beginTransaction()returns AutoCloseableTransaction<K,V>; commit() is atomic; close() without commit() auto-rolls back; deadlock prevented by always locking segments in ascending index order - LowHeapIndex -
lowHeapIndex()is String-key-only; does not supportbeginTransaction(); does not auto-migrate legacy index formats - Iterator Safety - Set/List iterators are fail-fast; do not modify collection during iteration
- Test File Cleanup - After JVM crash, @AfterEach doesn't run. Clean test directories in @BeforeEach to avoid corrupt leftover files crashing subsequent test runs
- Keys on heap, values off-heap - For expansion tests, value bytes (not key count) must exceed initial file size to trigger growth
offset 0-47: 9 data fields (magic, version, dataType, entryCount, etc.)
offset 48-51: CRC32 checksum of bytes 0-47
offset 52-55: writeGen (odd=writing, even=complete)
offset 56-59: dirtyFlag (1=unclean close, 0=clean close)
offset 60-63: Reserved
offset 64-95: Queue snapshot area (headOffset, tailOffset, size, valid)
offset 96-4095: Reserved
MmapAllocator.allocate()rejects sizes > 512MB (defensive check)MmapAllocator.free()is a no-op (append-only allocator)- LinkedQueueStorage maintains its own free list for node recycling
getAddressForOffset(fileOffset)— file offset to physical address via segment tablegetFileOffsetForAddress(physAddr)— physical address to file offset (reverse lookup)
[expireTime: 8 bytes (long)][actual serialized data]
TTLUtils.TTL_HEADER_SIZE = 8;DEFAULT_TTL = 0(never expires)- Expiration stored as absolute timestamp from
System.currentTimeMillis() + ttlMillis