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