Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Unreleased]

- PostgreSQL `kv/sync` quiet-prefix polls can seek by byte-ordered `(space, key)` rather than scanning newer keys outside the prefix. The new index leaves empty-poll cursors and feed contents unchanged; SQLite already has the matching primary key (TC-737).
- Account delegation session discovery keyset-pages delegation rows independently of ability fan-out, using a composite delegator/id index so large grant sets are not truncated (TC-1195).
- `/attestation` quotes the SHA-256 of `key_binding` as REPORTDATA and returns it as `key_binding_sha256`; the quote no longer carries the raw binding. Before answering 200 the node checks that the returned TDX v4 quote's REPORTDATA field holds that digest (a structural check; it does not verify the quote). When the TEE can't produce a bound quote, the endpoint returns 503 instead of 200 `mode: "classic"`, and the dstack client reports a guest-agent error status instead of a parse error. `nonce` must be 1-64 characters of `A-Z a-z 0-9 - _` (400 otherwise), and the endpoint now shares the public routes' per-IP rate limit. Verifiers recompute the digest from their own nonce and expected DID and must still verify the quote; see `docs/attestation.md` (TC-963).

Expand Down
18 changes: 18 additions & 0 deletions docs/kv-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ root feeds advertise `kv-sync-root` alongside `kv-sync-v1` in `/info`.
the node's reads. It is not an error. Keep paging with the returned cursor;
the next request makes progress.

The PostgreSQL node checks a non-root prefix by seeking the exact key and
its descendants in byte-key order before reading the sequence-ordered feed.
If no key has a change after the cursor (or a live key at the bootstrap floor),
it returns the same cursor without scanning unrelated writes in a busy space.
The probe reads at most the selected prefix's keys; positive polls retain
commit ordering, tombstone handling, and whole-invocation pages.

### Pages and `limit`

All keys written or deleted by one invocation (for example a batch put) share
Expand Down Expand Up @@ -129,3 +136,14 @@ cursor.

Read audit records every poll. Poll on demand, or no more often than every
60 seconds.

On PostgreSQL, a `(space, key COLLATE "C")` index bounds a quiet-prefix poll
to keys inside that prefix even when other keys in the space keep changing.
The byte collation matches the prefix range predicate; the older feed-order
index still serves broad or active feeds. SQLite uses its existing
`(space, key)` primary key. This does not advance the cursor on an empty poll.

MySQL does not get this index: its prefix predicate casts `key` to binary,
which does not seek the normal `(space, key)` index. MySQL's `kv/sync`
sequence lock is currently marked unsupported/untested for newly created
spaces. This change does not claim MySQL quiet-prefix performance.
22 changes: 22 additions & 0 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,28 @@ gh workflow run docker.yml -R TinyCloudLabs/tinycloud-node --ref main \
release; only the node binary rolls back. Check
`tinycloud-core/src/migrations` between the two revisions first: a binary
rollback across a schema migration is not DB-safe.
- After TC-737's `m20261015_010000_current_kv_prefix_index` is recorded,
an older node binary cannot restart against that database: SeaORM rejects
unknown applied migration versions. Already-running older writers can keep
writing while PostgreSQL builds the additive index concurrently, but binary
rollback is not safe. Recover by rolling forward through the coordinated
release sequence, not by promoting an older image.
- TC-737 also orders PostgreSQL `tinycloud.kv/list` pages by key bytes,
matching SQLite's BINARY order. Newly issued list cursors use version 2.
A valid version-1 cursor from before this cutover returns HTTP 400 with
"restart listing"; the client must omit `x-tinycloud-cursor` and begin a
new listing. The node rejects rather than silently skipping or repeating
keys when a database's native collation differs from byte order.
- PostgreSQL `tinycloud.kv/sync` prefix polls first inspect at most 64 raw
sequence-index candidates; dense continuations use a bounded sequence feed,
while a full window without a match falls back to the C-ordered key index.
Empty polls preserve the supplied cursor bytes. The root feed and
SQLite/MySQL behavior are unchanged.
- The PostgreSQL migrator supports `up` and `down` across the concurrent index.
`fresh`, `refresh`, and `reset` reject before changing schema or migration
history; SeaORM's inherited implementations require one transaction and
cannot execute `CREATE/DROP INDEX CONCURRENTLY`. SQLite and MySQL keep their
standard migrator operations.
- The sealed-config preflight is skipped for rollbacks, and the post-deploy
`/version` check expects `rollback_image_version`. Run the same manual
verification as for a release.
Expand Down
Loading
Loading