/// <summary> /// /// </summary> public void Dispose() { try { if (sm != null) { sm.Dispose(); sm = null; } } catch {} try { ResponseCrate rc = null; foreach (var el in df.ToList()) { if (df.TryRemove(el.Key, out rc)) { if (rc.mre != null) { rc.IsRespOk = false; rc.mre.Set(); rc.mre.Dispose(); rc.mre = null; } } } } catch { } }
public async Task <bool> AddLogEntryAsync(byte[] data, string entityName = "default", int timeoutMs = 20000) { if (System.Threading.Interlocked.Read(ref disposed) == 1) { return(false); } RaftNode rn = null; if (this.raftNodes.TryGetValue(entityName, out rn)) { //Generating externalId var msgId = AsyncResponseHandler.GetMessageId(); var msgIdStr = msgId.ToBytesString(); var resp = new ResponseCrate(); resp.TimeoutsMs = timeoutMs; //enable for amre //resp.TimeoutsMs = Int32.MaxValue; //using timeout of the wait handle (not the timer), enable for mre //resp.Init_MRE(); resp.Init_AMRE(); AsyncResponseHandler.df[msgIdStr] = resp; var aler = rn.AddLogEntry(data, msgId); switch (aler.AddResult) { case AddLogEntryResult.eAddLogEntryResult.LOG_ENTRY_IS_CACHED: case AddLogEntryResult.eAddLogEntryResult.NODE_NOT_A_LEADER: //async waiting await resp.amre.WaitAsync(); //enable for amre resp.Dispose_MRE(); if (AsyncResponseHandler.df.TryRemove(msgIdStr, out resp)) { if (resp.IsRespOk) { return(true); } } break; default: //case AddLogEntryResult.eAddLogEntryResult.ERROR_OCCURED: //case AddLogEntryResult.eAddLogEntryResult.NO_LEADER_YET: resp.Dispose_MRE(); AsyncResponseHandler.df.TryRemove(msgIdStr, out resp); return(false); } } //return new AddLogEntryResult { AddResult = AddLogEntryResult.eAddLogEntryResult.NODE_NOT_FOUND_BY_NAME }; //return new Tuple<bool, byte[]>(false, null); return(false); }
/// <summary> /// /// </summary> /// <param name="args">payload which must be send to remote partner</param> /// <param name="callBack">if specified then response for the request will be returned into callBack (async). Default is sync.</param> /// <param name="timeoutMs">Default 30 sec</param> /// <returns></returns> public Tuple <bool, byte[]> RemoteRequest(byte[] args, Action <Tuple <bool, byte[]> > callBack = null, int timeoutMs = 30000) { ulong msgId = sm.GetMessageId(); var resp = new ResponseCrate(); if (callBack != null) { //Async return resp.callBack = callBack; df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { df.TryRemove(msgId, out resp); callBack(new Tuple <bool, byte[]>(false, null)); return(new Tuple <bool, byte[]>(false, null)); } return(new Tuple <bool, byte[]>(true, null)); } resp.mre = new ManualResetEvent(false); df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { if (resp.mre != null) { resp.mre.Dispose(); } resp.mre = null; df.TryRemove(msgId, out resp); return(new Tuple <bool, byte[]>(false, null)); } else if (!resp.mre.WaitOne(timeoutMs)) { if (resp.mre != null) { resp.mre.Dispose(); } resp.mre = null; df.TryRemove(msgId, out resp); return(new Tuple <bool, byte[]>(false, null)); } if (resp.mre != null) { resp.mre.Dispose(); } resp.mre = null; if (df.TryRemove(msgId, out resp)) { return(new Tuple <bool, byte[]>(resp.IsRespOk, resp.res)); } return(new Tuple <bool, byte[]>(false, null)); }
/// <summary> /// /// </summary> public void Dispose() { if (System.Threading.Interlocked.CompareExchange(ref Disposed, 1, 0) != 0) { return; } //this.sm.SharmIPC.LogException("dispose test",new Exception("p1 ")); try { if (tmr != null) { tmr.Dispose(); tmr = null; } } catch { } //this.sm.SharmIPC.LogException("dispose test", new Exception("p2")); try { ResponseCrate rc = null; foreach (var el in df.ToList()) { if (df.TryRemove(el.Key, out rc)) { rc.IsRespOk = false; rc.Dispose_MRE(); } } } catch { } //this.sm.SharmIPC.LogException("dispose test", new Exception("p3")); try { if (sm != null) { sm.Dispose(); sm = null; } } catch { } }
/// <summary> /// Usage var x = await RemoteRequestAsync(...); /// </summary> /// <param name="args">payload which must be send to remote partner</param> /// <param name="timeoutMs">Default 30 sec</param> /// <returns></returns> public async Task <Tuple <bool, byte[]> > RemoteRequestAsync(byte[] args, int timeoutMs = 30000) { if (Interlocked.Read(ref Disposed) == 1) { return(new Tuple <bool, byte[]>(false, null)); } ulong msgId = sm.GetMessageId(); var resp = new ResponseCrate(); resp.TimeoutsMs = timeoutMs; //enable for amre //resp.TimeoutsMs = Int32.MaxValue; //using timeout of the wait handle (not the timer), enable for mre //resp.Init_MRE(); resp.Init_AMRE(); df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { resp.Dispose_MRE(); //if (resp.mre != null) // resp.mre.Dispose(); //resp.mre = null; df.TryRemove(msgId, out resp); return(new Tuple <bool, byte[]>(false, null)); } //await resp.mre.AsTask(TimeSpan.FromMilliseconds(timeoutMs)); //enable for mre await resp.amre.WaitAsync(); //enable for amre resp.Dispose_MRE(); if (df.TryRemove(msgId, out resp)) { return(new Tuple <bool, byte[]>(resp.IsRespOk, resp.res)); } return(new Tuple <bool, byte[]>(false, null)); }
/// <summary> /// called by external service /// </summary> /// <param name="data"></param> /// <param name="entityName"></param> /// <param name="timeoutMs"></param> /// <returns></returns> public async Task <object> AddLogEntryRequestAsync(byte[] data, string entityName = "default", int timeoutMs = 20000) { if (System.Threading.Interlocked.Read(ref disposed) == 1) { return(false); } RaftStateMachine rn = this.raftNode;; { //Generating externalId var msgId = AsyncResponseHandler.GetMessageId(); var msgIdStr = msgId.ToBytesString(); var resp = new ResponseCrate(); resp.TimeoutsMs = timeoutMs; //enable for amre resp.Init_AMRE(); AsyncResponseHandler.df[msgIdStr] = resp; var aler = rn.logHandler.ProcessAddLogRequest(data, msgId); switch (aler.AddResult) { case AddLogEntryResult.eAddLogEntryResult.LOG_ENTRY_IS_CACHED: case AddLogEntryResult.eAddLogEntryResult.NODE_NOT_A_LEADER: //async waiting resp.amre.Wait(); //enable for amre resp.Dispose_MRE(); if (AsyncResponseHandler.df.TryRemove(msgIdStr, out resp)) { if (resp.IsRespOk) { return(resp.ReturnValue); } } break; default: resp.Dispose_MRE(); AsyncResponseHandler.df.TryRemove(msgIdStr, out resp); return(resp.ReturnValue); } } return(null); }
SharmIpc(string uniqueHandlerName, long bufferCapacity = 50000, int maxQueueSizeInBytes = 20000000, Action <string, System.Exception> ExternalExceptionHandler = null, eProtocolVersion protocolVersion = eProtocolVersion.V1) { this.Statistic.ipc = this; tmr = new Timer(new TimerCallback((state) => { DateTime now = DateTime.UtcNow; //This timer is necessary for Calls based on Callbacks, calls based on WaitHandler have their own timeout, //That's why for non-callback calls, timeout will be infinite List <ulong> toRemove = new List <ulong>(); //foreach (var el in df.Where(r => now.Subtract(r.Value.created).TotalMilliseconds >= r.Value.TimeoutsMs)) foreach (var el in df.Where(r => now.Subtract(r.Value.created).TotalMilliseconds >= r.Value.TimeoutsMs).ToList()) { if (el.Value.callBack != null) { toRemove.Add(el.Key); } else { el.Value.Set_MRE(); } } ResponseCrate rc = null; foreach (var el in toRemove) { if (df.TryRemove(el, out rc)) { rc.callBack(new Tuple <bool, byte[]>(false, null)); //timeout } } }), null, 10000, 10000); this.ExternalExceptionHandler = ExternalExceptionHandler; sm = new SharedMemory(uniqueHandlerName, this, bufferCapacity, maxQueueSizeInBytes, protocolVersion); }
/// <summary> /// Any incoming data from remote partner is accumulated here /// </summary> /// <param name="msgType"></param> /// <param name="msgId"></param> /// <param name="bt"></param> void InternalDataArrived(eMsgType msgType, ulong msgId, byte[] bt) { ResponseCrate rsp = null; switch (msgType) { case eMsgType.Request: Task.Run(() => { if (AsyncRemoteCallHandler != null) { AsyncRemoteCallHandler(msgId, bt); //Answer must be supplied via AsyncAnswerOnRemoteCall } else { this.remoteCallHandler(bt); } }); break; case eMsgType.RpcRequest: Task.Run(() => { if (AsyncRemoteCallHandler != null) { AsyncRemoteCallHandler(msgId, bt); //Answer must be supplied via AsyncAnswerOnRemoteCall } else { var res = this.remoteCallHandler(bt); sm.SendMessage(res.Item1 ? eMsgType.RpcResponse : eMsgType.ErrorInRpc, sm.GetMessageId(), res.Item2, msgId); } }); break; case eMsgType.ErrorInRpc: case eMsgType.RpcResponse: if (df.TryGetValue(msgId, out rsp)) { rsp.res = bt; rsp.IsRespOk = msgType == eMsgType.RpcResponse; if (rsp.callBack == null) { rsp.mre.Set(); } else { df.TryRemove(msgId, out rsp); rsp.callBack(new Tuple <bool, byte[]>(rsp.IsRespOk, bt)); } } break; } }
//internal void InternalDataArrived(eMsgType msgType, ulong msgId, byte[] bt) //{ // ResponseCrate rsp = null; // switch (msgType) // { // case eMsgType.Request: // if (AsyncRemoteCallHandler != null) // { // RunAsync(msgId, bt); // } // else // { // RunV1(bt); // } // break; // case eMsgType.RpcRequest: // if (AsyncRemoteCallHandler != null) // { // RunAsync(msgId, bt); // //Answer must be supplied via AsyncAnswerOnRemoteCall // } // else // { // Run(msgId, bt); // } // break; // case eMsgType.ErrorInRpc: // case eMsgType.RpcResponse: // if (df.TryGetValue(msgId, out rsp)) // { // rsp.res = bt; // rsp.IsRespOk = msgType == eMsgType.RpcResponse; // if (rsp.callBack == null) // { // //rsp.mre.Set(); //Signalling, to make waiting in parallel thread to proceed // rsp.Set_MRE(); // } // else // { // df.TryRemove(msgId, out rsp); // //Calling callback in parallel thread, quicly to return to ReaderWriterhandler.Reader procedure // RunV2(rsp, bt); // } // } // break; // } //} //async Task RunAsync(ulong msgId, byte[] bt) //{ // AsyncRemoteCallHandler(msgId, bt); //} //async Task Run(ulong msgId, byte[] bt) //{ // var res = this.remoteCallHandler(bt); // sm.SendMessage(res.Item1 ? eMsgType.RpcResponse : eMsgType.ErrorInRpc, sm.GetMessageId(), res.Item2, msgId); //} //async Task RunV1(byte[] bt) //{ // this.remoteCallHandler(bt); //} //async Task RunV2(ResponseCrate rsp, byte[] bt) //{ // rsp.callBack(new Tuple<bool, byte[]>(rsp.IsRespOk, bt)); //} /// <summary> /// /// </summary> /// <param name="args">payload which must be send to remote partner</param> /// <param name="callBack">if specified then response for the request will be returned into callBack (async). Default is sync.</param> /// <param name="timeoutMs">Default 30 sec</param> /// <returns></returns> public Tuple <bool, byte[]> RemoteRequest(byte[] args, Action <Tuple <bool, byte[]> > callBack = null, int timeoutMs = 30000) { ulong msgId = sm.GetMessageId(); var resp = new ResponseCrate(); if (callBack != null) { resp.TimeoutsMs = timeoutMs; //IS NECESSARY FOR THE CALLBACK TYPE OF RETURN //Async return resp.callBack = callBack; df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { df.TryRemove(msgId, out resp); callBack(new Tuple <bool, byte[]>(false, null)); return(new Tuple <bool, byte[]>(false, null)); } return(new Tuple <bool, byte[]>(true, null)); } resp.TimeoutsMs = Int32.MaxValue; //using timeout of the wait handle (not the timer) //resp.mre = new ManualResetEvent(false); resp.Init_MRE(); df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { resp.Dispose_MRE(); //if (resp.mre != null) // resp.mre.Dispose(); //resp.mre = null; df.TryRemove(msgId, out resp); return(new Tuple <bool, byte[]>(false, null)); } //else if (!resp.mre.WaitOne(timeoutMs)) else if (!resp.WaitOne_MRE(timeoutMs)) { //--STAT this.Statistic.Timeout(); //if (resp.mre != null) // resp.mre.Dispose(); //resp.mre = null; resp.Dispose_MRE(); df.TryRemove(msgId, out resp); return(new Tuple <bool, byte[]>(false, null)); } //if (resp.mre != null) // resp.mre.Dispose(); //resp.mre = null; resp.Dispose_MRE(); if (df.TryRemove(msgId, out resp)) { return(new Tuple <bool, byte[]>(resp.IsRespOk, resp.res)); } return(new Tuple <bool, byte[]>(false, null)); }
//async Task CallAsyncRemoteHandler(ulong msgId, byte[] bt) //{ // AsyncRemoteCallHandler(msgId, bt); //} /// <summary> /// Any incoming data from remote partner is accumulated here /// </summary> /// <param name="msgType"></param> /// <param name="msgId"></param> /// <param name="bt"></param> internal void InternalDataArrived(eMsgType msgType, ulong msgId, byte[] bt) { ResponseCrate rsp = null; switch (msgType) { case eMsgType.Request: Task.Run(() => { if (AsyncRemoteCallHandler != null) { //CallAsyncRemoteHandler(msgId, bt); AsyncRemoteCallHandler(msgId, bt); //Answer must be supplied via AsyncAnswerOnRemoteCall } else { this.remoteCallHandler(bt); } }); break; case eMsgType.RpcRequest: Task.Run(() => { if (AsyncRemoteCallHandler != null) { AsyncRemoteCallHandler(msgId, bt); //Answer must be supplied via AsyncAnswerOnRemoteCall } else { var res = this.remoteCallHandler(bt); sm.SendMessage(res.Item1 ? eMsgType.RpcResponse : eMsgType.ErrorInRpc, sm.GetMessageId(), res.Item2, msgId); } }); break; case eMsgType.ErrorInRpc: case eMsgType.RpcResponse: if (df.TryGetValue(msgId, out rsp)) { rsp.res = bt; rsp.IsRespOk = msgType == eMsgType.RpcResponse; if (rsp.callBack == null) { //rsp.mre.Set(); //Signalling, to make waiting in parallel thread to proceed rsp.Set_MRE(); } else { df.TryRemove(msgId, out rsp); //Calling callback in parallel thread, quicly to return to ReaderWriterhandler.Reader procedure Task.Run(() => { rsp.callBack(new Tuple <bool, byte[]>(rsp.IsRespOk, bt)); }); } } break; } }
/// <summary> /// /// </summary> /// <param name="args">payload which must be send to remote partner</param> /// <param name="callBack">if specified then response for the request will be returned into callBack (async). Default is sync.</param> /// <param name="timeoutMs">Default 30 sec</param> /// <returns></returns> public Tuple<bool, byte[]> RemoteRequest(byte[] args, Action<Tuple<bool, byte[]>> callBack = null, int timeoutMs = 30000) { ulong msgId = sm.GetMessageId(); var resp = new ResponseCrate(); if (callBack != null) { //Async return resp.callBack = callBack; df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { df.TryRemove(msgId, out resp); callBack(new Tuple<bool, byte[]>(false, null)); return new Tuple<bool, byte[]>(false, null); } return new Tuple<bool, byte[]>(true, null); } resp.mre = new ManualResetEvent(false); df[msgId] = resp; if (!sm.SendMessage(eMsgType.RpcRequest, msgId, args)) { if (resp.mre != null) resp.mre.Dispose(); resp.mre = null; df.TryRemove(msgId, out resp); return new Tuple<bool, byte[]>(false, null); } else if (!resp.mre.WaitOne(timeoutMs)) { if (resp.mre != null) resp.mre.Dispose(); resp.mre = null; df.TryRemove(msgId, out resp); return new Tuple<bool, byte[]>(false, null); } if (resp.mre != null) resp.mre.Dispose(); resp.mre = null; if (df.TryRemove(msgId, out resp)) { return new Tuple<bool, byte[]>(resp.IsRespOk, resp.res); } return new Tuple<bool, byte[]>(false, null); }