|
2 | 2 |
|
3 | 3 | Aerospike remote storage backend for [LMCache](https://github.com/LMCache/LMCache). LMCache caches LLM attention KV tensors; this package implements the durable shared tier via LMCache's `RemoteConnector` plugin contract. |
4 | 4 |
|
5 | | -**Status:** Pre-implementation (design + executable plan only; no `src/` yet). Do not invent APIs or skip the plan's verification gates. |
| 5 | +**Status:** Phase 1 (`ConnectorAdapter` + `AerospikeRemoteConnector`) is implemented on `main`. Phase 2/3 remain design-only in `DESIGN.md`. |
6 | 6 |
|
7 | 7 | ## Read order |
8 | 8 |
|
9 | 9 | 1. **This file** — workflow, pitfalls, and verification expectations. |
10 | 10 | 2. `[DESIGN.md](DESIGN.md)` — authoritative contract: data model, config, error handling, phases. |
11 | | -3. `[IMPLEMENTATION_PLAN.md](IMPLEMENTATION_PLAN.md)` — step-by-step build guide (S0–S16). **When implementing, the plan wins over stale design text** until S16 reconciles `DESIGN.md`. |
| 11 | +3. `[IMPLEMENTATION_PLAN.md](IMPLEMENTATION_PLAN.md)` — step-by-step build guide (S0–S16). |
12 | 12 |
|
13 | | -For Aerospike client/modeling rules, use the vetted skills in [aerospike/agent-skills](https://github.com/aerospike/agent-skills) (especially `[skills/aerospike-development/](https://github.com/aerospike/agent-skills/tree/main/skills/aerospike-development)`). Do not guess Aerospike APIs or namespace defaults. |
| 13 | +For Aerospike client/modeling rules, use [aerospike/agent-skills](https://github.com/aerospike/agent-skills) (especially `skills/aerospike-development/`). Do not guess Aerospike APIs or namespace defaults. |
14 | 14 |
|
15 | 15 | ## Phases (scope discipline) |
16 | 16 |
|
17 | | - |
18 | | -| Phase | Surface | In this repo today | |
19 | | -| ----- | ----------------------------------------------- | --------------------------------- | |
20 | | -| 1 | `ConnectorAdapter` + `RemoteConnector` (Python) | **Only phase to implement now** | |
21 | | -| 2 | `StoragePluginInterface`, `L2AdapterInterface` | Architectural in `DESIGN.md` only | |
22 | | -| 3 | C++ `ConnectorBase` / `libaerospike` | Architectural in `DESIGN.md` only | |
23 | | - |
| 17 | +| Phase | Surface | In this repo today | |
| 18 | +| ----- | ------- | ------------------ | |
| 19 | +| 1 | `ConnectorAdapter` + `RemoteConnector` (Python) | **Implemented** | |
| 20 | +| 2 | `StoragePluginInterface`, `L2AdapterInterface` | Architectural in `DESIGN.md` only | |
| 21 | +| 3 | C++ `ConnectorBase` / `libaerospike` | Architectural in `DESIGN.md` only | |
24 | 22 |
|
25 | 23 | Stay inside Phase 1 unless the user explicitly expands scope. |
26 | 24 |
|
27 | | -## Implementation workflow |
28 | | - |
29 | | -1. Start at **S0** in `IMPLEMENTATION_PLAN.md` and proceed **in order** (S0 → S16). |
30 | | -2. **Stop if a step's verify gate fails** — fix before continuing; do not batch steps. |
31 | | -3. Mark **⚠ DESIGN-CORRECTION** items as non-negotiable (they were verified against upstream LMCache `dev` and the real Aerospike Python client). |
32 | | -4. After S16, reconcile `DESIGN.md` with the implementation (grep for `exists_many`, `post_init`, `shape0`, stale caps). |
33 | | - |
34 | | -### Critical upstream facts (do not regress) |
35 | | - |
36 | | -- `**post_init()` is never called** on remote connectors. Server record-size discovery runs in the connector constructor (`_ensure_limits`), not in `post_init`. |
37 | | -- **Adapter has a no-arg `__init__`**. LMCache instantiates `AerospikeConnectorAdapter()` then calls `create_connector(context)`. |
38 | | -- **Config/metadata** come from `context.local_cpu_backend` (`.config`, `.metadata`), with fallback to `context.config` / `context.metadata`. |
39 | | -- **Connector is serde-agnostic.** `naive` / `cachegen` / `kivi` and MLA/layerwise key rewriting happen in `RemoteBackend` above the connector. |
40 | | -- `**save_chunk_meta`:** when true, store one `md` bin (`RemoteMetadata.serialize()`); when false, use `self.meta_`* + `reshape_partial_chunk` on read (mirror `FSConnector`). |
41 | | -- **Batch API:** `batch_read(keys, bins=...)` and `batch_write(BatchRecords([Write|Read|Remove, ...]))`. Do **not** use removed `exists_many` / `get_many` / `select_many`. |
42 | | -- **TTL:** pin `aerospike>=14,<19` and centralize TTL in one helper (`meta={"ttl": N}`); namespace must have `nsup-period > 0` when using positive TTL. |
43 | | -- **Default `target_segment_bytes` = 4 MiB** (LMCache byte-throughput sweet spot); clamp to server-discovered cap, not Aerospike's 1–10 KiB ops sweet spot. |
44 | | - |
45 | | -### Package layout (target) |
| 25 | +## Package layout |
46 | 26 |
|
47 | 27 | ```text |
48 | | -src/lmcache_aerospike/ |
49 | | - adapter.py connector.py client.py config.py keys.py |
50 | | - sharding.py limits.py serde.py policies.py errors.py metrics.py |
51 | | -tests/unit/ tests/integration/ tests/bench/ |
52 | | -docker/docker-compose.yml docker/aerospike.conf |
| 28 | +src/lmcache_aerospike/ # published on PyPI |
| 29 | +tests/unit/ tests/integration/ |
| 30 | +benchmarks/ # NOT published — ai-ecosystem-benchmark + micro harness |
| 31 | +docker/ scripts/ |
53 | 32 | ``` |
54 | 33 |
|
55 | | -## Verification (once code exists) |
56 | | - |
| 34 | +## Verification |
57 | 35 |
|
58 | | -| Scope | Command | Notes | |
59 | | -| -------------- | ----------------------------------------------- | ------------------------------------------------------------ | |
60 | | -| Preflight (S0) | `python scripts/preflight.py` | Confirms LMCache + Aerospike client symbols | |
61 | | -| Unit | `pytest tests/unit -q` | No network; mock `aerospike.Client` | |
62 | | -| Integration | `RUN_INTEGRATION=1 pytest tests/integration -q` | Requires `docker compose -f docker/docker-compose.yml up -d` | |
63 | | -| Bench / vLLM | per S15 | Optional; gated by env vars | |
| 36 | +| Scope | Command | Notes | |
| 37 | +| ----- | ------- | ----- | |
| 38 | +| Preflight (S0) | `python scripts/preflight.py` | LMCache + Aerospike client symbols | |
| 39 | +| Unit | `pytest tests/unit -q` | No network | |
| 40 | +| Integration | `./scripts/start_aerospike_ce.sh` then `pytest tests/integration -q` | Live CE | |
| 41 | +| Ecosystem bench | `pip install -r benchmarks/requirements.txt` then `python benchmarks/run.py --profile smoke` | Not in CI by default | |
| 42 | +| Micro bench | `RUN_BENCH=1 pytest benchmarks/micro --benchmark-only` | FakeClient only | |
64 | 43 |
|
| 44 | +Pinned versions: `IMPLEMENTATION_PLAN.md` §0.2. |
65 | 45 |
|
66 | | -Pinned versions are in `IMPLEMENTATION_PLAN.md` §0.2 — do not change without re-running S0. |
| 46 | +## Critical upstream facts (do not regress) |
67 | 47 |
|
68 | | -## Aerospike skills (external) |
69 | | - |
70 | | -Before changing client usage, policies, TTL, batching, or record sizing, read the relevant reference from [agent-skills](https://github.com/aerospike/agent-skills/tree/main/skills/aerospike-development/references/). `DESIGN.md` §8.3 lists the ones this design depends on. |
71 | | - |
72 | | -For local Docker CE setup in integration tests, see [aerospike-getting-started/SKILL.md](https://github.com/aerospike/agent-skills/blob/main/skills/aerospike-getting-started/SKILL.md). |
73 | | - |
74 | | -## LMCache upstream (re-verify when unsure) |
75 | | - |
76 | | -- `[RemoteConnector](https://github.com/LMCache/LMCache/blob/dev/lmcache/v1/storage_backend/connector/base_connector.py)` |
77 | | -- `[ConnectorAdapter` / `ConnectorContext](https://github.com/LMCache/LMCache/blob/dev/lmcache/v1/storage_backend/connector/__init__.py)` |
78 | | -- `[RemoteBackend](https://github.com/LMCache/LMCache/blob/dev/lmcache/v1/storage_backend/remote_backend.py)` — serde, `init_connection`, no `post_init` |
79 | | -- `[FSConnector](https://github.com/LMCache/LMCache/blob/dev/lmcache/v1/storage_backend/connector/fs_connector.py)` — `save_chunk_meta` pattern |
80 | | -- `[redis_connector.py](https://github.com/LMCache/LMCache/blob/dev/lmcache/v1/storage_backend/connector/redis_connector.py)` — `batched_contains` consecutive-prefix semantics |
| 48 | +- **`post_init()` is never called** on remote connectors. Discovery runs in `_ensure_limits()` during construction. |
| 49 | +- **Adapter has a no-arg `__init__`**. Config/metadata from `context.local_cpu_backend` (fallback `context.config` / `context.metadata`). |
| 50 | +- **Connector is serde-agnostic.** MLA/layerwise key rewriting happens in `RemoteBackend` above the connector. |
| 51 | +- **`save_chunk_meta`:** one `md` bin when true; `meta_*` + `reshape_partial_chunk` when false (mirror `FSConnector`). |
| 52 | +- **Batch API:** `batch_read` / `batch_write(BatchRecords(...))` — not `exists_many` / `get_many`. |
| 53 | +- **TTL:** `aerospike>=14,<19`, single `_put_meta` helper; `nsup-period > 0` for positive TTL. |
| 54 | +- **Default `target_segment_bytes` = 4 MiB** (LMCache byte-throughput); clamp to server cap. |
81 | 55 |
|
82 | 56 | ## What not to do |
83 | 57 |
|
84 | | -- Do not implement Phase 2/3 features (pin/unpin L2, native C++, controller metadata, EE-only APIs) in Phase 1 code paths. |
85 | | -- Do not create a new `aerospike.Client` per request; use `AerospikeClientHolder` ref-counting. |
86 | | -- Do not use CDTs or secondary indexes for chunk payload storage. |
87 | | -- Do not hardcode 8 MiB record caps; discover `max-record-size` / `write-block-size` at construction. |
| 58 | +- Do not implement Phase 2/3 features in Phase 1 paths. |
| 59 | +- Do not add benchmark-only deps to `pyproject.toml` `[project]` dependencies (use `benchmarks/requirements.txt`). |
| 60 | +- Do not create a new `aerospike.Client` per request; use `AerospikeClientHolder`. |
| 61 | +- Do not hardcode record-size caps; discover at construction. |
88 | 62 | - Do not commit unless the user asks. |
89 | | - |
90 | | -## Commits and PRs |
91 | | - |
92 | | -Follow repository commit style from `git log`. Summarize *why* in commit messages. For PRs, include unit-test results and note whether integration tests were run. |
0 commit comments