May 10, 2017·6 min read·engineeringcockroachdbdistributed-sqltransactionsarchitecture

CockroachDB 1.0 puts distributed transactions behind a familiar SQL interface

CockroachDB 1.0 reaches general availability with distributed ACID transactions and PostgreSQL-compatible clients. Transaction retries and launch-time limits remain part of the application contract.

Keeping SQL while distributing a database's writes requires more than translating a familiar query language. A transaction can touch rows on different machines, and the system must decide what to commit even when those machines communicate imperfectly. CockroachDB 1.0 reaches general availability on May 10 with distributed ACID transactions and consensus-based replication as central product claims.

The launch announcement by Spencer Kimball describes graduation from beta to a production-ready database. It also announces a $27 million Series B. The financing establishes commercial context, but the engineering question is the contract available to an application now, including the work still required when a transaction cannot complete on its first attempt.

I find serializable isolation by default a useful starting point. It asks the database to preserve a strong model while making its coordination costs visible. PostgreSQL-compatible clients lower the cost of connecting, but understanding CockroachDB's transaction behavior remains necessary for writing the application correctly.

Distributed SQL includes distributed transaction boundaries

The transaction guide at the launch commit defines transactions across arbitrary tables and rows even when the data is distributed. A successful transaction applies its mutations together. If it fails and aborts, the mutations do not become a partially committed application operation.

That property is useful for a familiar relational reason. An operation that changes related data needs one completion decision, even if the storage arrangement puts those rows on different nodes. Distribution should not force the caller to treat each row update as an independently successful business action.

Version 1.0 defaults to SERIALIZABLE isolation and also offers SNAPSHOT. The documented distinction is that snapshot isolation permits write skew, while serializable isolation does not permit those anomalies. Serializable transactions may consequently require more retries under contention. The default chooses the stronger behavior, with an execution consequence the client must understand.

The guide describes pending writes as locking the data they modify. A conflicting writer can wait for an earlier transaction, while distributed deadlock detection finds dependency cycles. Transaction priorities allow the system to resolve those cycles by aborting a dependency. An aborted operation then needs another attempt.

Retries are part of execution

CockroachDB can automatically retry individual statements and transactions received as a single batch. In those cases, the server has the statements together and can repeat the operation without another application decision between them. The guide distinguishes that case from a transaction whose statements arrive individually.

When an application reads a value, makes a decision, and sends another statement, the server cannot necessarily recreate that decision by replaying only the last request. The client needs retry logic around the transaction's work. A retry uses a later timestamp and may see different data, so calculations based on earlier reads must be performed again.

The documented retryable error has code 40001 or a message beginning retry transaction. Handling it is an expected part of transaction control. It should not be interpreted as evidence that the database permits a half-committed version of the operation. The transaction needs another attempt precisely because the system could not preserve the required execution on that attempt.

I consider this an acceptable tradeoff when it stays explicit. Strong isolation has a cost under conflicting work. Moving that cost into a defined retry protocol is easier to reason about than leaving an application to infer whether concurrent changes produced an invalid result.

The restart savepoint has a specific purpose

The guide supplies a special savepoint protocol for client retries. SAVEPOINT cockroach_restart must appear after BEGIN and before statements that manipulate the database. After a retryable error, ROLLBACK TO SAVEPOINT cockroach_restart restarts the transaction's work with increased priority.

For successful work, RELEASE SAVEPOINT cockroach_restart commits the transaction, followed by COMMIT to clear the connection for its next use. The release operation itself can report a retryable error, so reaching the end of the application's statements does not remove the need to handle that case.

This savepoint is a retry interface, not general nested-transaction support. The contemporary guide explicitly notes that the implementation does not provide all savepoint functionality. Familiar SQL spelling should not be used to infer a broader transaction facility than the version documents.

The distinction also affects external actions. A client retry protocol means application work inside the retried unit can execute again. An application must know which of its decisions depend on database reads and which actions occur outside the database transaction's all-or-nothing boundary. The database cannot roll back an unrelated external operation merely by restarting its own transaction.

Ambiguous results differ from retryable conflicts

The launch transaction guide separately describes ambiguous errors returned around commit. Inter-node communication failure can prevent a caller from knowing whether the transaction committed. That is uncertainty about the outcome, unlike an ordinary retryable conflict whose handling calls for another attempt.

A client must not simply equate every connection or commit error with proof that nothing happened. The guide suggests examining database state or choosing application-specific retry behavior to resolve ambiguity. The correct response depends on whether repeating the operation can cause an unintended second effect.

This is a distributed-systems property exposed through an otherwise familiar SQL workflow. The application can use a PostgreSQL-compatible driver and still need to distinguish failed execution from an unknown completion result. The protocol vocabulary reduces integration work without removing those different outcomes.

Consensus changes the availability model

The launch announcement calls the replication model multi-active availability and describes strongly consistent consensus-based replication using three or more active replicas. It contrasts that model with eventual consistency that requires conflict resolution. The stated intent is to preserve consistent database behavior while replicas handle failures.

Consensus also makes replica placement and communication part of the execution cost. A connection to a nearby node does not erase the need for coordination among the replicas responsible for data. The system's availability claim needs to be understood with the deployed topology, rather than as a promise that arbitrary partitions can all accept conflicting writes independently.

The announcement presents deployment on private infrastructure and public clouds, with support for orchestration or manual operations. That flexibility is relevant to placing a cluster, but it does not make every placement equivalent. Network distance remains an input to distributed work, and locality configuration describes the failure and latency relationships the system can use.

General availability includes documented limitations

The launch-time limitations page provides necessary context for production readiness. Large whole-table deletes and truncations run as a single transaction and can create severe memory and CPU pressure. The page also documents limits on transaction write volume and total update size.

Several SQL operations accumulate intermediate results in memory, including sorting, grouping, and some subqueries. Depending on the operation, exceeding memory can produce an error or crash a node. A distributed database still has per-node execution resources, and a query's logical size does not guarantee that every stage spreads evenly across the cluster.

The same page identifies an ordinary client-type hazard. unique_rowid() returns integers that JavaScript numbers cannot always represent exactly. The documented workaround is to cast the identifier to a string on the server before inspecting or using it in such a client. A familiar driver connection does not preserve an integer that the host language's chosen numeric type cannot represent.

For an existing table with an identifier column, the documented cast can be expressed directly in the query. The client receives the identifier as text:

SELECT CAST(id AS string) FROM my_table;

Schema operations also have launch-time restrictions, including dropping and recreating a table with the same name within one transaction. These details matter when evaluating existing migration tools. General availability means the project is offering this implementation for production use, with a documented set of capabilities and limitations, not claiming every PostgreSQL workflow already transfers unchanged.

Backup is distinct from live replication

The release includes distributed incremental backup and restore as a commercial capability. The launch article describes parallelizing backup tasks across cluster nodes and writing to configurable storage destinations. It also identifies a free non-distributed backup option. Those are separate packaging choices around preserving recoverable data.

Replication keeps an active database available through the system's consensus model. A backup preserves an earlier state for recovery requirements that live replicas alone do not satisfy. At launch, transaction retries, ambiguous outcomes, and the documented resource limits remain concrete application and operational responsibilities around CockroachDB's distributed SQL interface.