Skip to content

Commit f78f004

Browse files
AV-35207 - Restructure Distributed ACID Transactions docs (#273)
1 parent 9baf4c6 commit f78f004

10 files changed

Lines changed: 393 additions & 313 deletions

modules/ROOT/nav.adoc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@
1616
* xref:howtos:full-text-searching-with-sdk.adoc[Search]
1717
* xref:howtos:view-queries-with-sdk.adoc[MapReduce Views]
1818
19+
.Transactions
20+
* xref:howtos:distributed-acid-transactions-from-the-sdk.adoc[How-to Guide]
21+
** xref:howtos:transactions-single-query.adoc[Single Query Transactions]
22+
// TODO: Add this for .NET when available
23+
//** xref:howtos:transactions-tracing.adoc[Tracing]
24+
* xref:concept-docs:transactions.adoc[Key Concepts]
25+
** xref:concept-docs:transactions-cleanup.adoc[Cleanup]
26+
** xref:concept-docs:transactions-error-handling.adoc[Error Handling]
27+
1928
.Advanced Data Operations
2029
* xref:howtos:concurrent-async-apis.adoc[Async & React APIs]
2130
* xref:howtos:concurrent-document-mutations.adoc[Concurrent Document Mutations]
22-
* xref:howtos:distributed-acid-transactions-from-the-sdk.adoc[Distributed ACID Transactions]
2331
* xref:howtos:encrypting-using-sdk.adoc[Encrypting Your Data]
2432
* xref:howtos:transcoders-nonjson.adoc[Transcoders & Non-JSON]
2533
* xref:howtos:working-with-collections.adoc[Working with Collections]

modules/concept-docs/pages/errors.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ include::{version-server}@sdk:shared:partial$errors.adoc[tag=observability]
3030

3131
== ACID Transactions
3232

33-
For a discussion of errors affecting multi-document ACID transactions, see xref:howtos:distributed-acid-transactions-from-the-sdk.adoc#error-handling[our documentation on transactions from the .NET SDK].
33+
For a discussion of errors affecting multi-document ACID transactions, see xref:concept-docs:transactions-error-handling.adoc#error-handling[our documentation on transactions from the .NET SDK].
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
= Cleanup
2+
:description: The SDK takes care of failed or lost transactions, using an asynchronous cleanup background task.
3+
:page-toclevels: 2
4+
:page-pagination: full
5+
6+
[abstract]
7+
{description}
8+
9+
include::project-docs:partial$attributes.adoc[]
10+
include::howtos:partial$acid-transactions-attributes.adoc[]
11+
12+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tags=cleanup;!integrated-sdk-cleanup-collections]
13+
14+
[#tuning-cleanup]
15+
=== Configuring Cleanup
16+
17+
The cleanup settings can be configured as so:
18+
19+
[options="header"]
20+
|===
21+
|Setting|Default|Description
22+
|`CleanupWindow`|60 seconds|This determines how long a cleanup 'run' is; that is, how frequently this client will check its subset of ATR documents. It is perfectly valid for the application to change this setting, which is at a conservative default. Decreasing this will cause expiration transactions to be found more swiftly (generally, within this cleanup window), with the tradeoff of increasing the number of reads per second used for the scanning process.
23+
|`CleanupLostAttempts`|true|This is the thread that takes part in the distributed cleanup process described above, that cleans up expired transactions created by any client. It is strongly recommended that it is left enabled.
24+
|`CleanupClientAttempts`|true|This thread is for cleaning up transactions created just by this client. The client will preferentially aim to send any transactions it creates to this thread, leaving transactions for the distributed cleanup process only when it is forced to (for example, on an application crash). It is strongly recommended that it is left enabled.
25+
|===
26+
27+
// TODO: Add this for .NET when available
28+
////
29+
=== Monitoring Cleanup
30+
31+
If the application wishes to monitor cleanup it may subscribe to these events:
32+
33+
[source,csharp]
34+
----
35+
include::example$TransactionsExample.cs[tag=cleanup-events,indent=0]
36+
----
37+
38+
`TransactionCleanupEndRunEvent` is raised whenever a current 'run' is finished, and contains statistics from the run.
39+
(A run is typically around every 60 seconds, with default configuration.)
40+
41+
A `TransactionCleanupAttempt` event is raised when an expired transaction was found by this process, and a cleanup attempt was made.
42+
It contains whether that attempt was successful, along with any logs relevant to the attempt.
43+
44+
In addition, if cleanup fails to cleanup a transaction that is more than two hours past expiry, it will raise the `TransactionCleanupAttempt` event at WARN level (rather than the default DEBUG).
45+
With most default configurations of the event-bus (see <<Logging>> below), this will cause that event to be logged somewhere visible to the application.
46+
If there is not a good reason for the cleanup to be failed (such as a downed node that has not yet been failed-over), then the user is encouraged to report the issue.
47+
////
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
= Error Handling
2+
:description: Handling transaction errors with Couchbase.
3+
:page-toclevels: 2
4+
:page-pagination: prev
5+
6+
[abstract]
7+
{description}
8+
9+
include::project-docs:partial$attributes.adoc[]
10+
include::howtos:partial$acid-transactions-attributes.adoc[]
11+
12+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tag=error-intro]
13+
14+
== Transaction Errors
15+
16+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tag=error]
17+
18+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tag=txnfailed]
19+
20+
[source,csharp]
21+
----
22+
include::howtos:example$TransactionsExample.cs[tag=config-expiration,indent=0]
23+
----
24+
25+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tag=txnfailed1]
26+
27+
Similar to `TransactionResult`, `SingleQueryTransactionResult` also has an `UnstagingComplete` property.
28+
29+
=== Full Error Handling Example
30+
31+
Pulling all of the above together, this is the suggested best practice for error handling:
32+
33+
[source,csharp]
34+
----
35+
include::howtos:example$TransactionsExample.cs[tag=full-error-handling,indent=0]
36+
----
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
= Distributed ACID Transactions
2+
:description: A high-level overview of Distributed ACID Transactions with Couchbase.
3+
:page-toclevels: 2
4+
:page-pagination: next
5+
6+
include::project-docs:partial$attributes.adoc[]
7+
include::howtos:partial$acid-transactions-attributes.adoc[]
8+
9+
[abstract]
10+
{description}
11+
12+
For a practical guide, see xref:howtos:distributed-acid-transactions-from-the-sdk.adoc[Distributed ACID Transactions from the Java SDK].
13+
14+
== Overview
15+
16+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tags=intro]
17+
18+
== Transaction Mechanics
19+
20+
[source,csharp]
21+
----
22+
include::howtos:example$TransactionsExample.cs[tag=create-simple,indent=0]
23+
----
24+
25+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tags=mechanics;!integrated-sdk-cleanup-process]
26+
27+
TIP: Committing is automatic: if there is no explicit call to `ctx.CommitAsync()` at the end of the transaction logic callback, and no exception is thrown, it will be committed.
28+
29+
=== Rollback
30+
31+
When an exception is thrown, either by the application from the {lambda}, or by the transactions logic itself (e.g. on a failed operation), then that attempt is rolled back.
32+
33+
The application's {lambda} may or may not be retried, depending on the error that occurred.
34+
The general rule for retrying is whether the transaction is likely to succeed on a retry.
35+
For example, if this transaction is trying to write a document that is currently involved in another transaction (a write-write conflict), this will lead to a retry as that is likely a transient state.
36+
But if the transaction is trying to get a document that does not exist, it will not retry.
37+
38+
If the transaction is not retried then it will throw a `{transaction-failed}`.
39+
40+
[source,csharp]
41+
----
42+
include::howtos:example$TransactionsExample.cs[tag=rollback-cause,indent=0]
43+
----
44+
45+
The transaction can also be explicitly rolled back:
46+
47+
[source,csharp]
48+
----
49+
include::howtos:example$TransactionsExample.cs[tag=rollback,indent=0]
50+
----
51+
52+
In this case, if `ctx.RollbackAsync()` is reached, then the transaction will be regarded as successfully rolled back and no `{transaction-failed}` will be thrown.
53+
54+
After a transaction is rolled back, it cannot be committed, no further operations are allowed on it, and the SDK will not try to automatically commit it at the end of the code block.
55+
56+
== Transaction Operations
57+
58+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tags=query;!integrated-sdk-begin-transaction]
59+
60+
== Custom Metadata Collections
61+
62+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tag=custom-metadata-1]
63+
64+
[source,csharp]
65+
----
66+
include::howtos:example$TransactionsExample.cs[tag=custom-metadata,indent=0]
67+
----
68+
69+
include::{version-server}@sdk:shared:partial$acid-transactions.adoc[tag=custom-metadata-2]
70+

modules/howtos/examples/Couchbase.Examples/Couchbase.Examples.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="CouchbaseNetClient" Version="3.1.3" />
10+
<PackageReference Include="CouchbaseNetClient" Version="3.3.4" />
1111
<PackageReference Include="Couchbase.Extensions.Encryption" Version="2.0.0-dp.1" />
12-
<PackageReference Include="MessagePack" Version="2.2.85" />
12+
<PackageReference Include="MessagePack" Version="2.4.35" />
1313
</ItemGroup>
1414

1515
</Project>

modules/howtos/examples/TransactionsExample.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static async Task Main(string[] args)
3636
var options = new ClusterOptions().WithCredentials("Administrator", "password");
3737
var cluster = await Cluster.ConnectAsync("couchbase://localhost", options).ConfigureAwait(false);
3838
var bucket = await cluster.BucketAsync("default").ConfigureAwait(false);
39-
var collection = bucket.DefaultCollection();
39+
var collection = await bucket.ScopeAsync("inventory").CollectionAsync("airport").ConfigureAwait(false);
4040

4141
// Create the single Transactions object
4242
var transactions = Transactions.Create(cluster, TransactionConfigBuilder.Create());
@@ -78,6 +78,24 @@ void ConfigCleanup(byte[] encoded)
7878
// #end::config-cleanup[]
7979
}
8080

81+
async Task CreateSimpleAsync()
82+
{
83+
var doc1Content = new { };
84+
var doc2Content = new { };
85+
86+
// tag::create-simple[]
87+
await _transactions.RunAsync(async (ctx) =>
88+
{
89+
await ctx.InsertAsync(_collection, "doc-1", doc1Content).ConfigureAwait(false);
90+
91+
var doc2 = await ctx.GetAsync(_collection, "doc-2").ConfigureAwait(false);
92+
await ctx.ReplaceAsync(doc2, doc2Content).ConfigureAwait(false);
93+
94+
await ctx.CommitAsync().ConfigureAwait(false);
95+
}).ConfigureAwait(false);
96+
// end::create-simple[]
97+
}
98+
8199
async Task CreateAsync()
82100
{
83101
// #tag::create[]
@@ -335,9 +353,7 @@ public class BalanceInsufficientException : Exception { }
335353
private async Task RollbackCause()
336354
{
337355
const int costOfItem = 10;
338-
339-
// #tag::rollback-cause[]
340-
356+
// tag::rollback-cause[]
341357
try
342358
{
343359
await _transactions.RunAsync(async ctx =>
@@ -351,8 +367,7 @@ await _transactions.RunAsync(async ctx =>
351367
catch (TransactionCommitAmbiguousException e)
352368
{
353369
// This exception can only be thrown at the commit point, after the
354-
// BalanceInsufficient logic has been passed, so there is no need to
355-
// check getCause here.
370+
// BalanceInsufficient logic has been passed.
356371
Console.Error.WriteLine("Transaction possibly committed");
357372
Console.Error.WriteLine(e);
358373
}
@@ -361,7 +376,7 @@ await _transactions.RunAsync(async ctx =>
361376
Console.Error.WriteLine("Transaction did not reach commit point");
362377
}
363378

364-
// #end::rollback-cause[]
379+
// end::rollback-cause[]
365380
}
366381

367382
async Task CompleteErrorHandling()
@@ -559,7 +574,10 @@ await ctx.QueryAsync<object>(
559574
{
560575
// tag::queryInsert[]
561576
await transactions.RunAsync(async ctx => {
562-
await ctx.QueryAsync<object>("INSERT INTO `default` VALUES ('doc', {'hello':'world'})", TransactionQueryConfigBuilder.Create()); // <1>
577+
await ctx.QueryAsync<object>(
578+
"INSERT INTO `default` VALUES ('doc', {'hello':'world'})",
579+
TransactionQueryConfigBuilder.Create()
580+
); // <1>
563581

564582
// Performing a 'Read Your Own Write'
565583
var st = "SELECT `default`.* FROM `default` WHERE META().id = 'doc'"; // <2>
@@ -649,7 +667,8 @@ await ctx.QueryAsync<object>("INSERT INTO `default` VALUES ('doc', {'hello':'wor
649667

650668
{
651669
// tag::custom-metadata[]
652-
ICouchbaseCollection metadataCollection = null; // this is a Collection opened by your code earlier
670+
// Replace with your own metadata collection.
671+
ICouchbaseCollection metadataCollection = null;
653672
Transactions transactionsWithCustomMetadataCollection = Transactions.Create(cluster,
654673
TransactionConfigBuilder.Create().MetadataCollection(metadataCollection));
655674
// end::custom-metadata[]

0 commit comments

Comments
 (0)