Configuration & Options
NoKV exposes two configuration surfaces:
- Runtime options for the embedded engine (
Optionsinoptions.go). - Cluster topology for distributed mode (
raft_config.example.jsonviaconfig.LoadFile/Validate).
1. Runtime Options (Embedded Engine)
NoKV.NewDefaultOptions() returns a tuned baseline. Override fields before
calling NoKV.Open(opt), which now returns (*DB, error).
Key option groups (see options.go for the full list):
- Paths & durability
WorkDir,SyncWrites,ManifestSync,ManifestRewriteThreshold
- Write pipeline
WriteBatchMaxCount,WriteBatchMaxSize,WriteBatchWaitMaxBatchCount,MaxBatchSizeWriteThrottleMinRate,WriteThrottleMaxRate
- Value log
ValueThreshold,ValueLogFileSize,ValueLogMaxEntriesValueLogGCInterval,ValueLogGCDiscardRatioValueLogGCParallelism,ValueLogGCReduceScore,ValueLogGCSkipScoreValueLogGCReduceBacklog,ValueLogGCSkipBacklogValueLogGCSampleSizeRatio,ValueLogGCSampleCountRatio,ValueLogGCSampleFromHeadValueLogBucketCount
- LSM & compaction
MemTableSize,MemTableEngine,SSTableMaxSz,NumCompactorsNumLevelZeroTables,LandingCompactBatchSize,LandingBacklogMergeScoreCompactionValueWeight,CompactionValueAlertThreshold
- Caches
BlockCacheBytes,IndexCacheBytes
- Hot key throttling
WriteHotKeyLimitThermosEnabled,ThermosTopK, decay/window settingsThermosNodeCap,ThermosNodeSampleBits,ThermosRotationInterval
- WAL watchdog
EnableWALWatchdog,WALAutoGCIntervalWALAutoGCMinRemovable,WALAutoGCMaxBatchWALTypedRecordWarnRatio,WALTypedRecordWarnSegments
- Raft lag warnings (stats only)
RaftLagWarnSegments
Example:
opt := NoKV.NewDefaultOptions()
opt.WorkDir = "./data"
opt.SyncWrites = true
opt.ValueThreshold = 2048
opt.WriteBatchMaxCount = 128
db, err := NoKV.Open(opt)
if err != nil {
log.Fatalf("open failed: %v", err)
}
defer db.Close()
Notes:
NewDefaultOptions()populates concrete compaction/landing defaults up front.Open()resolves constructor-owned defaults once, then the DB and LSM layers consume the resolved values directly.WriteBatchMaxCount,WriteBatchMaxSize,MaxBatchCount,MaxBatchSize,WriteThrottleMinRate,WriteThrottleMaxRate, andWALBufferSizenow also expose concrete defaults throughNewDefaultOptions(). If you constructOptionsmanually, leaving these fields at zero letsOpen()resolve the constructor defaults.- Batch knobs are split by owner:
WriteBatchMaxCount/WriteBatchMaxSizebound commit-worker request coalescing.MaxBatchCount/MaxBatchSizebound internal apply/rewrite batches such asbatchSetand value-log GC rewrites.
- Write slowdown is bandwidth-driven:
WriteThrottleMaxRateapplies when slowdown first becomes active, and pressure lowers the target rate towardWriteThrottleMinRateas compaction debt approaches the stop threshold.
Load Options From TOML
For convenience, you can load engine options from a TOML file. Unspecified
fields keep their defaults from NewDefaultOptions.
opt, err := NoKV.LoadOptionsFile("nokv.options.toml")
if err != nil {
log.Fatal(err)
}
db, err := NoKV.Open(opt)
if err != nil {
log.Fatalf("open failed: %v", err)
}
defer db.Close()
Example (TOML):
work_dir = "./data"
mem_table_engine = "art"
value_threshold = 2048
write_hot_key_limit = 128
value_log_gc_interval = "30s"
Notes:
- Field names are case-insensitive;
_/-/.are ignored. - Durations accept Go-style strings (e.g.
"30s","200ms"). Numeric durations are interpreted as nanoseconds. - File extensions
.tomland.tmlare accepted. - JSON option files are rejected by design.
- Unknown fields return an error so typos do not silently pass.
2. Raft Topology File
raft_config.example.json is consumed by every CLI in distributed mode.
Two-layer semantics
The file has two independent layers with different lifecycles. Confusing them is a common deployment mistake, so be explicit:
| Layer | Keys | Lifecycle | Source of truth |
|---|---|---|---|
| Address directory | meta_root.peers, coordinator, stores, store_work_dir_template, max_retries | Read on every CLI invocation. Keep in sync with deployed containers/hosts. | This file is the source of truth. Nothing else knows where to dial. |
| Bootstrap seed | regions | Read only on first startup by scripts/ops/bootstrap.sh. Once a store has CURRENT, bootstrap skips it. | After first bootstrap, meta-root owns the runtime region topology. Inspect with nokv-config regions. |
Consequence: editing regions after bootstrap is a no-op for running
clusters. Editing addresses is effective on the next CLI invocation
(restart / docker compose up).
Precedence
When a value can come from both CLI and config file, CLI wins. Config is a source of defaults:
--root-peer=1=host:2380 → explicit, used
(absent) → fall back to meta_root.peers[0].addr
Minimal shape
{
"max_retries": 8,
"meta_root": {
"peers": [
{ "node_id": 1,
"addr": "127.0.0.1:2380", // coordinator/host audit tools dial here
"docker_addr": "nokv-meta-root-1:2380",
"transport_addr": "127.0.0.1:3380", // sibling meta-root peers dial here for raft
"docker_transport_addr": "nokv-meta-root-1:2480",
"work_dir": "./artifacts/cluster/meta-root-1",
"docker_work_dir": "/var/lib/nokv-meta-root" },
{ "node_id": 2, "...": "..." },
{ "node_id": 3, "...": "..." }
]
},
"coordinator": {
"addr": "127.0.0.1:2379",
"docker_addr": "nokv-coordinator-1:2379,nokv-coordinator-2:2379,nokv-coordinator-3:2379"
},
"store_work_dir_template": "./artifacts/cluster/store-{id}",
"store_docker_work_dir_template": "/var/lib/nokv/store-{id}",
"stores": [
{ "store_id": 1,
"listen_addr": "127.0.0.1:20170",
"addr": "127.0.0.1:20170",
"docker_listen_addr": "0.0.0.0:20160",
"docker_addr": "nokv-store-1:20160" }
],
"regions": [
{ "id": 1, "start_key": "", "end_key": "m",
"epoch": { "version": 1, "conf_version": 1 },
"peers": [{ "store_id": 1, "peer_id": 101 }],
"leader_store_id": 1 }
]
}
Field notes
meta_root.peers: exactly 3 entries.addris the gRPC service port (coordinators / host audit tools dial it).transport_addris the raft transport port (sibling meta-root peers dial it for raft messages). They MUST be different ports on the same host.coordinator.addr/docker_addr: may be a single endpoint or comma-separated for multi-coord HA (coord1:2379,coord2:2379,coord3:2379). Gateways and stores use this list to failover on lease-not-held errors.stores[i]:addris what other processes dial;listen_addris what the store binds locally. Usually the same on host scope; different on docker scope (0.0.0.0:20160vsnokv-store-1:20160).- Store workdir resolution (
ResolveStoreWorkDir):- store-scoped override (
stores[i].work_dir/docker_work_dir) - global template (must contain
{id}) - empty — caller falls back to its own default
- store-scoped override (
start_key/end_keyaccept plain strings,hex:<bytes>, or base64. Empty or"-"means unbounded.leader_store_idis bootstrap metadata only. Runtime routing comes from coordinator (GetRegionByKey), never from this field.
CLI integration
nokv meta-root --config <file> --node-id N resolves --peer,
--transport-addr, --workdir from the meta_root section. Explicit flags
still override.
nokv coordinator --config <file> resolves --addr from coordinator.addr
and --root-peer from meta_root.peers. This is how docker-compose keeps
meta-root addresses in a single file.
Programmatic loading:
cfg, _ := config.LoadFile("raft_config.example.json")
if err := cfg.Validate(); err != nil { /* handle */ }
peers := cfg.MetaRootServicePeers("docker") // id → gRPC addr
Related tools
scripts/dev/cluster.sh --config raft_config.example.jsonscripts/ops/serve-meta-root.sh --config ... --node-id 1scripts/ops/serve-coordinator.sh --config ... --coordinator-id c1nokv-config stores/nokv-config regions— query current rooted topology (not the JSON). Use these to diff against the deployment manifest after scheduler operations.