Skip to content

Commit

Permalink
Document nested transactions with SAVEPOINTs
Browse files Browse the repository at this point in the history
Fixes #5953.

Summary of changes:

- Update SAVEPOINT page with more examples of "generalized" aka "nested"
  savepoints adapted from the RFC, in addition to the existing "retry"
  savepoints info

- Add a new SHOW SAVEPOINT STATUS statement page (with syntax diagram),
  and add it to the sidebar

- Update RELEASE SAVEPOINT docs to clarify "retry" savepoints
  vs. "generalized/nested" savepoints, and update the examples as well

- Update the ROLLBACK docs to mention rollbacks to savepoints more
  explicitly.  Also, update the diagram to reflect that
  'cockroach_restart' is no longer the only allowed savepoint name.

- Add information on how CockroachDB handles savepoints and locking
  vs. Postgres

- Add a new "nested transactions" section to the 'Transactions' page,
  including descriptions of how COMMIT, ROLLBACK, RELEASE SAVEPOINT, and
  ROLLBACK TO SAVEPOINT relate to each other

- Draw distinctions in several places between "retry" savepoints and
  "nested" or "generalized" savepoints, since they are different

- Update mentions of savepoints on 'SQL Statements' and 'Postgres
  Compatibility' to note that they are supported now
  • Loading branch information
rmloveland committed Apr 6, 2020
1 parent a0d4629 commit 1dec38d
Show file tree
Hide file tree
Showing 21 changed files with 493 additions and 98 deletions.
6 changes: 6 additions & 0 deletions _includes/sidebar-data-v20.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,12 @@
"/${VERSION}/show-statistics.html"
]
},
{
"title": "<code>SHOW SAVEPOINT STATUS</code>",
"urls": [
"/${VERSION}/show-savepoint-status.html"
]
},
{
"title": "<code>SHOW TABLES</code>",
"urls": [
Expand Down
8 changes: 3 additions & 5 deletions _includes/v20.1/misc/customizing-the-savepoint-name.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
Set the `force_savepoint_restart` [session variable](set-vars.html#supported-variables) to `true` to enable using a custom name for the restart savepoint (for example, because you are using an ORM that wants to use its own names for savepoints).
Set the `force_savepoint_restart` [session variable](set-vars.html#supported-variables) to `true` to enable using a custom name for the [retry savepoint](advanced-client-side-transaction-retries.html#retry-savepoints) (for example, because you are using an ORM that wants to use its own names for savepoints).

Once this variable is set, the [`SAVEPOINT`](savepoint.html) statement will accept any name for the savepoint, not just `cockroach_restart`. This allows compatibility with existing code that uses a single savepoint per transaction as long as that savepoint occurs before any statements that access data stored in non-virtual tables.
Once this variable is set, the [`SAVEPOINT`](savepoint.html) statement will accept any name for the retry savepoint, not just `cockroach_restart`. In addition, it causes every savepoint name to be equivalent to `cockroach_restart`, therefore disallowing the use of [nested transactions](transactions.html#nested-transactions).

{{site.data.alerts.callout_danger}}
The `force_savepoint_restart` variable changes the semantics of CockroachDB savepoints so that `RELEASE SAVEPOINT <your-custom-name>` functions as a real commit. Note that the existence of this variable and its behavior does not change the fact that CockroachDB savepoints can only be used as a part of the transaction retry protocol.
{{site.data.alerts.end}}
This feature exists to support applications that want to use the [advanced client-side transaction retry protocol](advanced-client-side-transaction-retries.html), but cannot customize the name of savepoints to be `cockroach_restart`.
3 changes: 0 additions & 3 deletions _includes/v20.1/misc/savepoint-limitations.md

This file was deleted.

39 changes: 17 additions & 22 deletions _includes/v20.1/sql/diagrams/rollback_transaction.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
<div><svg width="518" height="68">

<polygon points="9 17 1 13 1 21"></polygon>
<polygon points="17 17 9 13 9 21"></polygon>
<rect x="31" y="3" width="92" height="32" rx="10"></rect>
<rect x="29" y="1" width="92" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="39" y="21">ROLLBACK</text>
<rect x="163" y="35" width="38" height="32" rx="10"></rect>
<rect x="161" y="33" width="38" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="171" y="53">TO</text>
<rect x="221" y="35" width="98" height="32" rx="10"></rect>
<rect x="219" y="33" width="98" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="229" y="53">SAVEPOINT</text>

<rect x="339" y="35" width="132" height="32"></rect>
<rect x="337" y="33" width="132" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="347" y="53">cockroach_restart</text>

<path class="line" d="m17 17 h2 m0 0 h10 m92 0 h10 m20 0 h10 m0 0 h318 m-348 0 h20 m328 0 h20 m-368 0 q10 0 10 10 m348 0 q0 -10 10 -10 m-358 10 v12 m348 0 v-12 m-348 12 q0 10 10 10 m328 0 q10 0 10 -10 m-338 10 h10 m38 0 h10 m0 0 h10 m98 0 h10 m0 0 h10 m132 0 h10 m23 -32 h-3"></path>
<polygon points="509 17 517 13 517 21"></polygon>
<polygon points="509 17 501 13 501 21"></polygon>
</svg></div>
<div><svg width="515" height="69">
<polygon points="9 17 1 13 1 21"></polygon>
<polygon points="17 17 9 13 9 21"></polygon>
<rect x="31" y="3" width="92" height="32" rx="10"></rect>
<rect x="29" y="1" width="92" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="39" y="21">ROLLBACK</text>
<rect x="163" y="35" width="38" height="32" rx="10"></rect>
<rect x="161" y="33" width="38" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="171" y="53">TO</text>
<rect x="221" y="35" width="100" height="32" rx="10"></rect>
<rect x="219" y="33" width="100" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="229" y="53">SAVEPOINT</text><a xlink:href="sql-grammar.html#savepoint_name" xlink:title="savepoint_name">
<rect x="341" y="35" width="126" height="32"></rect>
<rect x="339" y="33" width="126" height="32" class="nonterminal"></rect>
<text class="nonterminal" x="349" y="53">savepoint_name</text></a><path class="line" d="m17 17 h2 m0 0 h10 m92 0 h10 m20 0 h10 m0 0 h314 m-344 0 h20 m324 0 h20 m-364 0 q10 0 10 10 m344 0 q0 -10 10 -10 m-354 10 v12 m344 0 v-12 m-344 12 q0 10 10 10 m324 0 q10 0 10 -10 m-334 10 h10 m38 0 h10 m0 0 h10 m100 0 h10 m0 0 h10 m126 0 h10 m23 -32 h-3"></path>
<polygon points="505 17 513 13 513 21"></polygon>
<polygon points="505 17 497 13 497 21"></polygon></svg></div>
15 changes: 15 additions & 0 deletions _includes/v20.1/sql/diagrams/show_savepoint_status.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div><svg width="335" height="37">
<polygon points="9 17 1 13 1 21"></polygon>
<polygon points="17 17 9 13 9 21"></polygon>
<rect x="31" y="3" width="64" height="32" rx="10"></rect>
<rect x="29" y="1" width="64" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="39" y="21">SHOW</text>
<rect x="115" y="3" width="100" height="32" rx="10"></rect>
<rect x="113" y="1" width="100" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="123" y="21">SAVEPOINT</text>
<rect x="235" y="3" width="72" height="32" rx="10"></rect>
<rect x="233" y="1" width="72" height="32" class="terminal" rx="10"></rect>
<text class="terminal" x="243" y="21">STATUS</text>
<path class="line" d="m17 17 h2 m0 0 h10 m64 0 h10 m0 0 h10 m100 0 h10 m0 0 h10 m72 0 h10 m3 0 h-3"></path>
<polygon points="325 17 333 13 333 21"></polygon>
<polygon points="325 17 317 13 317 21"></polygon></svg></div>
1 change: 1 addition & 0 deletions _includes/v20.1/sql/retry-savepoints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A savepoint defined with the name `cockroach_restart` is a "retry savepoint" and is used to implement [advanced client-side transaction retries](advanced-client-side-transaction-retries.html). For more information, see [Retry savepoints](advanced-client-side-transaction-retries.html#retry-savepoints).
3 changes: 3 additions & 0 deletions _includes/v20.1/sql/savepoint-ddl-rollbacks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{site.data.alerts.callout_danger}}
Rollbacks to savepoints over [DDL](https://en.wikipedia.org/wiki/Data_definition_language) statements are only supported if you're rolling back to a savepoint created at the beginning of the transaction.
{{site.data.alerts.end}}
12 changes: 12 additions & 0 deletions _includes/v20.1/sql/savepoints-and-row-locks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CockroachDB supports exclusive row locks.

- In PostgreSQL, row locks are released/cancelled upon [`ROLLBACK TO SAVEPOINT`][rts].
- In CockroachDB, row locks are preserved upon [`ROLLBACK TO SAVEPOINT`][rts].

This is an architectural difference in v20.1 that may or may not be lifted in a later CockroachDB version.

The code of client applications that rely on row locks must be reviewed and possibly modified to account for this difference. In particular, if an application is relying on [`ROLLBACK TO SAVEPOINT`][rts] to release row locks and allow a concurrent transaction touching the same rows to proceed, this behavior will not work with CockroachDB.

<!-- Reference Links -->

[rts]: rollback-transaction.html
1 change: 0 additions & 1 deletion _includes/v20.1/sql/unsupported-postgres-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@
- GEOSPATIAL functions and indexes
- Drop primary key
- XML Functions
- Savepoints
- Column-level privileges
- XA syntax
2 changes: 1 addition & 1 deletion v19.1/rollback-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toc: true

The `ROLLBACK` [statement](sql-statements.html) aborts the current [transaction](transactions.html), discarding all updates made by statements included in the transaction.

When using [advanced client-side transaction retries](advanced-client-side-transaction-retries.html), use `ROLLBACK TO SAVEPOINT` to handle a transaction that needs to be retried (identified via the `40001` error code or `retry transaction` string in the error message), and then re-execute the statements you want the transaction to contain.
When using [advanced client-side transaction retries](advanced-client-side-transaction-retries.html), use `ROLLBACK TO SAVEPOINT` to handle a transaction that needs to be retried (identified via the `40001` error code or `restart transaction` string in the error message), and then re-execute the statements you want the transaction to contain.

## Synopsis

Expand Down
2 changes: 1 addition & 1 deletion v19.2/rollback-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toc: true

The `ROLLBACK` [statement](sql-statements.html) aborts the current [transaction](transactions.html), discarding all updates made by statements included in the transaction.

When using [advanced client-side transaction retries](advanced-client-side-transaction-retries.html), use `ROLLBACK TO SAVEPOINT` to handle a transaction that needs to be retried (identified via the `40001` error code or `retry transaction` string in the error message), and then re-execute the statements you want the transaction to contain.
When using [advanced client-side transaction retries](advanced-client-side-transaction-retries.html), use `ROLLBACK TO SAVEPOINT` to handle a transaction that needs to be retried (identified via the `40001` error code or `restart transaction` string in the error message), and then re-execute the statements you want the transaction to contain.

## Synopsis

Expand Down
18 changes: 14 additions & 4 deletions v20.1/advanced-client-side-transaction-retries.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If you are an application developer who needs to implement an application-level

## Overview

To improve the performance of transactions that fail due to contention, CockroachDB includes a set of statements (listed below) that let you retry those transactions. Retrying transactions using these statements has the following benefits:
To improve the performance of transactions that fail due to [contention](performance-best-practices-overview.html#understanding-and-avoiding-transaction-contention), CockroachDB includes a set of statements (listed below) that let you retry those transactions. Retrying transactions using these statements has the following benefits:

1. When you use savepoints, you "hold your place in line" between attempts. Without savepoints, you're starting from scratch every time.
2. Transactions increase their priority each time they're retried, increasing the likelihood they will succeed. This has a lesser effect than #1.
Expand All @@ -32,21 +32,31 @@ A retryable transaction goes through the process described below, which maps to

1. The transaction starts with the [`BEGIN`](begin-transaction.html) statement.

2. The [`SAVEPOINT`](savepoint.html) statement declares the intention to retry the transaction in the case of contention errors. Note that CockroachDB's savepoint implementation does not support all savepoint functionality, such as nested transactions. It must be executed after [`BEGIN`](begin-transaction.html) but before the first statement that manipulates a database.
2. The [`SAVEPOINT`](savepoint.html) statement shown here is a [retry savepoint](#retry-savepoints); that is, it declares the intention to retry the transaction in the case of contention errors. It must be executed after [`BEGIN`](begin-transaction.html) but before the first statement that manipulates a database. Although [nested transactions](savepoint.html#savepoints-for-nested-transactions) are supported in versions of CockroachDB >= 20.1, a retry savepoint must be the outermost savepoint in a transaction.

3. The statements in the transaction are executed.

4. If a statement returns a retry error (identified via the `40001` error code or `"retry transaction"` string at the start of the error message), you can issue the [`ROLLBACK TO SAVEPOINT`](rollback-transaction.html) statement to restart the transaction and increase the transaction's priority. Alternately, the original [`SAVEPOINT`](savepoint.html) statement can be reissued to restart the transaction.

You must now issue the statements in the transaction again.

In cases where you do not want the application to retry the transaction, you can simply issue [`ROLLBACK`](rollback-transaction.html) at this point. Any other statements will be rejected by the server, as is generally the case after an error has been encountered and the transaction has not been closed.
In cases where you do not want the application to retry the transaction, you can issue [`ROLLBACK`](rollback-transaction.html) at this point. Any other statements will be rejected by the server, as is generally the case after an error has been encountered and the transaction has not been closed.

5. Once the transaction executes all statements without encountering contention errors, execute [`RELEASE SAVEPOINT`](release-savepoint.html) to commit the changes. If this succeeds, all changes made by the transaction become visible to subsequent transactions and are guaranteed to be durable if a crash occurs.

In some cases, the [`RELEASE SAVEPOINT`](release-savepoint.html) statement itself can fail with a retry error, mainly because transactions in CockroachDB only realize that they need to be restarted when they attempt to commit. If this happens, the retry error is handled as described in step 4.

## Customizing the savepoint name
## Retry savepoints

A savepoint defined with the name `cockroach_restart` is a "retry savepoint" and is used to implement advanced client-side transaction retries. A retry savepoint differs from a [savepoint for nested transactions](savepoint.html#savepoints-for-nested-transactions) as follows:

- It must be the outermost savepoint in the transaction.
- After a successful [`RELEASE`](release-savepoint.html), a retry savepoint does not allow further use of the transaction. The next statement must be a [`COMMIT`](commit-transaction.html).
- It cannot be nested. Issuing `SAVEPOINT cockroach_restart` two times in a row only creates a single savepoint marker (this can be verified with [`SHOW SAVEPOINT STATUS`](show-savepoint-status.html)). Issuing `SAVEPOINT cockroach_restart` after `ROLLBACK TO SAVEPOINT cockroach_restart` reuses the marker instead of creating a new one.

Note that you can [customize the retry savepoint name](#customizing-the-retry-savepoint-name) to something other than `cockroach_restart` with a session variable if you need to.

## Customizing the retry savepoint name

{% include {{ page.version.version }}/misc/customizing-the-savepoint-name.md %}

Expand Down
1 change: 1 addition & 0 deletions v20.1/commit-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ If you are using transactions that CockroachDB will [automatically retry](transa
- [`RELEASE SAVEPOINT`](release-savepoint.html)
- [`ROLLBACK`](rollback-transaction.html)
- [`SAVEPOINT`](savepoint.html)
- [`SHOW SAVEPOINT STATUS`](show-savepoint-status.html)
2 changes: 1 addition & 1 deletion v20.1/detailed-sql-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ To understand the extent to which we support the standard SQL features, use the
| T241 | START TRANSACTION statement | Yes |
| T251 | SET TRANSACTION statement: LOCAL option | No |
| T261 | Chained transactions | No |
| T271 | Savepoints | No |
| T271 | Savepoints | Yes |
| T272 | Enhanced savepoint management | No |
| T281 | SELECT privilege with column granularity | No |
| T285 | Enhanced derived column names | No |
Expand Down
Loading

0 comments on commit 1dec38d

Please sign in to comment.