Skip to content

Data layout

Persistent mode writes to:

~/.memd/data/
├── .writer.lock                      # Exclusive writer flock
├── metadata.db                       # SQLite metadata (WAL mode, pooled)
├── sparse_index/                     # tantivy BM25 index (open_or_create)
├── warm/<hash>/                      # 0700 runtime dir for warm worker socket
│                                      # socket file chmod 0600
└── tenants/
    └── <tenant_id>/
        ├── wal.log                   # Append-only WAL; fsync before commit
        ├── segments/                 # Immutable chunk segments + payload
        └── warm_index/               # HNSW state
            ├── embeddings.bin        # Source of truth for vectors
            ├── mapping.bin           # bincode (legacy: mapping.json)
            ├── config.json           # HnswConfig snapshot
            └── graph.hnsw.{graph,data}  # Optional fast-load dump
                                          # (skipped when persist_graph_dump=false)

Default data dir: ~/.memd/data. Override with --data-dir.

Retrieval/list scans are tolerant of stale metadata rows with unreadable segment payloads: unreadable chunks are logged and skipped. Direct memory.get remains strict so point lookups still surface storage corruption instead of silently returning the wrong record.

Disk hygiene

Run memd maintenance to sweep orphan HNSW snapshots and report the result. Use --aggressive to force-merge the global Tantivy sparse index into one searchable segment:

memd maintenance --dry-run                  # report what would change
memd maintenance --aggressive               # run the full pass
memd maintenance --tenant-id <id>           # restrict the HNSW sweep only

The orphan sweep targets graph-NNNN.hnsw.{graph,data} files. Aggressive output includes sparse_segments_before, sparse_segments_after, and segments_merged. Output uses key:value lines for shell parsing. The command takes the data-directory writer lock and does not run through the warm worker.

Why bincode for the mapping?

Older builds wrote mapping.json (~5× larger). v0.50.0 packs the same chunk-id → HNSW-index mapping as bincode mapping.bin. The reader still accepts the legacy JSON format and auto-migrates on next save.