Skip to Content
We are live but in Staging 🎉
Reservation & Hot CacheOverview

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 get on 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 its capacity_gb of 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:

FieldMeaning
capacity_gbTotal 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).
dedicatedtrue = dedicated (metered) reservation; false = a budget within the shared tier.
floors.sql_gbMinimum resident GB guaranteed to the SQL engine. 0 = no floor.
floors.vector_gbMinimum resident GB guaranteed to the Vector engine. 0 = no floor.
floors.graph_gbMinimum resident GB guaranteed to the Graph engine. 0 = no floor.
exclude_tablesTables kept out of the residency budget entirely. A k3-side hint — never sent to the plane.
priorityReservation 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.
generationThe monotonic author version k3 stamps on each set.
stateRESERVATION_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_mbHow much more room the cluster needs before a PENDING_CAPACITY reservation can promote. 0 when state is ACTIVE.
appliedBest-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 empty exclude_tables, priority: 0, and an absent applied are 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 sales

set 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:

MethodRouteRPC
POST/:bucket/tables/reservationSetReservation — author (create or replace) the reservation
GET/:bucket/tables/reservationGetReservation — intent + best-effort applied plane read-back; free-tier zero shape when unset
DELETE/:bucket/tables/reservationDeleteReservation — 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