Skip to content

Commit 9d5b059

Browse files
committed
Add durability and CAS examples
1 parent 22597b7 commit 9d5b059

File tree

4 files changed

+150
-5
lines changed

4 files changed

+150
-5
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ This example should show how to initialize and update a counter
7474
[C](c/counter.cc) |
7575
[Python](python/counter.py) |
7676
[Java](java/src/main/java/com/couchbase/devguide/Counter.java) |
77-
.NET |
77+
[.NET](dotnet/Counter.cs) |
7878
[Go](go/counter.go) |
7979
[node.js](nodejs/counter.js)
8080

@@ -84,7 +84,7 @@ This example should show how to initialize a document with an Expiry or "ttl" -
8484
[C](c/expiration.cc) |
8585
[Python](python/expiration.py) |
8686
[Java](java/src/main/java/com/couchbase/devguide/Expiration.java) |
87-
.NET |
87+
[.NET](dotnet/Expiration.cs) |
8888
[Go](go/expiration.go) |
8989
[node.js](nodejs/expiration.js)
9090

@@ -158,7 +158,7 @@ all mutations remain in tact
158158
[C](c/cas.cc) |
159159
[Python](python/cas.py) |
160160
[Java](java/src/main/java/com/couchbase/devguide/Cas.java) |
161-
.NET |
161+
[.NET](dotnet/Cas.cs) |
162162
Go |
163163
node.js
164164

@@ -171,6 +171,6 @@ Some SDKs provide APIs to determine how many nodes are in the cluster, while som
171171
[C](c/durability.cc) |
172172
[Python](python/durability.py) |
173173
[Java](java/src/main/java/com/couchbase/devguide/Durability.java) |
174-
.NET |
174+
[.NET](dotnet/Durability.cs) |
175175
Go |
176176
node.js

dotnet/Cas.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using Couchbase;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace DevGuide
9+
{
10+
public class Cas : ConnectionBase
11+
{
12+
public override async Task ExecuteAsync()
13+
{
14+
var key = "dotnetDevguideExampleCas-" + DateTime.Now.Ticks;
15+
var data = new Data
16+
{
17+
Number = 0
18+
};
19+
20+
// Set the inital number value to 0
21+
await _bucket.UpsertAsync(key, data);
22+
23+
// Try to increment the number 1000 times without using CAS (10 threads x 100 increments)
24+
// We would expect the result to be Number == 1000 at the end of the process.
25+
var tasksWithoutCas = Enumerable.Range(1, 10).Select(i => UpdateNumberWithoutCas(key, 100));
26+
await Task.WhenAll(tasksWithoutCas);
27+
28+
// Check if the actual result is 1000 as expected
29+
var result = await _bucket.GetAsync<Data>(key);
30+
Console.WriteLine("Expected number = 1000, actual number = " + result.Value.Number);
31+
32+
33+
// Set the inital number value back to 0
34+
await _bucket.UpsertAsync(key, data);
35+
36+
// Now try to increment the number 1000 times with CAS
37+
var tasksWithCas = Enumerable.Range(1, 10).Select(i => UpdateNumberWithCas(key, 100));
38+
await Task.WhenAll(tasksWithCas);
39+
40+
// Check if the actual result is 1000 as expected
41+
var result2 = await _bucket.GetAsync<Data>(key);
42+
Console.WriteLine("Expected number = 1000, actual number = " + result2.Value.Number);
43+
}
44+
45+
private Task UpdateNumberWithoutCas(string key, int count)
46+
{
47+
return Task.Run(async () =>
48+
{
49+
for (int i = 0; i < count; i++)
50+
{
51+
// Get the document
52+
var result = await _bucket.GetAsync<Data>(key);
53+
// Update the document
54+
result.Value.Number++;
55+
// Store the document back without CAS
56+
await _bucket.ReplaceAsync(key, result.Value);
57+
}
58+
});
59+
}
60+
61+
private Task UpdateNumberWithCas(string key, int count)
62+
{
63+
return Task.Run(async () =>
64+
{
65+
for (int i = 0; i < count; i++)
66+
{
67+
IOperationResult<Data> result = null;
68+
var retries = 100;
69+
do
70+
{
71+
// Get the document
72+
result = await _bucket.GetAsync<Data>(key);
73+
// Update the document
74+
result.Value.Number++;
75+
// Store the document back without CAS
76+
result = await _bucket.ReplaceAsync(key, result.Value, result.Cas);
77+
}
78+
while (result != null &&
79+
!result.Success &&
80+
// The .NET SDK returns a KeyExists status when the provided CAS doesn't match
81+
result.Status == Couchbase.IO.ResponseStatus.KeyExists &&
82+
retries-- > 0);
83+
}
84+
});
85+
}
86+
87+
static void Main(string[] args)
88+
{
89+
new Cas().ExecuteAsync().Wait();
90+
}
91+
}
92+
}

dotnet/DevGuide.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<WarningLevel>4</WarningLevel>
3434
</PropertyGroup>
3535
<PropertyGroup>
36-
<StartupObject>DevGuide.Expiration</StartupObject>
36+
<StartupObject>DevGuide.Cas</StartupObject>
3737
</PropertyGroup>
3838
<ItemGroup>
3939
<Reference Include="Common.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e, processorArchitecture=MSIL">
@@ -71,6 +71,8 @@
7171
<Compile Include="BulkInsert.cs" />
7272
<Compile Include="BulkGet.cs" />
7373
<Compile Include="Counter.cs" />
74+
<Compile Include="Durability.cs" />
75+
<Compile Include="Cas.cs" />
7476
<Compile Include="Update.cs" />
7577
<Compile Include="Retrieve.cs" />
7678
</ItemGroup>

dotnet/Durability.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Couchbase;
2+
using Couchbase.IO;
3+
using System;
4+
using System.Threading.Tasks;
5+
6+
namespace DevGuide
7+
{
8+
public class Durability : ConnectionBase
9+
{
10+
public override async Task ExecuteAsync()
11+
{
12+
var key = "dotnetDevguideExampleDurability-" + DateTime.Now.Ticks;
13+
var data = new Data
14+
{
15+
Number = 42,
16+
Text = "Life, the Universe, and Everything",
17+
Date = DateTime.UtcNow
18+
};
19+
20+
// The ReplicateTo parameter must be less than or equal to the number of replicas
21+
// you have configured. Assuming that 3 replicas are configured, the following call
22+
// waits for replication to 3 replicas and persistence to 4 nodes in total.
23+
var result = await _bucket.UpsertAsync(key, data, ReplicateTo.Three, PersistTo.Four);
24+
Console.WriteLine("Durability status: " + result.Durability);
25+
26+
if(!result.Success)
27+
{
28+
if (result.Status == ResponseStatus.NoReplicasFound)
29+
Console.WriteLine("Write failed - not enough replicas configured to satisfy durability requirements");
30+
else
31+
Console.WriteLine("An error has occured: {0}\r\n{1}", result.Message, result.Exception.ToString());
32+
}
33+
else
34+
{
35+
// It's possible for a write to succeed, but not satisfy durability.
36+
// For example, writing with PersistTo.Two and ReplicateTo.Zero on a 1-node cluster.
37+
if (result.Durability == Couchbase.IO.Operations.Durability.NotSatisfied)
38+
Console.WriteLine("Write succeeded, but some durability requirements were not satisfied.");
39+
}
40+
41+
// Wait for the write to be persisted to disk on one (normally the master) node.
42+
var result2 = await _bucket.UpsertAsync(key, data, ReplicateTo.Zero, PersistTo.One);
43+
Console.WriteLine("Durability status: " + result.Durability);
44+
}
45+
46+
static void Main(string[] args)
47+
{
48+
new Durability ().ExecuteAsync().Wait();
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)