private async Task <bool> CheckPersistToAsync(ObserveParams observeParams) { if (observeParams.PersistTo == PersistTo.Zero) { return(true); } var op = new ObserveSeqno(observeParams.Token, _clusterController.Transcoder, _timeout); observeParams.Operation = op; var tcs = new TaskCompletionSource <IOperationResult <ObserveSeqnoResponse> >(); op.Completed = CallbackFactory.CompletedFuncForRetry(_pending, _clusterController, tcs); _pending.TryAdd(op.Opaque, op); var server = await GetServerAsync(observeParams); await server.SendAsync(op).ContinueOnAnyContext(); var response = await tcs.Task.ContinueOnAnyContext(); observeParams.CheckMutationLost(response); observeParams.CheckPersisted(response); return(observeParams.IsDurabilityMet()); }
/// <summary> /// Asynchronously checks the replications status of a key. /// </summary> /// <param name="observeParams">The <see cref="ObserveParams"/> object.</param> /// <param name="replicaIndex">The replicaIndex of the replica within the <see cref="IVBucket"/></param> /// <returns>True if the durability requirements specified by <see cref="PersistTo"/> and <see cref="ReplicateTo"/> have been satisfied.</returns> private async Task <bool> CheckReplicaAsync(ObserveParams observeParams, int replicaIndex) { if (observeParams.IsDurabilityMet()) { return(true); } var operation = new Observe(observeParams.Key, observeParams.VBucket, _clusterController.Transcoder, (uint)_timeout); var tcs = new TaskCompletionSource <IOperationResult <ObserveState> >(); operation.Completed = CallbackFactory.CompletedFuncForRetry(_pending, _clusterController, tcs); _pending.TryAdd(operation.Opaque, operation); var replica = observeParams.VBucket.LocateReplica(replicaIndex); await replica.SendAsync(operation).ContinueOnAnyContext(); var result = await tcs.Task.ContinueOnAnyContext(); Log.Debug("Replica {0} - {1} {2} - opaque: {3} key:{4}", replica.EndPoint, result.Value.KeyState, replicaIndex, operation.Opaque, observeParams.Key); var state = result.Value; if (state.KeyState == observeParams.Criteria.PersistState) { Interlocked.Increment(ref observeParams.ReplicatedToCount); Interlocked.Increment(ref observeParams.PersistedToCount); } else if (state.KeyState == observeParams.Criteria.ReplicateState) { Interlocked.Increment(ref observeParams.ReplicatedToCount); } return(!observeParams.HasMutated(state.Cas)); }
/// <summary> /// Sends a <see cref="IOperation" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <param name="operation">The <see cref="IOperation" /> to send.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public async override Task <IOperationResult> SendWithRetryAsync(IOperation operation) { var tcs = new TaskCompletionSource <IOperationResult>(); var cts = new CancellationTokenSource(OperationLifeSpan); cts.CancelAfter(OperationLifeSpan); try { var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key); operation.VBucket = vBucket; operation.Completed = CallbackFactory.CompletedFuncWithRetryForCouchbase( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); var server = vBucket.LocatePrimary(); server.SendAsync(operation).ConfigureAwait(false); } catch (Exception e) { tcs.TrySetResult(new OperationResult { Exception = e, Status = ResponseStatus.ClientFailure }); } return(await tcs.Task); }
/// <summary> /// Sends a <see cref="IOperation" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <param name="operation">The <see cref="IOperation" /> to send.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public override Task <IOperationResult> SendWithRetryAsync(IOperation operation) { var tcs = new TaskCompletionSource <IOperationResult>(); var cts = new CancellationTokenSource(OperationLifeSpan); cts.CancelAfter(OperationLifeSpan); try { operation.Completed = CallbackFactory.CompletedFuncWithRetryForMemcached( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); var server = GetServer(operation.Key); server.SendAsync(operation).ConfigureAwait(false); } catch (Exception e) { tcs.TrySetResult(new OperationResult { Exception = e, Status = ResponseStatus.ClientFailure }); } return(tcs.Task); }
/// <summary> /// Checks the primary node for the key, if a NMV is encountered, will retry on each replica, asynchronously. /// </summary> /// <typeparam name="T">The Type of the body of the request.</typeparam> /// <param name="operation">The <see cref="IOperation" /> to execiute.</param> /// <returns> /// The <see cref="Task{IOperationResult}" /> object representing asynchcronous operation. /// </returns> /// <exception cref="System.NotImplementedException"></exception> public async Task <IOperationResult <T> > ReadFromReplicaAsync <T>(ReplicaRead <T> operation) { var tcs = new TaskCompletionSource <IOperationResult <T> >(); var cts = new CancellationTokenSource(OperationLifeSpan); cts.CancelAfter(OperationLifeSpan); var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key); operation.VBucket = vBucket; operation.Completed = CallbackFactory.CompletedFuncForRetry(this, Pending, ClusterController, tcs); Pending.TryAdd(operation.Opaque, operation); IOperationResult <T> result = new OperationResult <T>(); foreach (var index in vBucket.Replicas) { var replica = vBucket.LocateReplica(index); if (replica == null) { continue; } await replica.SendAsync(operation).ConfigureAwait(false); result = await tcs.Task; if (result.Success && !result.IsNmv()) { return(result); } } return(result); }
/// <summary> /// Sends a <see cref="IOperation" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <param name="operation">The <see cref="IOperation" /> to send.</param> /// <param name="tcs">The <see cref="TaskCompletionSource{T}"/> the represents the task to await on.</param> /// <param name="cts">The <see cref="CancellationTokenSource"/> for cancellation.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public override async Task <IOperationResult> SendWithRetryAsync(IOperation operation, TaskCompletionSource <IOperationResult> tcs = null, CancellationTokenSource cts = null) { tcs = tcs ?? new TaskCompletionSource <IOperationResult>(); cts = cts ?? new CancellationTokenSource(OperationLifeSpan); try { //Is the cluster configured for Data services? if (!ConfigInfo.IsDataCapable) { tcs.SetException(new ServiceNotSupportedException( ExceptionUtil.GetMessage(ExceptionUtil.ServiceNotSupportedMsg, "Data"))); } var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key, operation.LastConfigRevisionTried); operation.VBucket = vBucket; operation.LastConfigRevisionTried = vBucket.Rev; operation.Completed = CallbackFactory.CompletedFuncWithRetryForCouchbase( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); IServer server; var attempts = 0; while ((server = vBucket.LocatePrimary()) == null) { if (attempts++ > 10) { throw new TimeoutException("Could not acquire a server."); } await Task.Delay((int)Math.Pow(2, attempts)).ContinueOnAnyContext(); } Log.Debug("Starting send for {0} with {1}", operation.Opaque, server.EndPoint); await server.SendAsync(operation).ContinueOnAnyContext(); } catch (Exception e) { tcs.TrySetResult(new OperationResult { Id = operation.Key, Exception = e, Status = ResponseStatus.ClientFailure }); } return(await tcs.Task.ContinueOnAnyContext()); }
/// <summary> /// Sends a <see cref="IOperation" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <param name="operation">The <see cref="IOperation" /> to send.</param> /// <param name="tcs">The <see cref="TaskCompletionSource{T}"/> the represents the task to await on.</param> /// <param name="cts">The <see cref="CancellationTokenSource"/> for cancellation.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public override Task <IOperationResult> SendWithRetryAsync(IOperation operation, TaskCompletionSource <IOperationResult> tcs = null, CancellationTokenSource cts = null) { tcs = tcs ?? new TaskCompletionSource <IOperationResult>(); cts = cts ?? new CancellationTokenSource(OperationLifeSpan); //Is the cluster configured for Data services? if (!ConfigInfo.IsDataCapable) { tcs.SetException( new ServiceNotSupportedException("The cluster does not support Data services.")); } try { var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key); operation.VBucket = vBucket; operation.Completed = CallbackFactory.CompletedFuncWithRetryForCouchbase( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); IServer server; var attempts = 0; while ((server = vBucket.LocatePrimary()) == null) { if (attempts++ > 10) { throw new TimeoutException("Could not acquire a server."); } Thread.Sleep((int)Math.Pow(2, attempts)); } Log.Debug(m => m("Starting send for {0} with {1}", operation.Opaque, server.EndPoint)); server.SendAsync(operation).ConfigureAwait(false); } catch (Exception e) { tcs.TrySetResult(new OperationResult { Exception = e, Status = ResponseStatus.ClientFailure }); } return(tcs.Task); }
/// <summary> /// Checks the primary node for the key, if a NMV is encountered, will retry on each replica, asynchronously. /// </summary> /// <typeparam name="T">The Type of the body of the request.</typeparam> /// <param name="operation">The <see cref="IOperation" /> to execiute.</param> /// <returns> /// The <see cref="Task{IOperationResult}" /> object representing asynchcronous operation. /// </returns> public async Task <IOperationResult <T> > ReadFromReplicaAsync <T>(ReplicaRead <T> operation) { var tcs = new TaskCompletionSource <IOperationResult <T> >(); var cts = new CancellationTokenSource(OperationLifeSpan); cts.CancelAfter(OperationLifeSpan); var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key); operation.VBucket = vBucket; operation.Completed = CallbackFactory.CompletedFuncForRetry(Pending, ClusterController, tcs); Pending.TryAdd(operation.Opaque, operation); IOperationResult <T> result = null; if (vBucket.HasReplicas) { foreach (var index in vBucket.Replicas) { var replica = vBucket.LocateReplica(index); if (replica == null) { continue; } await replica.SendAsync(operation).ContinueOnAnyContext(); result = await tcs.Task; if (result.Success && !result.IsNmv()) { return(result); } } } else { result = new OperationResult <T> { Id = operation.Key, Status = ResponseStatus.NoReplicasFound, Message = "No replicas found; have you configured the bucket for replica reads?", Success = false }; } return(result); }
/// <summary> /// Sends a <see cref="IOperation" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <param name="operation">The <see cref="IOperation" /> to send.</param> /// /// <param name="tcs">The <see cref="TaskCompletionSource{T}"/> the represents the task to await on.</param> /// <param name="cts">The <see cref="CancellationTokenSource"/> for cancellation.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public override async Task <IOperationResult> SendWithRetryAsync(IOperation operation, TaskCompletionSource <IOperationResult> tcs = null, CancellationTokenSource cts = null) { tcs = tcs ?? new TaskCompletionSource <IOperationResult>(); cts = cts ?? new CancellationTokenSource(OperationLifeSpan); var parentSpan = Tracer.StartParentSpan(operation, ConfigInfo.BucketName); try { operation.Completed = CallbackFactory.CompletedFuncWithRetryForMemcached( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); IServer server; var attempts = 0; while ((server = GetServer(operation.Key)) == null) { if (attempts++ > 10) { throw new TimeoutException("Could not acquire a server."); } await Task.Delay((int)Math.Pow(2, attempts)).ContinueOnAnyContext(); } await server.SendAsync(operation).ContinueOnAnyContext(); } catch (Exception e) { tcs.TrySetResult(new OperationResult { Id = operation.Key, Exception = e, Status = ResponseStatus.ClientFailure }); } finally { parentSpan.Finish(); } return(await tcs.Task.ContinueOnAnyContext()); }
public Task <IOperationResult <ObserveState> > ObserveAsync(Observe operation) { var tcs = new TaskCompletionSource <IOperationResult <ObserveState> >(); var cts = new CancellationTokenSource(OperationLifeSpan); cts.CancelAfter(OperationLifeSpan); var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key); operation.VBucket = vBucket; operation.Completed = CallbackFactory.CompletedFuncForRetry(Pending, ClusterController, tcs); Pending.TryAdd(operation.Opaque, operation); var server = vBucket.LocatePrimary(); server.SendAsync(operation); return(tcs.Task); }
private async Task <bool> CheckPersistToAsync(ObserveParams observeParams) { if (observeParams.PersistTo == PersistTo.Zero) { return(true); } var tcs = new TaskCompletionSource <IOperationResult <ObserveState> >(); var operation = new Observe(observeParams.Key, observeParams.VBucket, _clusterController.Transcoder, (uint)_timeout); operation.Completed = CallbackFactory.CompletedFuncForRetry(_pending, _clusterController, tcs); _pending.TryAdd(operation.Opaque, operation); var server = await GetServerAsync(observeParams); await server.SendAsync(operation).ContinueOnAnyContext(); var result = await tcs.Task.ContinueOnAnyContext(); Log.Debug("Master {0} - {1} key:{2}", server.EndPoint, result.Value, observeParams.Key); var state = result.Value; if (state.KeyState == observeParams.Criteria.PersistState) { Interlocked.Increment(ref observeParams.PersistedToCount); } //Key mutation detected so fail if (observeParams.HasMutated(state.Cas)) { Log.Debug("Mutation detected {0} - {1} - opaque: {2} key:{3}", server.EndPoint, result.Value, operation.Opaque, observeParams.Key); throw new DocumentMutationException(string.Format("Document mutation detected during observe for key '{0}'", observeParams.Key)); } //Check if durability requirements have been met if (observeParams.IsDurabilityMet()) { Log.Debug("Durability met {0} - {1} - opaque: {2} key:{3}", server.EndPoint, result.Value, operation.Opaque, observeParams.Key); return(true); } return(false); }
/// <summary> /// Sends a <see cref="IOperation{T}" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <typeparam name="T">The Type of the body of the request.</typeparam> /// <param name="operation">The <see cref="IOperation{T}" /> to send.</param> /// <param name="tcs">The <see cref="TaskCompletionSource{T}"/> the represents the task to await on.</param> /// <param name="cts">The <see cref="CancellationTokenSource"/> for cancellation.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public override Task <IOperationResult <T> > SendWithRetryAsync <T>(IOperation <T> operation, TaskCompletionSource <IOperationResult <T> > tcs = null, CancellationTokenSource cts = null) { tcs = tcs ?? new TaskCompletionSource <IOperationResult <T> >(); cts = cts ?? new CancellationTokenSource(OperationLifeSpan); try { var keyMapper = ConfigInfo.GetKeyMapper(); var vBucket = (IVBucket)keyMapper.MapKey(operation.Key); operation.VBucket = vBucket; operation.Completed = CallbackFactory.CompletedFuncWithRetryForCouchbase( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); IServer server; var attempts = 0; while ((server = vBucket.LocatePrimary()) == null) { if (attempts++ > 10) { throw new TimeoutException("Could not acquire a server."); } Thread.Sleep((int)Math.Pow(2, attempts)); } server.SendAsync(operation).ConfigureAwait(false); } catch (Exception e) { tcs.TrySetResult(new OperationResult <T> { Exception = e, Status = ResponseStatus.ClientFailure }); } return(tcs.Task); }
private async Task <bool> CheckReplicaAsync(ObserveParams observeParams, int replicaId) { var op = new ObserveSeqno(observeParams.Token, _clusterController.Transcoder, _timeout); observeParams.Operation = op; var tcs = new TaskCompletionSource <IOperationResult <ObserveSeqnoResponse> >(); op.Completed = CallbackFactory.CompletedFuncForRetry(_pending, _clusterController, tcs); _pending.TryAdd(op.Opaque, op); Log.Debug("checking replica {0} - opaque: {1}", replicaId, op.Opaque); var replica = observeParams.VBucket.LocateReplica(replicaId); await replica.SendAsync(op).ContinueOnAnyContext(); var response = await tcs.Task.ContinueOnAnyContext(); observeParams.CheckMutationLost(response); observeParams.CheckPersisted(response); observeParams.CheckReplicated(response); return(observeParams.IsDurabilityMet()); }
/// <summary> /// Sends a <see cref="IOperation" /> to the Couchbase Server using the Memcached protocol using async/await. /// </summary> /// <param name="operation">The <see cref="IOperation" /> to send.</param> /// /// <param name="tcs">The <see cref="TaskCompletionSource{T}"/> the represents the task to await on.</param> /// <param name="cts">The <see cref="CancellationTokenSource"/> for cancellation.</param> /// <returns> /// An <see cref="Task{IOperationResult}" /> object representing the asynchronous operation. /// </returns> public override Task <IOperationResult> SendWithRetryAsync(IOperation operation, TaskCompletionSource <IOperationResult> tcs = null, CancellationTokenSource cts = null) { tcs = tcs ?? new TaskCompletionSource <IOperationResult>(); cts = cts ?? new CancellationTokenSource(OperationLifeSpan); try { operation.Completed = CallbackFactory.CompletedFuncWithRetryForMemcached( this, Pending, ClusterController, tcs, cts.Token); Pending.TryAdd(operation.Opaque, operation); IServer server; var attempts = 0; while ((server = GetServer(operation.Key)) == null) { if (attempts++ > 10) { throw new TimeoutException("Could not acquire a server."); } Thread.Sleep((int)Math.Pow(2, attempts)); } server.SendAsync(operation).ConfigureAwait(false); } catch (Exception e) { tcs.TrySetResult(new OperationResult { Id = operation.Key, Exception = e, Status = ResponseStatus.ClientFailure }); } return(tcs.Task); }