/// <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> /// 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> /// <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()); }
private void CollectPendingRpc(ConnectorEx oldLeader, AsyncSocket oldSocket) { if (null != oldLeader) { // 再 Rpc.UserState 里面记录发送目的的ConnectorEx,然后这里严格判断? // 由于一个时候只有Leader,所以直接使用Sender也足够了吧。 var ctxSends = Client.GetRpcContextsToSender(oldSocket); var ctxPending = Client.RemoveRpcContets(ctxSends.Keys); foreach (var rpc in ctxPending) { Pending.TryAdd(rpc, rpc); } } }
/// <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); }
SendForWait <TArgument, TResult>( Rpc <TArgument, TResult> rpc, bool autoResend = true, int timeout = -1) where TArgument : Bean, new() where TResult : Bean, new() { if (timeout < 0) { timeout = RaftConfig.AppendEntriesTimeout + 1000; } var future = new TaskCompletionSource <Rpc <TArgument, TResult> >(); if (autoResend) { var tmp = _Leader; if (null != tmp && tmp.IsHandshakeDone && rpc.Send(tmp.Socket, (p) => SendForWaitHandle(future, rpc), timeout)) { return(future); } rpc.ResponseHandle = (p) => SendForWaitHandle(future, rpc); rpc.Timeout = timeout; Pending.TryAdd(rpc, rpc); return(future); } // 记录不要自动发送的请求。 NotAutoResend[rpc] = rpc; if (false == rpc.Send(_Leader?.Socket, (p) => { NotAutoResend.TryRemove(p, out var _); return(SendForWaitHandle(future, rpc)); }, timeout)) { future.TrySetException(new Exception("Send Failed.")); } ; return(future); }
/// <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()); }
/// <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); }
/// <summary> /// 发送Rpc请求。 /// 如果 autoResend == true,那么总是返回成功。内部会在需要的时候重发请求。 /// 如果 autoResend == false,那么返回结果表示是否成功。 /// </summary> /// <typeparam name="TArgument"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="rpc"></param> /// <param name="handle"></param> /// <param name="autoResend"></param> /// <param name="timeout"></param> /// <returns></returns> public bool Send <TArgument, TResult>( Rpc <TArgument, TResult> rpc, Func <Protocol, int> handle, bool autoResend = true, int timeout = -1) where TArgument : Bean, new() where TResult : Bean, new() { if (timeout < 0) { timeout = RaftConfig.AppendEntriesTimeout + 1000; } if (autoResend) { var tmp = _Leader; if (null != tmp && tmp.IsHandshakeDone && rpc.Send(tmp.Socket, handle, timeout)) { return(true); } rpc.ResponseHandle = handle; rpc.Timeout = timeout; Pending.TryAdd(rpc, rpc); return(true); } // 记录不要自动发送的请求。 NotAutoResend[rpc] = rpc; return(rpc.Send(_Leader?.Socket, (p) => { NotAutoResend.TryRemove(p, out var _); return handle(p); }, timeout)); }
/// <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); }