Reservation & Hot Cache
Every bucket’s SQL / Vector / Graph data lives on the tabled data plane, which serves hot (resident, RAM/disk-cached) data much faster than cold data rehydrated from the Objects layer. A reservation is the user-facing budget for how much resident capacity a bucket is entitled to.
Two tiers:
- Free shared tier (the default) — no reservation. The bucket competes for shared hot-cache capacity on a best-effort basis. Fine for development and small or latency-tolerant workloads.
reservation geton such a bucket returns the free-tier zero shape (it never errors on a missing reservation). - Dedicated (metered) — an explicit reservation with
dedicated: true. The bucket is guaranteed itscapacity_gbof resident capacity, and that capacity is billed (metered as GB-hours).
A reservation is a budget, never a pin list — “how much”, not “which tables”. Pinning specific tables hot is the SQL LOAD TABLE / RELEASE TABLE verb, separate from reservations. The plane owns the actual RAM/disk and per-node split; the control plane validates, meters, stamps a monotonic generation, and authors the reservation onto the plane.
Per-engine floors — one hot engine can’t starve the others
By default the whole capacity_gb total is shared: sql, vector, and graph residency all compete for it. Optional floors (PillarFloors) set the MINIMUM resident GB guaranteed to each engine:
| Field | Meaning |
|---|---|
capacity_gb | Total resident GB the bucket is entitled to. The plane owns the split beyond the floors. Rendered as a string in JSON (it’s a proto uint64). |
dedicated | true = dedicated (metered) reservation; false = a budget within the shared tier. |
floors.sql_gb | Minimum resident GB guaranteed to the SQL engine. 0 = no floor. |
floors.vector_gb | Minimum resident GB guaranteed to the Vector engine. 0 = no floor. |
floors.graph_gb | Minimum resident GB guaranteed to the Graph engine. 0 = no floor. |
exclude_tables | Tables kept out of the residency budget entirely. A k3-side hint — never sent to the plane. |
priority | Reservation priority hint, range -100..100 (higher packs first / may preempt strictly-lower dedicated reservations). A k3-side hint persisted for the operator/packer — never sent to the plane. |
generation | The monotonic author version k3 stamps on each set. |
state | RESERVATION_STATE_ACTIVE — held on the plane now — or RESERVATION_STATE_PENDING_CAPACITY — accepted and durable but not yet held because the cluster is short of room. A backordered reservation accrues no billing until it promotes. |
shortfall_mb | How much more room the cluster needs before a PENDING_CAPACITY reservation can promote. 0 when state is ACTIVE. |
applied | Best-effort read-back of what the plane actually holds (present, capacity_mb, dedicated, generation), from the engine’s GetDatabaseStats. Absent when the plane holds no reservation for the db or is unreachable. |
The floors must sum to ≤ capacity_gb. A floor of 0 means that engine holds no guaranteed minimum and competes for the unfloored remainder — so a bucket whose vector collections suddenly run hot cannot evict the SQL engine below its sql_gb floor, and vice versa.
JSON omits fields at their default. Because the response is protobuf-JSON, fields left at their zero value are dropped from the output. A shared-tier reservation with no floors reads back as just
{bucket, capacity_gb, floors: {}, generation, state}—dedicated: false, an emptyexclude_tables,priority: 0, and an absentappliedare all simply omitted, not missing from the schema.
CLI — dodil data reservation
Aliases: reserve, capacity. All subcommands take --bucket / -b (required).
# Reserve 32 GB of dedicated (metered) resident capacity
dodil data reservation set -b sales --capacity-gb 32 --dedicated
# 64 GB total with per-engine floors: SQL ≥ 16 GB, Vector ≥ 8 GB
dodil data reservation set -b sales --capacity-gb 64 --sql-gb 16 --vector-gb 8
# Keep a cold archive table out of the budget
dodil data reservation set -b sales --capacity-gb 32 --dedicated --exclude events_archive
# Inspect — intent + best-effort `applied` read-back from the plane
dodil data reservation get -b sales -o json
# Release — the bucket falls back to the free shared tier
dodil data reservation delete -b salesset flags: --capacity-gb, --dedicated, --sql-gb, --vector-gb, --graph-gb, --exclude (repeatable), --priority.
SetReservation creates or replaces — run set again with new values to resize; there is no separate update verb. The response echoes the applied intent including the stamped generation; get additionally returns applied — what the plane actually holds right now (best-effort read-back).
API — ReservationService
Three RPCs — SetReservation, GetReservation, DeleteReservation (dodil.data.reservation.v1), served over HTTP by the control plane on one route:
| Method | Route | RPC |
|---|---|---|
POST | /:bucket/tables/reservation | SetReservation — author (create or replace) the reservation |
GET | /:bucket/tables/reservation | GetReservation — intent + best-effort applied plane read-back; free-tier zero shape when unset |
DELETE | /:bucket/tables/reservation | DeleteReservation — release; returns released: true |
curl -sS -X POST "https://api.data.dodil.io/sales/tables/reservation" \
-H "Authorization: Bearer $DODIL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"capacityGb": "64",
"dedicated": true,
"floors": { "sqlGb": "16", "vectorGb": "8", "graphGb": "0" }
}'The org is always taken from the authenticated caller — never a request field. A caller can only reserve capacity for buckets its own org owns.
Console
- At bucket creation — the create dialog’s Hot data slider sets the initial reservation alongside the bucket.
- Afterwards — the bucket’s Capacity tab shows the current reservation (total, tier, per-engine floors, what the plane holds) and lets you resize or release it.
See also
- Data Engines — the sql / vector / graph planes this budget governs
- SQL → Concepts — the tabled engine and its serving lanes
- Connect & Adapters — the data-plane endpoints themselves