← Pepper 0.2.0

Namespaces and KV

A namespace is a versioned ordered map whose mutations are committed by a three-node OpenRaft group. KV, buckets, and filesystems build on the same revision, history, snapshot, rollback, and durability machinery.

Enable the service

[namespace]
enabled = true
consensus_enabled = true

All three candidate nodes need namespace consensus enabled, sufficient advertised storage, and available namespace-group capacity. Replica placement considers failure domains and capacity. Namespace aliases are local metadata conveniences; the namespace ID is the durable identity.

Lifecycle and inspection

Namespace commands

namespace create --kind <KIND> [--alias NAME]

Create a namespace on exactly three replicas. Use kind kv directly; bucket and filesystem have dedicated create commands.

namespace inspect <NAMESPACE>

Show descriptor, current revision, root CID, and head commit CID.

namespace status <NAMESPACE>

Show leader, term, log/application indexes, state, and quorum availability.

namespace replicas <NAMESPACE>

List the three voter identities and Raft IDs.

namespace history <NAMESPACE>

List immutable revisions and their roots/commits.

namespace diff <NAMESPACE> <A> <B>

Compare two revisions; changed-key output is bounded.

namespace rollback <NAMESPACE> <REVISION> [--request-id ID]

Create a new monotonic revision whose content matches an older revision.

KV reads and writes

pepper kv put <NAMESPACE> <KEY> --cid <CID> [--if-generation N] [--if-cid CID] [--request-id ID]
pepper kv put-file <NAMESPACE> <KEY> <PATH> [PRECONDITIONS]
pepper kv get <NAMESPACE> <KEY> [--revision N | --root CID | --checkpoint CID]
pepper kv delete <NAMESPACE> <KEY> [PRECONDITIONS]
pepper kv scan <NAMESPACE> [--prefix TEXT] [--limit N] [--cursor CURSOR] [--revision N]

Normal reads are linearizable. Revision, root, and checkpoint selectors provide historical reads. Scan cursors are bound to the root that created them, so a cursor cannot silently continue against a different snapshot.

--if-generation and --if-cid provide optimistic concurrency. A mismatch is a stable generation-conflict error. --request-id makes an identical retry idempotent; reusing the same ID for a different intent is rejected.

Atomic transactions

{
  "version": 1,
  "base_revision": 4,
  "base_root_cid": "cid://...",
  "mutations": [
    {"op":"put","key_hex":"616c706861","value_cid":"cid://...","value_kind":"object","metadata":{},"precondition":"absent"},
    {"op":"delete","key_hex":"62657461","precondition":{"match":{"generation":2,"cid":"cid://..."}}}
  ],
  "message": "atomic update"
}
pepper kv txn apply <NAMESPACE> ./transaction.json [--request-id ID]

The whole mutation list commits or conflicts as one revision. The transaction file must declare version 1; the CLI supplies the target namespace and generates missing request metadata.

Snapshots and retention

pepper namespace snapshot create <NAMESPACE> nightly [--revision N] [--request-id ID]
pepper namespace snapshot list <NAMESPACE>
pepper namespace snapshot delete <NAMESPACE> nightly [--request-id ID]

Named snapshots retain a revision independently of the moving head. Rollback is also non-destructive: history remains immutable and the rollback appears as a new revision. Publication intents, staging leases, read leases, and synchronized pins prevent referenced DAGs from being collected while a write or retained read is live.

Failure behavior

  • A quorum is required for linearizable reads and writes; any healthy ingress node routes work to the current leader.
  • Referenced content must reach the required durability before its namespace mutation becomes visible.
  • put-file retains its uploaded CID when the metadata mutation conflicts, and reports that CID so it can be reused or unpinned.
  • Stable CLI exit categories distinguish conflicts (20), namespace/leader unavailability (21), durability failure (22), authorization (23), and invalid requests/cursors (24).