Skip to content

Guarantees

fdyno maps a DynamoDB action to one or more FoundationDB transactions. FoundationDB supplies the transaction guarantees. fdyno tests the mapping and its failure behavior. These guarantees do not cover unrelated HTTP calls or an underconfigured FoundationDB cluster.

Atomicity, application consistency, isolation, and durability have different scopes and failure modes.

Guarantees by operation

Assertion Scope Exception
A committed data-plane transaction is all-or-nothing. One FoundationDB transaction. BatchWriteItem, GSI backfill, backup/restore, and maintenance can span transactions.
One-transaction operations are strictly serializable. Keys and ranges read and written by that transaction. Pagination is a new snapshot per page; concurrent requests may be ordered either way.
A successful write has committed before fdyno replies. The FoundationDB cluster selected by the deployment. A lost response can leave the client with an unknown outcome; cluster redundancy determines survival of hardware failure.
Base items and active index entries change together. Existing registered GSIs/LSIs on a normal item mutation. A new GSI is incomplete while its status is CREATING.
A stream record and its item mutation commit together. Stream-enabled, state-changing writes. Delivery and consumer effects are not exactly-once; order is per shard.
A live ClientRequestToken deduplicates the same transaction. TransactWriteItems within the 10-minute token window. Tokenless retries and replay after the window are not deduplicated.
An fdyno process can be replaced without replaying database state. State persisted in FoundationDB. Configuration, metrics, in-flight requests, and some compatibility state are process-local.
A large restore is invisible until complete and can resume after process loss. Durable staged source, target identity, progress, lease, and fence in FoundationDB. Small restores are one transaction; deleting a CREATING target cancels its job.
Historical PITR is never simulated with current data. Continuous-backup enablement and RestoreTableToPointInTime. Unsupported and returned as an explicit unavailable error; use tested backups.
Conformance results establish the selected tested API cases. Listed suite revisions and scenarios. They do not prove unselected options, replicated failover, off-host recovery, or every concurrent history.

The operation-to-transaction map is in Transactions, and cross-page and concurrent-read behavior is in Consistency model.

Assertion. For a normal state-changing item operation, fdyno commits the base item (including chunks), old-index removal, new-index entries, and an optional change-stream record in one FoundationDB transaction. A tokened TransactWriteItems also commits its idempotency record in that transaction. A reader cannot observe only part of that commit.

Scope. This applies to PutItem, UpdateItem, DeleteItem, TransactWriteItems, and accepted write statements in PartiQL ExecuteTransaction. A TransactWriteItems request may span tables, provided the whole request fits one FoundationDB transaction.

Exception and failure behavior. Validation and failed conditions commit nothing. A process failure before commit exposes none of the buffered writes. A process or network failure after commit may prevent the response from arriving, but does not turn one commit into a partial commit. BatchWriteItem is explicitly non-atomic and may split an oversized valid batch; GSI backfill, backup, restore, TTL cleanup, and stream trimming use bounded multi-transaction protocols.

Evidence. The write set is assembled in item_ops.go, txn_ops.go, fdb_store.go, and streams.go. Transaction rollback is exercised by ExtendDB transaction tests and nubo-db transaction tests. The underlying all-or-nothing commit guarantee is FoundationDB's transaction guarantee.

Consistency: invariants must be expressed in the transaction

Assertion. A transaction can enforce an invariant that it reads and checks. Every writer must preserve the same invariant in its transaction. Conflicting attempts cannot both commit from stale data. Conditions such as attribute_not_exists(pk) and read-modify-write updates therefore have one serializable outcome.

Scope. This covers the keys and ranges fdyno reads through FoundationDB's normal, non-snapshot transaction API. Point and range reads create conflict ranges, and a conflicting attempt is retried against a newer read version.

Exception and failure behavior. The ā€œCā€ in ACID does not invent application rules. An invariant omitted from conditions or split over separate API calls is not made atomic by fdyno. Retryable conflicts can increase latency and eventually fail at the request deadline; they do not authorize a stale commit.

Evidence. Retry and deadline handling is in transaction_runner.go. Focused tests cover one-winner conditional writes and concurrent counters, list/set updates, and nested updates in test_conditional_writes.py and test_concurrency.py. These are targeted histories, not a formal verification of every workload.

Isolation and read recency: strict serializability per transaction

Assertion. A successful one-transaction operation is strictly serializable. It can be placed at one instant between invocation and response, and a transaction started after another operation completed cannot be ordered before that completed operation.

Scope. GetItem, one Query or Scan page, BatchGetItem, and TransactGetItems each read one FoundationDB MVCC version. Normal fdyno reads use that transactional path even when ConsistentRead is false or omitted.

Exception and failure behavior. Concurrent operations may be serialized in either order. LastEvaluatedKey is a key position, not a retained read version, so a multi-page query or scan is not one repeatable snapshot. Separate GetItem calls are separate transactions. ConsistentRead=true remains invalid on a GSI for DynamoDB request compatibility even though active GSI maintenance is synchronous. If FoundationDB cannot supply a read version, fdyno fails the request rather than serving a process-local stale copy.

Evidence. The operation boundaries are implemented in query_ops.go, batch_ops.go, and txn_ops.go. FoundationDB documents global ACID transactions with strict serializability in its developer guide. fdyno publishes one narrow two-instance history for dropped responses, process loss, and single-FDB restart. It is not Jepsen or Elle and does not inject an fdyno-to-FDB network partition. Replicated failover and broad history analysis remain evidence gaps.

Durability: success means FoundationDB accepted the commit

Assertion. fdyno sends a successful write response only after the FoundationDB commit completes. No fdyno-local write-behind queue or WAL must later be flushed.

Scope. Durability covers the committed keys in the attached FoundationDB database. Table metadata, items, chunks, indexes, stream records, transaction-token records, and fdyno backup objects are durable database state.

Exception and failure behavior. Durability against machine, disk, zone, or site failure is only as strong as the FoundationDB redundancy and backup design selected by the operator. More fdyno replicas do not add storage replicas. A timeout while a commit is in flight is explicitly returned as an outcome that may be unknown; an error or missing HTTP response is not proof of rollback. fdyno publishes no general RPO, RTO, or availability SLO.

Evidence. Commit acknowledgement and unknown-outcome mapping are in transaction_runner.go. The bounded two-instance campaign is scripts/fault-smoke.sh. Its checked invariants and limits are in Failure testing. FoundationDB's cluster is the durable-state owner; deployment responsibilities are spelled out in Durability & recovery and Deployment & operations.

Secondary indexes: synchronous after registration

Assertion. A successful normal item mutation cannot expose a new base item with an old active GSI/LSI entry. Old entries are removed and new projected entries are written in the base mutation's transaction.

Scope. This applies to indexes already registered in table metadata, including a GSI registered as CREATING for live writes after the registration commit.

Exception and failure behavior. Existing rows are copied into a newly added GSI across bounded backfill transactions. Until status becomes ACTIVE, old rows may be missing. A stopped backfill is retried on process startup; readiness does not wait for it. Index projection also increases transaction size and latency, so a logically valid item can fail when the amplified FoundationDB write is too large.

Evidence. Index writes are in fdb_store.go, and the CREATING → backfill → ACTIVE protocol is in table_ops.go. Black-box coverage includes test_gsi.py, test_lsi.py, and test_gsi_updatetable.py.

Streams: atomic capture and per-shard commit order

Assertion. For a stream-enabled table, a state-changing mutation and its stream record commit together. Versionstamped keys order records by FoundationDB commit order within each shard; records for one partition key remain in one shard.

Scope. The guarantee covers stream record creation and stored ordering. With the default single shard, one table has one stored commit order. With multiple static shards, ordering is per shard and therefore per partition key.

Exception and failure behavior. This is not exactly-once delivery or exactly-once sink processing. A consumer can replay a sequence number and must checkpoint and apply records idempotently. There is no global API delivery order across shards. Iterators do not expire, and trimming can remove unread history without an explicit gap error. Large records use versioned, integrity-checked chunks. They still increase the size of the item mutation's FoundationDB transaction.

Evidence. Atomic record creation and versionstamps are in streams.go, with client-level coverage in test_streams.py. Consumer and retention boundaries are detailed in Change streams.

Retry deduplication: token and data share the commit

Assertion. Repeating the same TransactWriteItems request with the same live ClientRequestToken does not apply the mutation again. Reusing that token for a different request fails with IdempotentParameterMismatchException.

Scope. The request fingerprint and token timestamp are stored in FoundationDB in the same transaction as the protected writes. The behavior survives process restart and works across fdyno instances for the 10-minute window.

Exception and failure behavior. A client retry does not add a token to other APIs. A tokenless read-modify-write can apply twice after a lost response. A replay after the token window is a new request. Malformed token records fail closed.

Evidence. The durable format and window are in idempotency.go. Cross-instance, concurrent, replay, mismatch, and expiry behavior is exercised in retry_safety_integration_test.go, retry_safety_test.go, and test_transact.py. No end-to-end test currently injects a real lost commit acknowledgement; see Reliable writes for required client behavior.

Process replacement: durable state is not tied to one server

Assertion. Replacing an fdyno process does not require replaying table data. Another correctly configured process attached to the same FoundationDB database can read committed user state.

Scope. This covers schema, items, indexes, stream topology and records, backups, restore jobs, TTL configuration, receipts, transaction tokens, and worker state.

Exception and failure behavior. Credentials, environment defaults, open requests, metrics, token-GC cursor, and some compatibility configuration are process-local. Process replacement does not recover a failed FoundationDB cluster.

Evidence. The state boundary is visible in types.go, lease.go, ttl.go, and Architecture overview.

Not guaranteed

  • They do not make BatchWriteItem atomic or make a sequence of HTTP calls one transaction.
  • They do not provide a snapshot across query/scan pages.
  • They do not provide multi-Region replication, detached reads, or writes while FoundationDB is unavailable.
  • They do not make a CREATING GSI complete, a stream consumer exactly-once, or an in-cluster backup independent disaster recovery.
  • They do not specify a throughput floor, availability percentage, RPO, or RTO.

Before relying on these guarantees, review Tradeoffs, Limits, Compatibility, and the operator-owned failure domain in Durability & recovery.