You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+46-43Lines changed: 46 additions & 43 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,32 +1,34 @@
1
1
# minikv
2
2
3
-
Minimal, S3-compatible distributed key-value store. Keys and metadata are stored in LevelDB; values (object bytes) live on nginx WebDAV volume servers.
3
+
A distributed key-value store written in Rust.
4
+
5
+
**minikv** stores keys and metadata in LevelDB and object bytes on nginx WebDAV volume servers. Each object is replicated across a configurable number of volumes. The server handles routing, replication, and metadata; nginx handles the data.
**GET/HEAD flow:** The coordinator looks up the key in LevelDB, probes volume servers to find a live replica, then returns `X-Accel-Redirect` to the frontend nginx. nginx fetches the object body directly from the volume server and streams it to the client - the coordinator is never in the data path. Response headers (`Content-Type`, `Content-Blake3`, `Key-Balance`) come from coordinator metadata.
23
+
**GET/HEAD flow:** The server looks up the key in LevelDB, probes volume servers to find a live replica, then returns `X-Accel-Redirect` to the frontend nginx. nginx fetches the object body directly from the volume server and streams it to the client. The server is not in the data path for reads. Response headers (`Content-Type`, `Content-Blake3`, `Key-Balance`) come from stored metadata.
22
24
23
-
**PUT flow:** The coordinator writes a soft-delete sentinel to LevelDB, replicates the object body to all replica volumes, optionally computes a BLAKE3 checksum, then marks the key as fully present.
25
+
**PUT flow:** The server writes a soft-delete sentinel to LevelDB, replicates the object body to all replica volumes, optionally computes a BLAKE3 checksum, then marks the key as fully present.
24
26
25
27
## Hashing
26
28
27
-
This project uses **BLAKE3**for all content-addressing and volume selection.
29
+
BLAKE3 is used for all content-addressing (`key_to_path`) and volume selection (`key_to_volume`).
28
30
29
-
> ⚠️ The hash function used for `key_to_path` and `key_to_volume`determines the physical layout of all stored data. Changing it after data is written is a **breaking change** requiring a full rebalance.
31
+
> The hash function determines the physical layout of all stored data. Changing it after data is written is a breaking change and requires a full rebalance.
30
32
31
33
## Record Wire Format
32
34
@@ -43,19 +45,20 @@ Each LevelDB value encodes object metadata as a compact byte string:
> Always supply `Content-Type` on PUT. It is stored in LevelDB and returned on all subsequent GET/HEAD requests. Objects stored without `Content-Type` will be served as `application/octet-stream`.
90
+
It is recommended to supply a `Content-Type`header on **PUT**. It is stored in LevelDB and returned on subsequent GET/HEAD requests, allowing clients and browsers to handle the response correctly without guessing the format. Objects stored without one will be served as `application/octet-stream`.
--fallback <host:port> Fallback for missing keys [env: MINIKV_FALLBACK]
130
133
--protect Require UNLINK before DELETE [env: MINIKV_PROTECT]
131
134
--checksum Store BLAKE3 digest on PUT [env: MINIKV_CHECKSUM]
@@ -137,31 +140,31 @@ All flags can be set via environment variables. Duration values accept `1s`, `50
137
140
138
141
### rebuild
139
142
140
-
Reconstructs LevelDB by scanning nginx autoindex JSON listings on all volume servers. This is a **destructive** operation. It clears the existing DB before scanning. Use when LevelDB is lost but volume data is intact.
143
+
Reconstructs LevelDB by scanning nginx autoindex JSON listings on all volume servers. **Destructive**: clears the existing DB before scanning. Use when LevelDB is lost but volume data is intact.
141
144
142
-
> `Content-Type` metadata cannot be recovered during rebuild. It exists only in LevelDB, never on volume servers. Objects will be served as `application/octet-stream` until re-PUT.
145
+
`Content-Type` metadata cannot be recovered during rebuild. It exists only in LevelDB, never on volume servers. Affected objects will be served as `application/octet-stream` until re-PUT with a `Content-Type` header.
143
146
144
147
### rebalance
145
148
146
149
Moves all keys to their ideal volume set as computed by the current `--volumes` list. Run after adding or removing volume servers.
147
150
148
151
## Consistency Model
149
152
150
-
-**PUT** is atomic at the record level. The key is marked soft-deleted (in-progress sentinel) before any volume write and marked fully present only after all replicas succeed. A crash mid-write leaves a soft-deleted key that can be cleaned up manually.
153
+
-**PUT** is atomic at the record level. The key is marked soft-deleted (in-progress sentinel) before any volume write, and marked fully present only after all replicas succeed. A crash mid-write leaves a soft-deleted key that can be cleaned up manually.
151
154
-**No read-after-write guarantee across replicas.** GET probes volumes in random order and returns the first live replica.
152
155
-**Rebalance** clears the stored hash for the moved object. The body is not re-verified during rebalance.
153
156
-**Soft delete (UNLINK)** removes the key from client visibility immediately. The object bytes remain on volume servers until a hard DELETE is issued.
154
157
155
158
## Content-Type and X-Accel-Redirect
156
159
157
-
When `--accel-redirect` is enabled the coordinator returns `X-Accel-Redirect` instead of `302`. The frontend nginx intercepts this, fetches the object body from the volume server internally, and sends it to the client. Because the body comes from nginx's internal subrequest (not the coordinator response), headers are injected via nginx variable persistence:
160
+
When `--accel-redirect` is enabled the server returns `X-Accel-Redirect` instead of `302`. The frontend nginx intercepts this, fetches the object body from the volume server internally, and sends it to the client. Because the body comes from nginx's internal subrequest rather than the server response, headers are carried across via nginx variable persistence:
158
161
159
-
1.Coordinator sets `X-Content-Type: image/png` on its response.
160
-
2. nginx captures this as `$upstream_http_x_content_type` - a variable that persists across the internal redirect.
162
+
1.The server sets `X-Content-Type: image/png` on its response.
163
+
2. nginx captures this as `$upstream_http_x_content_type`, a variable that persists across the internal redirect.
161
164
3. The `/accel/` location suppresses the volume's `Content-Type` and replaces it with `$upstream_http_x_content_type`.
162
165
163
-
In plain `302` mode, the coordinator sets `Content-Type`directly and the client receives it on the HEAD response. The GET redirect goes to the volume server which returns `application/octet-stream`- this is a known limitation of redirect mode.
166
+
In plain `302` mode, the server sets `Content-Type`on the redirect response and the client receives it on HEAD. The GET redirect goes to the volume server which returns `application/octet-stream`regardless of stored metadata. This is a known limitation of redirect mode.
164
167
165
168
## License
166
169
167
-
This project is licensed under the **GNU General Public License v2 (GPLv2)**. See [`LICENSE`](./LICENSE).
170
+
GNU General Public License v2 (GPLv2). See [`LICENSE`](./LICENSE).
0 commit comments