コード例 #1
0
        /// <summary>
        /// Checks the primary node for the key, if a NMV is encountered, will retry on each replica.
        /// </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 result of the operation.
        /// </returns>
        public IOperationResult <T> ReadFromReplica <T>(ReplicaRead <T> operation)
        {
            //Is the cluster configured for Data services?
            if (!ConfigInfo.IsDataCapable)
            {
                throw new ServiceNotSupportedException("The cluster does not support Data services.");
            }

            IOperationResult <T> result = new OperationResult <T> {
                Success = false
            };

            do
            {
                var keyMapper = ConfigInfo.GetKeyMapper();
                var vBucket   = (IVBucket)keyMapper.MapKey(operation.Key);
                operation.VBucket = vBucket;

                if (vBucket.HasReplicas)
                {
                    foreach (var index in vBucket.Replicas)
                    {
                        var replica = vBucket.LocateReplica(index);
                        if (replica == null)
                        {
                            continue;
                        }
                        result = replica.Send(operation);
                        if (result.Success && !result.IsNmv())
                        {
                            return(result);
                        }
                        operation = (ReplicaRead <T>)operation.Clone();
                    }
                }
                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
                    };
                }
            } while (result.ShouldRetry() && !result.Success && !operation.TimedOut());

            if (!result.Success)
            {
                if (operation.TimedOut() &&
                    (result.Status != ResponseStatus.NoReplicasFound && result.Status != ResponseStatus.KeyNotFound))
                {
                    const string msg = "The operation has timed out.";
                    ((OperationResult)result).Message = msg;
                    ((OperationResult)result).Status  = ResponseStatus.OperationTimeout;
                }
                LogFailure(operation, result);
            }
            return(result);
        }
コード例 #2
0
        private async Task <IGetReplicaResult> GetReplica(string id, short index, IRequestSpan span,
                                                          CancellationToken cancellationToken, ITranscoderOverrideOptions options)
        {
            using var childSpan = _tracer.RequestSpan(OuterRequestSpans.ServiceSpan.Kv.ReplicaRead, span);
            using var getOp     = new ReplicaRead <object>(id, index)
                  {
                      Key   = id,
                      Cid   = Cid,
                      CName = Name,
                      SName = ScopeName,
                      Span  = childSpan
                  };
            _operationConfigurator.Configure(getOp, options);

            using var cts =
                      CreateRetryTimeoutCancellationTokenSource((ITimeoutOptions)options, getOp, out var tokenPair);
            await _bucket.RetryAsync(getOp, tokenPair).ConfigureAwait(false);

            return(new GetReplicaResult(getOp.ExtractBody(), getOp.Transcoder, _getLogger)
            {
                Id = getOp.Key,
                Cas = getOp.Cas,
                OpCode = getOp.OpCode,
                Flags = getOp.Flags,
                Header = getOp.Header,
                IsActive = false
            });
        }
コード例 #3
0
        private async Task <IGetReplicaResult> GetReplica(string id, short index, IInternalSpan span, CancellationToken cancellationToken, ITranscoderOverrideOptions options)
        {
            using var childSpan = _tracer.InternalSpan(OperationNames.ReplicaRead, span);
            using var getOp     = new ReplicaRead <object>
                  {
                      Key        = id,
                      Cid        = Cid,
                      CName      = Name,
                      ReplicaIdx = index,
                      Span       = childSpan
                  };
            _operationConfigurator.Configure(getOp, options);

            await _bucket.RetryAsync(getOp, cancellationToken).ConfigureAwait(false);

            return(new GetReplicaResult(getOp.ExtractBody(), getOp.Transcoder, _getLogger)
            {
                Id = getOp.Key,
                Cas = getOp.Cas,
                OpCode = getOp.OpCode,
                Flags = getOp.Flags,
                Header = getOp.Header,
                IsActive = false
            });
        }
コード例 #4
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);
        }
コード例 #5
0
        /// <summary>
        /// Checks the primary node for the key, if a NMV is encountered, will retry on each replica.
        /// </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 result of the operation.
        /// </returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public IOperationResult <T> ReadFromReplica <T>(ReplicaRead <T> operation)
        {
            var keyMapper = ConfigInfo.GetKeyMapper();
            var vBucket   = (IVBucket)keyMapper.MapKey(operation.Key);

            operation.VBucket = vBucket;

            IOperationResult <T> result = new OperationResult <T>();

            foreach (var index in vBucket.Replicas)
            {
                var replica = vBucket.LocateReplica(index);
                if (replica == null)
                {
                    continue;
                }
                result = replica.Send(operation);
                if (result.Success && !result.IsNmv())
                {
                    return(result);
                }
                operation = (ReplicaRead <T>)operation.Clone();
            }
            return(result);
        }
コード例 #6
0
        public void ReadFromReplica_WhenKeyNotFound_ReturnsKeyNotFound()
        {
            var controller = new Mock <IClusterController>();

            controller.Setup(x => x.Configuration).Returns(new ClientConfiguration());

            var server1 = new Mock <IServer>();

            server1.Setup(x => x.Send(It.IsAny <IOperation <dynamic> >())).Returns(new OperationResult <dynamic> {
                Status = ResponseStatus.KeyNotFound
            });
            server1.Setup(x => x.EndPoint).Returns(new IPEndPoint(IPAddress.Loopback, 8091));

            var server2 = new Mock <IServer>();

            server2.Setup(x => x.Send(It.IsAny <IOperation <dynamic> >())).Returns(new OperationResult <dynamic> {
                Status = ResponseStatus.KeyNotFound
            });
            server2.Setup(x => x.EndPoint).Returns(new IPEndPoint(IPAddress.Parse("255.255.0.0"), 8091));

            var vBucketServerMap = new VBucketServerMap
            {
                ServerList = new[]
                {
                    "localhost:8901",
                    "255.255.0.0:8091"
                },
                VBucketMap        = new[] { new[] { 0, 1 } },
                VBucketMapForward = new[] { new[] { 1 } }
            };
            var keyMapper = new VBucketKeyMapper(new Dictionary <IPAddress, IServer>
            {
                { IPAddress.Loopback, server1.Object },
                { IPAddress.Parse("255.255.0.0"), server2.Object }
            }, vBucketServerMap, 3, "default");

            var configInfo = new Mock <IConfigInfo>();

            configInfo.Setup(x => x.IsDataCapable).Returns(true);
            configInfo.Setup(x => x.GetKeyMapper()).Returns(keyMapper);
            configInfo.Setup(x => x.ClientConfig).Returns(new ClientConfiguration());
            var pending  = new ConcurrentDictionary <uint, IOperation>();
            var executor = new CouchbaseRequestExecuter(controller.Object, configInfo.Object, "default", pending);

            var op     = new ReplicaRead <dynamic>("thekey", null, new DefaultTranscoder(), 100);
            var result = executor.ReadFromReplica(op);

            Assert.AreEqual(ResponseStatus.KeyNotFound, result.Status);
        }
コード例 #7
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);
        }
コード例 #8
0
        public override IOperation Clone()
        {
            var cloned = new ReplicaRead <T>
            {
                Key                     = Key,
                Content                 = Content,
                Transcoder              = Transcoder,
                VBucketId               = VBucketId,
                Opaque                  = Opaque,
                Attempts                = Attempts,
                Cas                     = Cas,
                CreationTime            = CreationTime,
                LastConfigRevisionTried = LastConfigRevisionTried,
                BucketName              = BucketName,
                ErrorCode               = ErrorCode
            };

            return(cloned);
        }
コード例 #9
0
        private async Task <IGetReplicaResult> GetReplica(string id, short index, CancellationToken cancellationToken, ITypeTranscoder transcoder)
        {
            using var getOp = new ReplicaRead <object>
                  {
                      Key        = id,
                      Cid        = Cid,
                      ReplicaIdx = index,
                      Transcoder = transcoder
                  };
            await _bucket.RetryAsync(getOp, cancellationToken).ConfigureAwait(false);

            return(new GetReplicaResult(getOp.ExtractData(), transcoder, _getLogger)
            {
                Id = getOp.Key,
                Cas = getOp.Cas,
                OpCode = getOp.OpCode,
                Flags = getOp.Flags,
                Header = getOp.Header,
                IsActive = false
            });
        }
コード例 #10
0
        /// <summary>
        /// Checks the primary node for the key, if a NMV is encountered, will retry on each replica.
        /// </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 result of the operation.
        /// </returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public IOperationResult <T> ReadFromReplica <T>(ReplicaRead <T> operation)
        {
            var keyMapper = ConfigInfo.GetKeyMapper();
            var vBucket   = (IVBucket)keyMapper.MapKey(operation.Key);

            operation.VBucket = vBucket;

            IOperationResult <T> result = null;

            if (vBucket.HasReplicas)
            {
                foreach (var index in vBucket.Replicas)
                {
                    var replica = vBucket.LocateReplica(index);
                    if (replica == null)
                    {
                        continue;
                    }
                    result = replica.Send(operation);
                    if (result.Success && !result.IsNmv())
                    {
                        return(result);
                    }
                    operation = (ReplicaRead <T>)operation.Clone();
                }
            }
            else
            {
                result = new OperationResult <T>
                {
                    Status  = ResponseStatus.NoReplicasFound,
                    Message = "No replicas found; have you configured the bucket for replica reads?",
                    Success = false
                };
            }
            return(result);
        }
        public void ReadFromReplica_WhenKeyNotFound_ReturnsKeyNotFound()
        {
            var controller = new Mock<IClusterController>();
            controller.Setup(x => x.Configuration).Returns(new ClientConfiguration());

            var server1 = new Mock<IServer>();
            server1.Setup(x => x.Send(It.IsAny<IOperation<dynamic>>())).Returns(new OperationResult<dynamic> { Status = ResponseStatus.KeyNotFound });
            server1.Setup(x => x.EndPoint).Returns(new IPEndPoint(IPAddress.Loopback, 8091));

            var server2 = new Mock<IServer>();
            server2.Setup(x => x.Send(It.IsAny<IOperation<dynamic>>())).Returns(new OperationResult<dynamic> {Status = ResponseStatus.KeyNotFound});
            server2.Setup(x => x.EndPoint).Returns(new IPEndPoint(IPAddress.Parse("255.255.0.0"), 8091));

            var vBucketServerMap = new VBucketServerMap
            {
                ServerList = new[]
                {
                    "localhost:8901",
                    "255.255.0.0:8091"
                },
                VBucketMap = new[] { new[] { 0, 1 } },
                VBucketMapForward = new[] { new[] { 1 } }
            };
            var keyMapper = new VBucketKeyMapper(new Dictionary<IPAddress, IServer>
            {
                { IPAddress.Loopback, server1.Object},
                { IPAddress.Parse("255.255.0.0"), server2.Object}
            }, vBucketServerMap, 3, "default");

            var configInfo = new Mock<IConfigInfo>();
            configInfo.Setup(x => x.IsDataCapable).Returns(true);
            configInfo.Setup(x => x.GetKeyMapper()).Returns(keyMapper);
            configInfo.Setup(x => x.ClientConfig).Returns(new ClientConfiguration());
            var pending = new ConcurrentDictionary<uint, IOperation>();
            var executor = new CouchbaseRequestExecuter(controller.Object, configInfo.Object, "default", pending);

            var op = new ReplicaRead<dynamic>("thekey", null, new DefaultTranscoder(), 100);
            var result = executor.ReadFromReplica(op);
            Assert.AreEqual(ResponseStatus.KeyNotFound, result.Status);
        }