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)); }