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));
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #8
0
        /// <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);
        }
Beispiel #9
0
        /// <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());
        }
Beispiel #10
0
        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);
        }
Beispiel #12
0
        /// <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());
        }
Beispiel #14
0
        /// <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);
        }