예제 #1
0
 private TransactionConfigBuilder DefaultConfigBuilder(ITestOutputHelper outputHelper)
 {
     return(TransactionConfigBuilder.Create()
            .CleanupClientAttempts(false)
            .CleanupLostAttempts(false)
            .LoggerFactory(new ClusterFixture.TestOutputLoggerFactory(outputHelper)));
 }
예제 #2
0
        public async Task Rollback_Insert_Should_Result_In_No_Document()
        {
            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc  = new { type = nameof(Rollback_Insert_Should_Result_In_No_Document), foo = "bar", revision = 100 };
            var docId      = Guid.NewGuid().ToString();
            var durability = DurabilityLevel.None;

            var txn           = Transactions.Create(_fixture.Cluster);
            var configBuilder = TransactionConfigBuilder.Create();

            configBuilder.DurabilityLevel(durability);

            var runTask = txn.RunAsync(async ctx =>
            {
                var insertResult = await ctx.InsertAsync(defaultCollection, docId, sampleDoc);
                throw ErrorClass.FailHard.Throwable();
            });

            var transactionFailedException = await Assert.ThrowsAsync <TransactionFailedException>(() => runTask);

            var result = transactionFailedException.Result;

            Assert.False(result.UnstagingComplete);

            var postTxnGetTask = defaultCollection.GetAsync(docId);

            _ = await Assert.ThrowsAsync <DocumentNotFoundException>(() => postTxnGetTask);
        }
        public async Task <IActionResult> Transfer([FromBody] ProfileTransferCredit request)
        {
            try
            {
                var bucket = await _bucketProvider.GetBucketAsync(_couchbaseConfig.BucketName);

                var collection = await bucket.CollectionAsync(_couchbaseConfig.CollectionName);

                // only use DurabilityLevel.None for single node (e.g. a local single-node install, not Capella)
                var tx = Transactions.Create(bucket.Cluster, TransactionConfigBuilder.Create().DurabilityLevel(DurabilityLevel.None));
                await tx.RunAsync(async (ctx) =>
                {
                    var fromProfileDoc = await ctx.GetAsync(collection, request.Pfrom.ToString());
                    var fromProfile    = fromProfileDoc.ContentAs <Profile>();

                    var toProfileDoc = await ctx.GetAsync(collection, request.Pto.ToString());
                    var toProfile    = toProfileDoc.ContentAs <Profile>();

                    fromProfile.TransferTo(toProfile, request.Amount);

                    await ctx.ReplaceAsync(fromProfileDoc, fromProfile);
                    await ctx.ReplaceAsync(toProfileDoc, toProfile);

                    await ctx.CommitAsync();
                });

                return(Ok());
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return(StatusCode(StatusCodes.Status500InternalServerError, $"Error: {ex.Message} {ex.StackTrace} {Request.GetDisplayUrl()}"));
            }
        }
예제 #4
0
        public async Task Basic_Insert_Should_Succeed_CustomMetadataCollection()
        {
            // Use a feature from an unreleased CouchbaseNetClient to guarantee we're using latest from master instead.
            var ex = new Core.Exceptions.CasMismatchException();

            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var customCollection = await _fixture.OpenCustomCollection(_outputHelper);

            var sampleDoc = new { type = nameof(Basic_Insert_Should_Succeed), foo = "bar", revision = 100 };
            var docId     = nameof(Basic_Insert_Should_Succeed) + Guid.NewGuid().ToString();

            try
            {
                var durability = await TestUtil.InsertAndVerifyDurability(defaultCollection, docId + "_testDurability", sampleDoc);

                var configBuilder = TransactionConfigBuilder.Create();
                configBuilder.DurabilityLevel(durability);
                configBuilder.MetadataCollection(customCollection);
                var txn = Transactions.Create(_fixture.Cluster, configBuilder.Build());

                var result = await txn.RunAsync(async ctx =>
                {
                    var insertResult = await ctx.InsertAsync(defaultCollection, docId, sampleDoc).ConfigureAwait(false);
                    Assert.Equal(ClusterFixture.CustomCollectionName, insertResult?.TransactionXattrs?.AtrRef?.CollectionName);

                    var getResult = await ctx.GetAsync(defaultCollection, docId);
                    Assert.NotNull(getResult);
                    var asJobj = getResult !.ContentAs <JObject>();
                    Assert.Equal("bar", asJobj["foo"].Value <string>());
                    Assert.Equal(ClusterFixture.CustomCollectionName, getResult?.TransactionXattrs?.AtrRef?.CollectionName);
                });

                var postTxnGetResult = await defaultCollection.GetAsync(docId);

                var postTxnDoc = postTxnGetResult.ContentAs <dynamic>();
                Assert.Equal("100", postTxnDoc.revision.ToString());

                var postTxnLookupInResult =
                    await defaultCollection.LookupInAsync(docId, spec => spec.Get("txn", isXattr: true));

                Assert.False(postTxnLookupInResult.Exists(0));
            }
            catch
            {
                throw;
            }
            finally
            {
                try
                {
                    await defaultCollection.RemoveAsync(docId);
                }
                catch (Exception e)
                {
                    _outputHelper.WriteLine($"Error during cleanup: {e.ToString()}");
                }
            }
        }
 void ConfigExpired()
 {
     // #tag::config-expiration[]
     Transactions transactions = Transactions.Create(_cluster, TransactionConfigBuilder.Create()
                                                     .ExpirationTime(TimeSpan.FromSeconds(120))
                                                     .Build());
     // #end::config-expiration[]
 }
 void Config()
 {
     // #tag::config[]
     var transactions = Transactions.Create(_cluster,
                                            TransactionConfigBuilder.Create()
                                            .DurabilityLevel(DurabilityLevel.PersistToMajority)
                                            .Build());
     // #end::config[]
 }
 void ConfigCleanup(byte[] encoded)
 {
     // #tag::config-cleanup[]
     Transactions transactions = Transactions.Create(_cluster, TransactionConfigBuilder.Create()
                                                     .CleanupClientAttempts(false)
                                                     .CleanupLostAttempts(false)
                                                     .CleanupWindow(TimeSpan.FromSeconds(120))
                                                     .Build());
     // #end::config-cleanup[]
 }
예제 #8
0
        public async Task DocumentLookup_Should_Include_Metadata()
        {
            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc = new { type = nameof(DocumentLookup_Should_Include_Metadata), foo = "bar", revision = 100 };
            var docId     = Guid.NewGuid().ToString();

            var durability = await TestUtil.InsertAndVerifyDurability(defaultCollection, docId, sampleDoc);

            var configBuilder = TransactionConfigBuilder.Create();

            configBuilder.DurabilityLevel(durability);
            if (Debugger.IsAttached)
            {
                configBuilder.ExpirationTime(TimeSpan.FromMinutes(10));
            }

            var txn = Transactions.Create(_fixture.Cluster, configBuilder);


            txn.TestHooks = new DelegateTestHooks()
            {
                BeforeDocCommittedImpl = async(ctx, id) =>
                {
                    var documentLookupResult =
                        await DocumentRepository.LookupDocumentAsync(defaultCollection, id, null, true);

                    return(0);
                },

                AfterStagedReplaceCompleteImpl = async(ctx, id) =>
                {
                    var documentLookupResult =
                        await DocumentRepository.LookupDocumentAsync(defaultCollection, id, null, true);

                    return(0);
                }
            };

            var result = await txn.RunAsync(async ctx =>
            {
                var getResult = await ctx.GetAsync(defaultCollection, docId);
                var docGet    = getResult !.ContentAs <dynamic>();

                docGet.revision   = docGet.revision + 1;
                var replaceResult = await ctx.ReplaceAsync(getResult, docGet);

                var documentLookupResult =
                    await DocumentRepository.LookupDocumentAsync(defaultCollection, docId, null, true);

                Assert.NotNull(documentLookupResult?.TransactionXattrs);
                Assert.NotNull(documentLookupResult?.StagedContent?.ContentAs <object>());
                _outputHelper.WriteLine(JObject.FromObject(documentLookupResult !.TransactionXattrs).ToString());
            });
        }
예제 #9
0
        void Config()
        {
            // #tag::config[]
            var transactions = Transactions.Create(_cluster,
                                                   TransactionConfigBuilder.Create()
                                                   .DurabilityLevel(DurabilityLevel.PersistToMajority)

                                                   /* // #tag::config_warn[]
                                                    * .LogOnFailure(true, Event.Severity.WARN)
                                                    * // #end::config_warn[]*/
                                                   .Build());
            // #end::config[]
        }
예제 #10
0
        public async Task Exception_Rollback_Should_Result_In_No_Changes()
        {
            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc = new { type = nameof(Exception_Rollback_Should_Result_In_No_Changes), foo = "bar", revision = 100 };
            var docId     = Guid.NewGuid().ToString();

            try
            {
                var durability = await TestUtil.InsertAndVerifyDurability(defaultCollection, docId, sampleDoc);

                var txn           = Transactions.Create(_fixture.Cluster);
                var configBuilder = TransactionConfigBuilder.Create();
                configBuilder.DurabilityLevel(durability);

                int attemptCount = 0;
                var runTask      = txn.RunAsync(async ctx =>
                {
                    attemptCount++;
                    var getResult = await ctx.GetAsync(defaultCollection, docId);
                    var docGet    = getResult.ContentAs <dynamic>();

                    docGet.revision   = docGet.revision + 1;
                    var replaceResult = await ctx.ReplaceAsync(getResult, docGet);
                    throw new InvalidOperationException("Forcing rollback.");
                });

                await Assert.ThrowsAsync <TransactionFailedException>(() => runTask);

                Assert.Equal(1, attemptCount);

                var postTxnGetResult = await defaultCollection.GetAsync(docId);

                var postTxnDoc = postTxnGetResult.ContentAs <dynamic>();
                Assert.Equal("100", postTxnDoc.revision.ToString());
            }
            finally
            {
                try
                {
                    await defaultCollection.RemoveAsync(docId);
                }
                catch (Exception e)
                {
                    _outputHelper.WriteLine($"Error during cleanup: {e.ToString()}");
                    throw;
                }
            }
        }
예제 #11
0
        public async Task DataAccess_Is_Abstracted()
        {
            // After the data access was refactored into repository classes, the ICouchbaseCollection instances passed in shouldn't actually be accessed.
            // We verify this by using Mock with strict behavior and NotImplemented members.
            // The test should run to the end without hitting any of the ICouchbaseCollection other than the names and fetching the default collection on the bucket.
            using var cluster = CreateTestCluster(Enumerable.Empty <TransactionGetResult>());
            var    mockCollection     = new MockCollectionWithNames(nameof(DataAccess_Is_Abstracted) + "col", nameof(DataAccess_Is_Abstracted) + "scp", nameof(DataAccess_Is_Abstracted) + "bkt");
            var    atr                = new MockAtrRepository();
            var    doc                = new MockDocumentRepository();
            string docId              = nameof(DataAccess_Is_Abstracted) + ".id";
            var    mockLookupInResult = new Mock <ILookupInResult>(MockBehavior.Strict);

            mockLookupInResult.SetupGet(l => l.IsDeleted).Returns(false);
            mockLookupInResult.SetupGet(l => l.Cas).Returns(5);
            doc.Add(mockCollection, docId, new DataModel.DocumentLookupResult(docId, new JObjectContentWrapper(new { foo = "original" }), null, mockLookupInResult.Object, new Components.DocumentMetadata(), mockCollection));
            var configBuilder = TransactionConfigBuilder.Create().DurabilityLevel(DurabilityLevel.Majority);

            try
            {
                await using var transactions    = Transactions.Create(cluster);
                transactions.DocumentRepository = doc;
                transactions.AtrRepository      = atr;
                var tr = await transactions.RunAsync(async ctx =>
                {
                    var fetched  = await ctx.GetAsync(mockCollection, docId);
                    var replaced = await ctx.ReplaceAsync(fetched, new { foo = "bar" });
                    await ctx.RemoveAsync(replaced);
                    var inserted = await ctx.InsertAsync(mockCollection, docId + "inserted", new { foo = "inserted in transaction" });
                });

                try
                {
                    var aborted = await transactions.RunAsync(async ctx =>
                    {
                        var inserted = await ctx.InsertAsync(mockCollection, docId + "inserted_to_rollback", new { foo = "to be thrown" });
                        throw new InvalidOperationException("force fail");
                    });
                }
                catch (TransactionFailedException)
                {
                }
            }
            catch (Exception ex)
            {
                _outputHelper.WriteLine(ex.ToString());
                throw;
            }
        }
예제 #12
0
        public static Transactions CreateTransaction(ICluster cluster, DurabilityLevel durability, ITestOutputHelper outputHelper)
        {
            var configBuilder = TransactionConfigBuilder.Create()
                                .DurabilityLevel(durability)
                                .LoggerFactory(new ClusterFixture.TestOutputLoggerFactory(outputHelper));

            if (Debugger.IsAttached)
            {
                // don't expire when watching the debugger.
                configBuilder.ExpirationTime(TimeSpan.FromMinutes(1000));
            }

            var txn = Transactions.Create(cluster, configBuilder.Build());

            return(txn);
        }
예제 #13
0
        static async Task Main(string[] args)
        {
            var options = new ClusterOptions().WithCredentials("Administrator", "password");
            var cluster = await Cluster.ConnectAsync("couchbase://localhost", options).ConfigureAwait(false);

            var bucket = await cluster.BucketAsync("default").ConfigureAwait(false);

            var collection = bucket.DefaultCollection();

            var transactions = Transactions.Create(cluster, TransactionConfigBuilder.Create());

            using var program = new Program(cluster, bucket, collection, transactions);


            Console.WriteLine("Hello World!");
        }
예제 #14
0
        public async Task Basic_Replace_Should_Succeed()
        {
            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc = new { type = nameof(Basic_Replace_Should_Succeed), foo = "bar", revision = 100 };
            var docId     = Guid.NewGuid().ToString();

            try
            {
                var durability = await TestUtil.InsertAndVerifyDurability(defaultCollection, docId, sampleDoc);

                var txn           = Transactions.Create(_fixture.Cluster);
                var configBuilder = TransactionConfigBuilder.Create();
                configBuilder.DurabilityLevel(durability);

                var result = await txn.RunAsync(async ctx =>
                {
                    var getResult = await ctx.GetAsync(defaultCollection, docId);
                    var docGet    = getResult.ContentAs <dynamic>();

                    docGet.revision   = docGet.revision + 1;
                    var replaceResult = await ctx.ReplaceAsync(getResult, docGet);
                });

                Assert.True(result.UnstagingComplete);

                var postTxnGetResult = await defaultCollection.GetAsync(docId);

                var postTxnDoc = postTxnGetResult.ContentAs <dynamic>();
                Assert.Equal("101", postTxnDoc.revision.ToString());

                await txn.DisposeAsync();
            }
            finally
            {
                try
                {
                    await defaultCollection.RemoveAsync(docId);
                }
                catch (Exception e)
                {
                    _outputHelper.WriteLine($"Error during cleanup: {e.ToString()}");
                    throw;
                }
            }
        }
예제 #15
0
        public async Task Basic_Remove_Should_Succeed()
        {
            bool removed           = false;
            var  defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc = new { type = nameof(Basic_Remove_Should_Succeed), foo = "bar", revision = 100 };
            var docId     = Guid.NewGuid().ToString();

            try
            {
                var durability = await TestUtil.InsertAndVerifyDurability(defaultCollection, docId, sampleDoc);

                var txn           = Transactions.Create(_fixture.Cluster);
                var configBuilder = TransactionConfigBuilder.Create();
                configBuilder.DurabilityLevel(durability);

                var result = await txn.RunAsync(async ctx =>
                {
                    var getResult = await ctx.GetAsync(defaultCollection, docId);
                    var docGet    = getResult.ContentAs <dynamic>();

                    docGet.revision = docGet.revision + 1;
                    await ctx.RemoveAsync(getResult);
                });

                await Assert.ThrowsAsync <DocumentNotFoundException>(() => defaultCollection.GetAsync(docId));

                removed = true;
            }
            finally
            {
                try
                {
                    if (!removed)
                    {
                        await defaultCollection.RemoveAsync(docId);
                    }
                }
                catch (Exception e)
                {
                    _outputHelper.WriteLine($"Error during cleanup: {e.ToString()}");
                    throw;
                }
            }
        }
        public async Task Singles(string statement)
        {
            (var defaultCollection, var docId, var sampleDoc) = await TestUtil.PrepSampleDoc(_fixture, _outputHelper);

            _outputHelper.WriteLine(sampleDoc.ToString());
            var loggerFactory = new ClusterFixture.TestOutputLoggerFactory(_outputHelper);
            await defaultCollection.InsertAsync(docId, sampleDoc);

            var txnCfg = TransactionConfigBuilder.Create().LoggerFactory(loggerFactory);
            var txn    = TestUtil.CreateTransaction(_fixture.Cluster, KeyValue.DurabilityLevel.None, _outputHelper);
            var config = new SingleQueryTransactionConfigBuilder();

            config.QueryOptionsValue.Parameter("docId", docId);
            var results = await txn.QueryAsync <object>(statement, config);

            await foreach (var r in results.QueryResult.Rows)
            {
                _outputHelper.WriteLine($"result = {r}");
            }
        }
        async Task CompleteLogging()
        {
            // #tag::full-logging[]
            //Logging dependencies
            var services = new ServiceCollection();

            services.AddLogging(builder =>
            {
                builder.AddFile(AppContext.BaseDirectory);
                builder.AddConsole();
            });
            await using var provider = services.BuildServiceProvider();
            var loggerFactory = provider.GetService <ILoggerFactory>();
            var logger        = loggerFactory.CreateLogger <Program>();

            //create the transactions object and add the ILoggerFactory
            var transactions = Transactions.Create(_cluster,
                                                   TransactionConfigBuilder.Create().LoggerFactory(loggerFactory));

            try
            {
                var result = await transactions.RunAsync(async ctx => {
                    // ... transactional code here ...
                });
            }
            catch (TransactionCommitAmbiguousException err)
            {
                // The transaction may or may not have reached commit point
                logger.LogInformation("Transaction returned TransactionCommitAmbiguous and" +
                                      " may have succeeded, logs:");
                Console.Error.WriteLine(err);
            }
            catch (TransactionFailedException err)
            {
                // The transaction definitely did not reach commit point
                logger.LogInformation("Transaction failed with TransactionFailed, logs:");
                Console.Error.WriteLine(err);
            }
            // #end::full-logging[]
        }
예제 #18
0
        public async Task Retry_On_Certain_Failures()
        {
            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc = new { type = nameof(Retry_On_Certain_Failures), foo = "bar", revision = 100 };
            var docId     = Guid.NewGuid().ToString();

            try
            {
                var durability = DurabilityLevel.Majority;

                try
                {
                    _ = await defaultCollection.InsertAsync(docId, sampleDoc, opts => opts.Durability(durability));
                }
                catch (DurabilityImpossibleException)
                {
                    // when running on single-node cluster, such as localhost.
                    durability = DurabilityLevel.None;
                    _          = await defaultCollection.InsertAsync(docId, sampleDoc, opts => opts.Durability(durability));
                }

                var txn           = Transactions.Create(_fixture.Cluster);
                var configBuilder = TransactionConfigBuilder.Create();
                configBuilder.DurabilityLevel(durability);

                int attemptCount = 0;
                var result       = await txn.RunAsync(async ctx =>
                {
                    attemptCount++;
                    var getResult = await ctx.GetAsync(defaultCollection, docId);
                    var docGet    = getResult.ContentAs <dynamic>();

                    docGet.revision   = docGet.revision + 1;
                    var replaceResult = await ctx.ReplaceAsync(getResult, docGet);
                    if (attemptCount < 3)
                    {
                        throw new TestRetryException("force retry", new InvalidOperationException());
                    }
                });

                Assert.True(result.UnstagingComplete);

                var postTxnGetResult = await defaultCollection.GetAsync(docId);

                var postTxnDoc = postTxnGetResult.ContentAs <dynamic>();
                Assert.Equal("101", postTxnDoc.revision.ToString());
            }
            catch (Exception ex)
            {
                _outputHelper.WriteLine($"Error during main try: {ex.ToString()}");
                throw;
            }
            finally
            {
                try
                {
                    await defaultCollection.RemoveAsync(docId);
                }
                catch (Exception e)
                {
                    _outputHelper.WriteLine($"Error during cleanup: {e.ToString()}");
                    throw;
                }
            }
        }
        static async Task Main(string[] args)
        {
            try
            {
                var clusterOptions = new ClusterOptions()
                {
                    RedactionLevel = Couchbase.Core.Logging.RedactionLevel.Partial,
                    UserName       = "******",
                    Password       = "******"
                };

                var connectionString = "couchbase://localhost";
                await using var cluster = await Cluster.ConnectAsync(connectionString, clusterOptions);

                await using var bucket = await cluster.BucketAsync("default");

                var collection = await bucket.DefaultCollectionAsync();

                var sampleDoc    = new ExampleTransactionDocument();
                var insertResult = await collection.InsertAsync(sampleDoc.Id,
                                                                sampleDoc)
                                   .ConfigureAwait(false);

                var getResultRoundTrip = await collection.GetAsync(sampleDoc.Id).ConfigureAwait(false);

                var roundTripSampleDoc = getResultRoundTrip.ContentAs <ExampleTransactionDocument>();

                Serilog.Log.Logger = new Serilog.LoggerConfiguration()
                                     .Enrich.FromLogContext()
                                     .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss.fff} {Level:u3}] |{Properties:j}| [{SourceContext:l}] {Message:lj}{NewLine}{Exception}").CreateLogger();
                var configBuilder = TransactionConfigBuilder.Create()
                                    .LoggerFactory(new SerilogLoggerFactory())
                                    .DurabilityLevel(DurabilityLevel.None);

                if (Debugger.IsAttached)
                {
                    configBuilder.ExpirationTime(TimeSpan.FromMinutes(10));
                }

                var txn = Transactions.Create(cluster, configBuilder.Build());
                for (int i = 0; i < 1; i++)
                {
                    var sw        = Stopwatch.StartNew();
                    var txnResult = await txn.RunAsync(async ctx =>
                    {
                        var getResult = await ctx.GetAsync(collection, sampleDoc.Id).ConfigureAwait(false);
                        var docGet    = getResult.ContentAs <JObject>();

                        var insertResult = await ctx.InsertAsync(collection, Guid.NewGuid().ToString(), docGet);

                        docGet["revision"] = docGet["revision"].Value <int>() + 1;
                        var replaceResult1 = await ctx.ReplaceAsync(insertResult, docGet).ConfigureAwait(false);
                        var replaceResult2 = await ctx.ReplaceAsync(getResult, docGet).ConfigureAwait(false);

                        // Commit happens automatically at this point.  You don't need to call it explicitly.
                    }).ConfigureAwait(false);

                    sw.Stop();

                    Console.Out.WriteLine(txnResult.ToString());
                    Console.Out.WriteLine($"Elapsed = {sw.Elapsed.TotalMilliseconds}ms");
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
                throw;
            }
        }
예제 #20
0
        private async Task <bool> CanonicalExample()
        {
            using var cluster = CreateTestCluster(Enumerable.Empty <TransactionGetResult>());

            var configBuilder = TransactionConfigBuilder.Create()
                                .DurabilityLevel(DurabilityLevel.Majority);

            if (Debugger.IsAttached)
            {
                configBuilder.ExpirationTime(TimeSpan.FromMinutes(10));
            }

            using var transactions = Transactions.Create(cluster, configBuilder.Build());

            bool reachedPostCommit = false;
            TransactionResult tr   = null;

            try
            {
                tr = await transactions.RunAsync(async ctx =>
                {
                    // Inserting a doc:
                    var docId        = "test-id";
                    var bucket       = await cluster.BucketAsync("test-bucket").ConfigureAwait(false);
                    var collection   = await bucket.DefaultCollectionAsync();
                    var insertResult = await ctx.InsertAsync(collection, docId, new JObject()).ConfigureAwait(false);

                    // Getting documents:
                    var docOpt = await ctx.GetOptionalAsync(collection, docId).ConfigureAwait(false);
                    var doc    = await ctx.GetAsync(collection, docId).ConfigureAwait(false);

                    // Replacing a document:
                    var anotherDoc          = await ctx.GetAsync(collection, "anotherDoc").ConfigureAwait(false);
                    var content             = anotherDoc.ContentAs <JObject>();
                    content["transactions"] = "are awesome";
                    await ctx.ReplaceAsync(anotherDoc, content);

                    // Removing a document:
                    var yetAnotherDoc = await ctx.GetAsync(collection, "yetAnotherDoc)").ConfigureAwait(false);
                    await ctx.RemoveAsync(yetAnotherDoc).ConfigureAwait(false);

                    await ctx.CommitAsync().ConfigureAwait(false);
                    reachedPostCommit = true;
                });
            }
            catch (TransactionCommitAmbiguousException e)
            {
                // TODO: log individual errors
                _outputHelper.WriteLine(e.ToString());
                throw;
            }
            catch (TransactionFailedException e)
            {
                // TODO: log errors from exception
                _outputHelper.WriteLine(e.ToString());
                throw;
            }

            Assert.NotNull(tr);
            return(reachedPostCommit);
        }
예제 #21
0
        static async Task Main(string[] args)
        {
            // SETUP: connect to Couchbase
            _cluster = await Cluster.ConnectAsync(
                "couchbase://localhost",
                "Administrator",
                "password");

            _bucket = await _cluster.BucketAsync("matt");

            _scope = await _bucket.ScopeAsync("myScope");

            _coll = await _scope.CollectionAsync("myCollection");

            // SETUP: create a 'conference' document and a 'conference activities' document
            await SetupInitialDocuments();

            // STEP 1: create transactions object
            var transactions = Transactions.Create(_cluster,
                                                   TransactionConfigBuilder.Create()
                                                   .DurabilityLevel(DurabilityLevel.MajorityAndPersistToActive) // since I have 1 node, replication must be 0, or this will throw exception
                                                   .Build());

            Console.WriteLine("Press ENTER to continue");
            Console.ReadLine();

            // STEP 2: transaction operations
            await transactions.RunAsync(async (ctx) =>
            {
                var now = DateTime.Now;

                // FIRST: get the two document I want to change
                var confDoc = await ctx.GetAsync(_coll, "dataLove2021");
                var actsDoc = await ctx.GetAsync(_coll, "dataLove2021::activities");
                var conf    = confDoc.ContentAs <Conference>();
                var acts    = actsDoc.ContentAs <ConferenceActivities>();

                // SECOND: add an event to the "activities" document
                acts.Events.Add(new ConferenceEvent
                {
                    Type       = "CFP",
                    DtActivity = now,
                    Desc       = "Submitted to the CFP"
                });
                // acts.Events.Add(new ConferenceEvent
                // {
                //     Type = "PRESENTATION",
                //     DtActivity = now,
                //     Desc = "Delivered ACID presentation"
                // });
                // acts.Events.Add(new ConferenceEvent
                // {
                //     Type = "SPATIAL",
                //     DtActivity = now,
                //     Desc = "Answered questions in Spatial Chat"
                // });

                // THIRD: change the "conference" document
                conf.Followups    = (conf.Followups ?? 0) + 1;
                conf.LastActivity = now;

                // FOURTH: write the changes
                await ctx.ReplaceAsync(confDoc, conf);

                // OPTIONAL STEP: fail right in the middle of the transaction making two writes
                // var fail = true;
                // if(fail) throw new Exception("Something went wrong!");

                await ctx.ReplaceAsync(actsDoc, acts);

                // FIFTH: commit (implied)
            });

            await _cluster.DisposeAsync();
        }
        public async Task Parallel_Increments_All_Succeed(int parallelCount)
        {
            var barrier           = new Barrier(parallelCount);
            var defaultCollection = await _fixture.OpenDefaultCollection(_outputHelper);

            var sampleDoc = new ParallelDoc {
                Type = nameof(Parallel_Increments_All_Succeed), Name = "ContentiousDoc", Participants = new List <int>(), Count = 0
            };
            var docId      = nameof(Parallel_Increments_All_Succeed) + Guid.NewGuid().ToString();
            var durability = await TestUtil.InsertAndVerifyDurability(defaultCollection, docId, sampleDoc);

            var sw    = Stopwatch.StartNew();
            var tasks = Enumerable.Range(0, parallelCount).Select(i => Task.Run(
                                                                      async() =>
            {
                try
                {
                    _outputHelper.WriteLine($"{sw.Elapsed}:{i}: BEGIN_INIT");
                    var configBuilder = TransactionConfigBuilder.Create();
                    configBuilder.DurabilityLevel(durability);
                    configBuilder.LoggerFactory(new TestOutputLoggerFactory(_outputHelper));
                    if (parallelCount > 50)
                    {
                        configBuilder.ExpirationTime(TimeSpan.FromMinutes(5));
                    }

                    await using var txn = Transactions.Create(_fixture.Cluster, configBuilder.Build());
                    barrier.SignalAndWait();
                    _outputHelper.WriteLine($"{sw.Elapsed}:{i}: BEFORE_RUN");
                    var swRunTime = Stopwatch.StartNew();
                    try
                    {
                        long retryCount = 0;
                        var tr          = await txn.RunAsync(async ctx =>
                        {
                            _outputHelper.WriteLine($"{sw.Elapsed}:{i}: BEGIN_RUN, retryCount={retryCount}");
                            Interlocked.Increment(ref retryCount);
                            var getResult = await ctx.GetAsync(defaultCollection, docId);
                            var doc       = getResult.ContentAs <ParallelDoc>();
                            doc.Count++;
                            doc.Participants.Add(i);
                            doc.LastParticipant = i;
                            _ = await ctx.ReplaceAsync(getResult, doc);
                            _outputHelper.WriteLine($"{sw.Elapsed}:{i}: END_RUN");
                        });
                    }
                    finally
                    {
                        _outputHelper.WriteLine($"{sw.Elapsed}:{i}: AFTER_RUN {swRunTime.Elapsed}");
                    }
                }
                catch (Exception ex)
                {
                    _outputHelper.WriteLine($"{sw.Elapsed}:{i}:Exception! {ex.ToString()}");
                    throw;
                }
            }));

            try
            {
                await Task.WhenAll(tasks);
            }
            finally
            {
                var getResult = await defaultCollection.GetAsync(docId);

                var finalDoc = getResult.ContentAs <ParallelDoc>();
                _outputHelper.WriteLine(JObject.FromObject(finalDoc).ToString());
                Assert.Equal(parallelCount, finalDoc.Count);
            }
        }
        async Task QueryExamples()
        {
            // this isn't meant to run, merely to compile correctly.
            ICluster cluster      = null;
            var      transactions = Transactions.Create(cluster);
            {
                // tag::queryExamplesSelect[]
                var st = "SELECT * FROM `travel-sample`.inventory.hotel WHERE country = $1";
                var transactionResult = await transactions.RunAsync(async ctx => {
                    IQueryResult <object> qr = await ctx.QueryAsync <object>(st,
                                                                             new TransactionQueryOptions().Parameter("United Kingdom"));

                    await foreach (var result in qr.Rows)
                    {
                        Console.Out.WriteLine($"result = {result}", result);
                    }
                });

                // end::queryExamplesSelect[]
            }

            {
                // tag::queryExamplesSelectScope[]
                IBucket travelSample = await cluster.BucketAsync("travel-sample");

                IScope inventory = travelSample.Scope("inventory");

                var transactionResult = await transactions.RunAsync(async ctx =>
                {
                    var st = "SELECT * FROM `travel-sample`.inventory.hotel WHERE country = $1";
                    IQueryResult <object> qr = await ctx.QueryAsync <object>(st,
                                                                             options: new TransactionQueryOptions().Parameter("United Kingdom"),
                                                                             scope: inventory);
                });

                // end::queryExamplesSelectScope[]
            }

            {
                IBucket travelSample = await cluster.BucketAsync("travel-sample");

                IScope inventory = travelSample.Scope("inventory");
                // tag::queryExamplesUpdate[]
                var hotelChain = "http://marriot%";
                var country    = "United States";

                await transactions.RunAsync(async ctx => {
                    var qr = await ctx.QueryAsync <object>(
                        statement: "UPDATE hotel SET price = $price WHERE url LIKE $url AND country = $country",
                        configure: options => options.Parameter("price", 99.99m)
                        .Parameter("url", hotelChain)
                        .Parameter("country", country),
                        scope: inventory);

                    Console.Out.WriteLine($"Records Updated = {qr?.MetaData.Metrics.MutationCount}");
                });

                // end::queryExamplesUpdate[]
            }

            {
                IBucket travelSample = await cluster.BucketAsync("travel-sample");

                IScope inventory  = travelSample.Scope("inventory");
                var    hotelChain = "http://marriot%";
                var    country    = "United States";
                //private class Review { };
                // tag::queryExamplesComplex[]
                await transactions.RunAsync(async ctx => {
                    // Find all hotels of the chain
                    IQueryResult <Review> qr = await ctx.QueryAsync <Review>(
                        statement: "SELECT reviews FROM hotel WHERE url LIKE $1 AND country = $2",
                        configure: options => options.Parameter(hotelChain).Parameter(country),
                        scope: inventory);

                    // This function (not provided here) will use a trained machine learning model to provide a
                    // suitable price based on recent customer reviews.
                    var updatedPrice = PriceFromRecentReviews(qr);

                    // Set the price of all hotels in the chain
                    await ctx.QueryAsync <object>(
                        statement: "UPDATE hotel SET price = $1 WHERE url LIKE $2 AND country = $3",
                        configure: options => options.Parameter(hotelChain, country, updatedPrice),
                        scope: inventory);
                });

                // end::queryExamplesComplex[]
            }

            {
                // tag::queryInsert[]
                await transactions.RunAsync(async ctx => {
                    await ctx.QueryAsync <object>("INSERT INTO `default` VALUES ('doc', {'hello':'world'})", TransactionQueryConfigBuilder.Create());  // <1>

                    // Performing a 'Read Your Own Write'
                    var st = "SELECT `default`.* FROM `default` WHERE META().id = 'doc'"; // <2>
                    IQueryResult <object> qr = await ctx.QueryAsync <object>(st, TransactionQueryConfigBuilder.Create());
                    Console.Out.WriteLine($"ResultCount = {qr?.MetaData.Metrics.ResultCount}");
                });

                // end::queryInsert[]
            }

            {
                // tag::querySingle[]
                var bulkLoadStatement = "<a bulk-loading N1QL statement>";

                try
                {
                    SingleQueryTransactionResult <object> result = await transactions.QueryAsync <object>(bulkLoadStatement);

                    IQueryResult <object> queryResult = result.QueryResult;
                }
                catch (TransactionCommitAmbiguousException e)
                {
                    Console.Error.WriteLine("Transaction possibly committed");
                    foreach (var log in e.Result.Logs)
                    {
                        Console.Error.WriteLine(log);
                    }
                }
                catch (TransactionFailedException e)
                {
                    Console.Error.WriteLine("Transaction did not reach commit point");
                    foreach (var log in e.Result.Logs)
                    {
                        Console.Error.WriteLine(log);
                    }
                }
                // end::querySingle[]
            }

            {
                string bulkLoadStatement = null /* your statement here */;

                // tag::querySingleScoped[]
                IBucket travelSample = await cluster.BucketAsync("travel-sample");

                IScope inventory = travelSample.Scope("inventory");

                await transactions.QueryAsync <object>(bulkLoadStatement, scope : inventory);

                // end::querySingleScoped[]
            }


            {
                string bulkLoadStatement = null; /* your statement here */

                // tag::querySingleConfigured[]
                // with the Builder pattern.
                await transactions.QueryAsync <object>(bulkLoadStatement, SingleQueryTransactionConfigBuilder.Create()
                                                       // Single query transactions will often want to increase the default timeout
                                                       .ExpirationTime(TimeSpan.FromSeconds(360)));

                // using the lambda style
                await transactions.QueryAsync <object>(bulkLoadStatement, config => config.ExpirationTime(TimeSpan.FromSeconds(360)));

                // end::querySingleConfigured[]
            }

            {
                ICouchbaseCollection collection = null;
                // tag::queryRyow[]
                await transactions.RunAsync(async ctx => {
                    _ = await ctx.InsertAsync(collection, "doc", new { Hello = "world" }); // <1>

                    // Performing a 'Read Your Own Write'
                    var st = "SELECT `default`.* FROM `default` WHERE META().id = 'doc'"; // <2>
                    var qr = await ctx.QueryAsync <object>(st);
                    Console.Out.WriteLine($"ResultCount = {qr?.MetaData.Metrics.ResultCount}");
                });

                // end::queryRyow[]
            }

            {
                // tag::queryOptions[]
                await transactions.RunAsync(async ctx => {
                    await ctx.QueryAsync <object>("INSERT INTO `default` VALUES ('doc', {'hello':'world'})",
                                                  new TransactionQueryOptions().FlexIndex(true));
                });

                // end::queryOptions[]
            }

            {
                // tag::custom-metadata[]
                ICouchbaseCollection metadataCollection = null; // this is a Collection opened by your code earlier
                Transactions         transactionsWithCustomMetadataCollection = Transactions.Create(cluster,
                                                                                                    TransactionConfigBuilder.Create().MetadataCollection(metadataCollection));
                // end::custom-metadata[]
            }
        }
예제 #24
0
        static async Task Main(string[] args)
        {
            Parser.Default.ParseArguments <Options>(args).WithParsed(RunOptions);

            var config = TransactionConfigBuilder.Create();

            config.DurabilityLevel(ParseDurability(_options.Durability));

            // Initialize the Couchbase cluster
            var cluster = await Cluster.ConnectAsync(_options.Cluster, _options.UserName, _options.Password).ConfigureAwait(false);

            var bucket = await cluster.BucketAsync(_options.Bucket).ConfigureAwait(false);

            var collection = bucket.DefaultCollection();

            // Initialize transactions.  Must only be one Transactions object per app as it creates background resources.
            var transactions = Transactions.Create(cluster, config);

            //Logging dependencies
            var services = new ServiceCollection();

            services.AddLogging(builder =>
            {
                builder.AddFile(AppContext.BaseDirectory);
                builder.AddConsole();
            });
            await using var provider = services.BuildServiceProvider();
            var loggerFactory = provider.GetService <ILoggerFactory>();
            var logger        = loggerFactory.CreateLogger <Program>();

            var gameServer = new GameServer(transactions, collection, logger);

            // Initialise some sample data - a player and a monster.  This is based on the Game Simulation sample bucket
            // provided with Couchbase, though that does not have to be installed.
            var playerId = "player_jane";
            var player   = new
            {
                experiance = 14248,
                hitpoints  = 23832,
                jsonType   = "player",
                level      = 141,
                loggedIn   = true,
                name       = "Jane",
                uuid       = Guid.NewGuid()
            };

            var monsterId = "a_grue";
            var monster   = new
            {
                experienceWhenKilled = 91,
                hitpoints            = 4000,
                itemProbability      = 0.19239324085462631,
                name = "grue",
                uuid = Guid.NewGuid()
            };

            await collection.UpsertAsync(playerId, player).ConfigureAwait(false);

            logger.LogInformation($"Upserted sample player document {playerId}");

            await collection.UpsertAsync(monsterId, monster).ConfigureAwait(false);

            logger.LogInformation($"Upserted sample monster document {monsterId}");

            // Now perform the transaction
            // The player is hitting the monster for a certain amount of damage
            await gameServer.PlayerHitsMonster(

                // This UUID identifies this action from the player's client
                Guid.NewGuid().ToString(),

                // This has a 50% chance of killing the monster, which has 4000 hitpoints
                new Random().Next(0, 8000),

                playerId,
                monsterId).ConfigureAwait(false);

            // Shutdown resources cleanly
            transactions.Dispose();
            await cluster.DisposeAsync().ConfigureAwait(false);

            Console.Read();
        }