Beispiel #1
0
        private static async Task UpdateSamePersonUsingOptimisticLockingWithCasValue(ICouchbaseCollection collection, string documentId)
        {
            var getResult = await collection.GetAsync(documentId);

            var person = getResult.ContentAs <Person>();


            var newPerson1     = person.WithSomeNumber(1);
            var replaceOptions = new ReplaceOptions().Cas(getResult.Cas);
            // csak akkor replace-el, ha a doksi CAS-ja egyezik a ReplaceOptions-ben megadottal
            // az UpsertAsync()-nek beadható UpsertOption()-nek nincs Cas() művelete, ezért használom Replace()-t
            var mutationResult1 = await collection.ReplaceAsync(documentId, newPerson1, replaceOptions);

            try
            {
                var newPerson2 = person.WithSomeNumber(2);
                // a doksi CAS-ja nem egyezik a korábban lekérttel, ezért dob
                var mutationResult2 = await collection.ReplaceAsync(documentId, newPerson2, replaceOptions);
            }
            catch (Couchbase.Core.Exceptions.KeyValue.DocumentExistsException ex)
            {
                // a hiba részeleteit tartalmazza; típusa: Couchbase.Core.Exceptions.KeyValue.KeyValueErrorContext: több minden van benne, mint IErrorContext-en
                var replaceContext = ex.Context;
            }
        }
        public static Task <IMutationResult> ReplaceAsync <T>(this ICouchbaseCollection collection, string id, T content,
                                                              Action <ReplaceOptions> configureOptions)
        {
            var options = new ReplaceOptions();

            configureOptions(options);

            return(collection.ReplaceAsync(id, content, options));
        }
        /// <inheritdoc/>
        public async Task Renew(TimeSpan expiration, CancellationToken cancellationToken = default)
        {
            if (expiration <= TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(expiration), "Value must be positive.");
            }

            var key      = LockDocument.GetKey(Name);
            var document = new LockDocument
            {
                Holder            = Holder,
                RequestedDateTime = DateTime.UtcNow
            };

            bool            lockAcquired = false;
            IMutationResult?result       = null;

            try
            {
                if (_cas == 0)
                {
                    // We're creating a new lock
                    _logger.LogDebug("Requesting lock '{name}' for holder '{holder}' for {expiration}", Name, Holder,
                                     expiration);
                    result = await _collection.InsertAsync(key, document,
                                                           new InsertOptions().Expiry(expiration).CancellationToken(cancellationToken))
                             .ConfigureAwait(false);
                }
                else
                {
                    _logger.LogDebug("Renewing lock '{name}' for holder '{holder}' for {expiration}", Name, Holder,
                                     expiration);
                    result = await _collection.ReplaceAsync(key, document,
                                                            new ReplaceOptions().Expiry(expiration).CancellationToken(cancellationToken).Cas(_cas))
                             .ConfigureAwait(false);
                }

                lockAcquired = true;
            }
            catch (CasMismatchException)
            {
                // This is a valid case, trap the exception
                _logger.LogDebug("CAS mismatch updating lock '{name}'", Name);
            }
            catch (DocumentExistsException)
            {
                // This is a valid case, trap the exception
                _logger.LogDebug("Lock document already exists for lock '{name}'", Name);
            }
            catch (DocumentNotFoundException)
            {
                // This is a valid, but rare, case where the document being renewed expired before
                // the renewal. In this case, we'll let the logic move on, which will recreate the document.
                _logger.LogDebug("Lock document missing for lock '{name}'", Name);
            }

            if (lockAcquired)
            {
                _logger.LogDebug("Lock '{name}' issued to holder '{holder}'", Name, Holder);

                _expirationInterval = expiration;
                _cas = result !.Cas;

                return;
            }

            if (!lockAcquired)
            {
                _logger.LogDebug("Lock '{name}' unavailable, getting lock info", Name);

                IGetResult getResult;
                try
                {
                    getResult = await _collection.GetAsync(key).ConfigureAwait(false);
                }
                catch (DocumentNotFoundException)
                {
                    try
                    {
                        // Couldn't find the lock, must have expired between Insert and Get, try one more time
                        result = await _collection.InsertAsync(key, document,
                                                               new InsertOptions().Expiry(expiration).CancellationToken(cancellationToken))
                                 .ConfigureAwait(false);
                    }
                    catch (DocumentExistsException)
                    {
                        throw new CouchbaseLockUnavailableException(Name);
                    }

                    _logger.LogDebug("Lock '{name}' issued to holder '{holder}'", Name, Holder);

                    _expirationInterval = expiration;
                    _cas = result.Cas;
                    return;
                }

                _logger.LogDebug("Unable to acquire lock '{name}' for holder '{holder}'", Name, Holder);

                throw new CouchbaseLockUnavailableException(Name)
                      {
                          Holder = getResult.ContentAs <LockDocument>().Holder
                      };
            }
        }
 public static Task <IMutationResult> ReplaceAsync <T>(this ICouchbaseCollection collection, string id, T content)
 {
     return(collection.ReplaceAsync(id, content, ReplaceOptions.Default));
 }
        /// <summary>
        /// Executes a query and ingests the results as documents into Couchbase server for further analytics.
        /// <para>
        /// NOTE: This is an experimental API and may change in the future.
        /// </para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cluster"></param>
        /// <param name="collection"></param>
        /// <param name="statement"></param>
        /// <param name="ingestOptions"></param>
        /// <returns></returns>
        public static async Task <IEnumerable <IMutationResult> > IngestAsync <T>(this ICluster cluster, string statement, ICouchbaseCollection collection, IngestOptions ingestOptions = null)
        {
            //use defaults if not options not explicitly passed
            ingestOptions ??= new IngestOptions();

            if (ingestOptions.TokenValue.IsCancellationRequested)
            {
                ingestOptions.TokenValue.ThrowIfCancellationRequested();
            }

            //execute the analytics query
            var result = await cluster.AnalyticsQueryAsync <T>(
                statement,
                options => options.CancellationToken(ingestOptions.TokenValue)
                ).ConfigureAwait(false);

            // ingest result into collection
            var results = new ConcurrentBag <Task <IMutationResult> >();

            await foreach (var row in result.WithCancellation(ingestOptions.TokenValue).ConfigureAwait(false))
            {
                Task <IMutationResult> op;
                switch (ingestOptions.IngestMethodValue)
                {
                case IngestMethod.Insert:
                    op = collection.InsertAsync(
                        ingestOptions.IdGeneratorValue(row),
                        row,
                        options =>
                    {
                        options.Expiry(ingestOptions.ExpiryValue);
                        options.Timeout(ingestOptions.TimeoutValue);
                    });
                    break;

                case IngestMethod.Upsert:
                    op = collection.UpsertAsync(
                        ingestOptions.IdGeneratorValue(row),
                        row,
                        options =>
                    {
                        options.Expiry(ingestOptions.ExpiryValue);
                        options.Timeout(ingestOptions.TimeoutValue);
                    });
                    break;

                case IngestMethod.Replace:
                    op = collection.ReplaceAsync(
                        ingestOptions.IdGeneratorValue(row),
                        row,
                        options =>
                    {
                        options.Expiry(ingestOptions.ExpiryValue);
                        options.Timeout(ingestOptions.TimeoutValue);
                    });
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                results.Add(op);
            }

            return(await Task.WhenAll(results).ConfigureAwait(false));
        }