/// <summary> /// 参加指定标识的分布式事务,直到事务执行完成。一个分布式事务包含若干本地事务 /// </summary> /// <param name="identity">标识一个分布式事务</param> /// <returns></returns> public bool AttendTransaction(string identity) { DistTransInfo info = new DistTransInfo(); info.ClientIdentity = base.CurrentContext.Request.ClientIdentity; info.CurrentDTCState = DistTrans3PCState.CanCommit; info.LastStateTime = DateTime.Now; info.TransIdentity = identity; //DTResourceList.Add(info); DateTime dtcStart = DateTime.Now; //获取一个当前事务标识的协调器线程 DTController controller = DTController.CheckStartController(identity); CurrentDTCState = DistTrans3PCState.CanCommit; while (CurrentDTCState != DistTrans3PCState.Completed) { //获取资源服务器的事务状态,资源服务器可能自身或者因为网络情况出错 if (!SendDTCState(info, controller, identity)) { break; } } SendDTCState(info, controller, identity); DTController.RemoveController(identity); Console.WriteLine("DTC Current Use time:{0}(s)", DateTime.Now.Subtract(dtcStart).TotalSeconds); return(true); }
/// <summary> /// 3阶段分布式事务请求函数,执行完本地事务操作后,请求线程将继续工作,处理分布式提交的问题 /// </summary> /// <typeparam name="T">本地事务操作函数的返回类型</typeparam> /// <param name="client">分布式事务服务的代理客户端</param> /// <param name="dbHelper">数据访问对象</param> /// <param name="transFunction">事务操作函数</param> /// <returns>返回事务操作函数的结果</returns> public T DistTrans3PCRequest <T>(Proxy client, AdoHelper dbHelper, Func <AdoHelper, T> transFunction) { string transIdentity = this.TransIdentity; ServiceRequest request = new ServiceRequest(); request.ServiceName = "DTCService"; request.MethodName = "AttendTransaction"; request.Parameters = new object[] { transIdentity }; DateTime dtcReqTime = DateTime.Now; ResourceServerState = DistTrans3PCState.CanCommit; System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource(); var tcs = new TaskCompletionSource <T>(); //可以在外部开启事务,以方便出错,回滚事务,这里检查下是否开启了事务 if (dbHelper.TransactionCount <= 0) { dbHelper.BeginTransaction(); } DataType resultDataType = MessageConverter <T> .GetResponseDataType(); client.ErrorMessage += client_ErrorMessage; client.RequestService <bool, DistTrans3PCState, DistTrans3PCState>(request.ServiceUrl, resultDataType, r => { PrintLog("MSF DTC({0}) Controller Process Reuslt:{1},Receive time:{2}", transIdentity, r, DateTime.Now.ToString("HH:mm:ss.fff")); client.Close(); }, s => { var DTR_State = ProcessDistTrans3PCState <T>(client, dbHelper, transFunction, s, tcs, transIdentity); if (DTR_State == DistTrans3PCState.Completed) { PrintLog("MSF DTC({0}) 3PC Request Completed,use time:{1} seconds.", transIdentity, DateTime.Now.Subtract(dtcReqTime).TotalSeconds); } return(DTR_State); } ); try { tcs.Task.Wait(); return(tcs.Task.Result); } catch (Exception ex) { PrintLog("MSF DTC({0}) Task Error:{1}", transIdentity, ex.Message); TryRollback(dbHelper); } return(default(T)); }
//private static System.Collections.Concurrent.ConcurrentBag<DistTransInfo> DTResourceList = new System.Collections.Concurrent.ConcurrentBag<DistTransInfo>(); /// <summary> /// (资源服务器向协调器服务)注册事务操作 /// </summary> /// <param name="identity">事务标识,需要在一个分布式事务下的服务请求必须使用同一个事务标识</param> /// <returns></returns> public ServiceEventSource RegisterTransaction(string identity) { //事务计数器累加 System.Threading.Interlocked.Increment(ref TransactionResourceCount); return(new ServiceEventSource(new object(), 5, () => { //注册即向资源服务器发出 CanCommit请求 //base.CurrentContext.PublishData(DistTrans3PCState.CanCommit); CurrentDTCState = DistTrans3PCState.CanCommit; while (CurrentDTCState != DistTrans3PCState.Completed) { CurrentDTCState = base.CurrentContext.CallBackFunction <DistTrans3PCState, DistTrans3PCState>(CurrentDTCState); Console.WriteLine("Callback Message:{0}", CurrentDTCState); } })); }
private bool SendDTCState(DistTransInfo info, DTController controller, string identity) { string clientIdentity = string.Format("[{0}:{1}-{2}]", base.CurrentContext.Request.ClientIP, base.CurrentContext.Request.ClientPort, base.CurrentContext.Request.ClientIdentity); try { Console.WriteLine("DTC Service Callback {0} Message:{1}", clientIdentity, CurrentDTCState); info.CurrentDTCState = base.CurrentContext.CallBackFunction <DistTrans3PCState, DistTrans3PCState>(CurrentDTCState); info.LastStateTime = DateTime.Now; CurrentDTCState = controller.GetDTCState(info.CurrentDTCState); return(true); } catch (Exception ex) { Console.WriteLine("DTC Service Callback {0} Error:{1}", clientIdentity, ex.Message); return(false); } }
void client_ErrorMessage(object sender, MessageSubscriber.MessageEventArgs e) { ResourceServerState = DistTrans3PCState.CommunicationInterrupt; PrintLog("MSF DTC({0}) Service Proxy Error:{1}", this.TransIdentity, e.MessageText); }
/// <summary> /// 3阶段分布式事务请求函数,执行完本地事务操作后,请求线程将继续工作,处理分布式提交的问题 /// </summary> /// <typeparam name="T">本地事务操作函数的返回类型</typeparam> /// <param name="client">分布式事务服务的代理客户端</param> /// <param name="dbHelper">数据访问对象</param> /// <param name="transFunction">事务操作函数</param> /// <returns>返回事务操作函数的结果</returns> public T DistTrans3PCRequest <T>(Proxy client, AdoHelper dbHelper, Func <AdoHelper, T> transFunction) { string transIdentity = this.TransIdentity; ServiceRequest request = new ServiceRequest(); request.ServiceName = "DTCService"; request.MethodName = "AttendTransaction"; request.Parameters = new object[] { transIdentity }; DateTime dtcReqTime = DateTime.Now; ResourceServerState = DistTrans3PCState.CanCommit; System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource(); var tcs = new TaskCompletionSource <T>(); //可以在外部开启事务,以方便出错,回滚事务,这里检查下是否开启了事务 if (dbHelper.TransactionCount <= 0) { dbHelper.BeginTransaction(); } DataType resultDataType = MessageConverter <T> .GetResponseDataType(); client.ErrorMessage += client_ErrorMessage; client.RequestService <bool, DistTrans3PCState, DistTrans3PCState>(request.ServiceUrl, resultDataType, r => { PrintLog("MSF DTC({0}) Controller Process Reuslt:{1},Receive time:{2}", transIdentity, r, DateTime.Now.ToString("HH:mm:ss.fff")); client.Close(); }, s => { PrintLog("MSF DTC({0}) Resource at {1} receive DTC Controller state:{2}", transIdentity, DateTime.Now.ToString("HH:mm:ss.fff"), s); if (s == DistTrans3PCState.CanCommit) { try { T t = transFunction(dbHelper); ResourceServerState = DistTrans3PCState.Rep_Yes_1PC; tcs.SetResult(t); } catch (Exception ex) { PrintLog(ex.Message); ResourceServerState = DistTrans3PCState.Rep_No_1PC; tcs.SetException(ex); } //警告:如果自此之后,很长时间没有收到协调服务器的任何回复,本地应回滚事务 new Task(() => { DateTime currOptTime = DateTime.Now; PrintLog("MSF DTC({0}) 1PC,Child moniter task has started at time:{1}", transIdentity, currOptTime.ToString("HH:mm:ss.fff")); while (ResourceServerState != DistTrans3PCState.Completed) { System.Threading.Thread.Sleep(10); if (ResourceServerState != DistTrans3PCState.Rep_Yes_1PC && ResourceServerState != DistTrans3PCState.Rep_No_1PC) { //在1阶段,只要发现通信中断,就应该回滚事务 if (ResourceServerState == DistTrans3PCState.CommunicationInterrupt) { TryRollback(dbHelper); client.Close(); PrintLog("** MSF DTC({0}) 1PC,Child moniter task check Communication Interrupt ,Rollback Transaction,task break!", transIdentity); } else { PrintLog("MSF DTC({0}) 1PC,Child moniter task find DistTrans3PCState has changed,Now is {1},task break!", transIdentity, ResourceServerState); } break; } else { //在1阶段回复消息后,超过一分钟,资源服务器没有收到协调服务器的任何响应,回滚本地事务 if (DateTime.Now.Subtract(currOptTime).TotalSeconds > 60) { TryRollback(dbHelper); client.Close(); PrintLog("** MSF DTC({0}) 1PC,Child moniter task check Opreation timeout,Rollback Transaction,task break!", transIdentity); break; } } } }, TaskCreationOptions.None).Start(); return(ResourceServerState); } else if (s == DistTrans3PCState.PreCommit) { ResourceServerState = DistTrans3PCState.ACK_Yes_2PC; //警告:如果自此之后,如果成功确认资源服务器进入第二阶段,但是很长时间没有收到协调服务器的任何回复,本地应提交事务 new Task(() => { DateTime currOptTime = DateTime.Now; PrintLog("MSF DTC({0}) 2PC,Child moniter task has started at time:{1}", transIdentity, currOptTime.ToString("HH:mm:ss.fff")); while (ResourceServerState != DistTrans3PCState.Completed) { System.Threading.Thread.Sleep(10); if (ResourceServerState != DistTrans3PCState.ACK_Yes_2PC) { //在2阶段,如果在1秒内就检测到通信已经中断,事务控制器可能难以收到预提交确认信息,考虑回滚本地事务 if (ResourceServerState == DistTrans3PCState.CommunicationInterrupt) { if (DateTime.Now.Subtract(currOptTime).TotalMilliseconds < 1000) { TryRollback(dbHelper); PrintLog("** MSF DTC({0}) 2PC,Child moniter find Communication Interrupt ,task break!", transIdentity); } else { //否则,1秒后才发现连接已经断开,预提交确认信号大概率已经发送过去,不用再等,提交本地事务 TryCommit(dbHelper); PrintLog("MSF DTC({0}) 2PC,Child moniter find Communication Interrupt,but ACK_Yes_2PC send ok,tansaction Commit ,task break!", transIdentity); } //已经结束事务,关闭通信连接 client.Close(); } else { //如果通信未中断且已经是其它状态,退出当前子任务 PrintLog("MSF DTC({0}) 2PC,Child moniter task find DistTrans3PCState has changed,Now is {1},task break!", transIdentity, ResourceServerState); } break; } else { //在2阶段,通信未中断,超过30秒,资源服务器没有收到协调服务器的任何响应,提交本地事务 if (DateTime.Now.Subtract(currOptTime).TotalSeconds > 30) { TryCommit(dbHelper); client.Close(); PrintLog("** MSF DTC({0}) 2PC,Child moniter task check Opreation timeout,Commit Transaction,task break!", transIdentity); break; } } } }, TaskCreationOptions.None).Start(); return(ResourceServerState); } else if (s == DistTrans3PCState.Abort) { TryRollback(dbHelper); ResourceServerState = DistTrans3PCState.ACK_No_2PC; return(ResourceServerState); } else if (s == DistTrans3PCState.DoCommit) { if (TryCommit(dbHelper)) { ResourceServerState = DistTrans3PCState.Rep_Yes_3PC; } else { ResourceServerState = DistTrans3PCState.Rep_No_3PC; } return(ResourceServerState); } else { //其它参数,原样返回 ResourceServerState = s; if (s == DistTrans3PCState.Completed) { PrintLog("MSF DTC({0}) 3PC Request Completed,use time:{1} seconds.", transIdentity, DateTime.Now.Subtract(dtcReqTime).TotalSeconds); } return(s); } }); try { tcs.Task.Wait(); return(tcs.Task.Result); } catch (Exception ex) { PrintLog("MSF DTC({0}) Task Error:{1}", transIdentity, ex.Message); TryRollback(dbHelper); } return(default(T)); }
/// <summary> /// 获取分布式事务的状态,注意某个调用线程可能会被阻塞等待 /// </summary> /// <param name="resourceState">资源服务器响应的状态</param> /// <returns></returns> public DistTrans3PCState GetDTCState(DistTrans3PCState resourceState) { if (resourceState == DistTrans3PCState.Rep_No_1PC) { //在1阶段,只要有一个资源服务器响应为不成功,则协调器将发出 终止指令。 this.TransAbort = true; return(DistTrans3PCState.Abort); } else if (resourceState == DistTrans3PCState.Rep_Yes_1PC) { //当前线程增加一个事务准备成功的计数器 System.Threading.Interlocked.Increment(ref PrearedOKCount); int waiteTime = 0; int timeSpan = 10;//毫秒 while (PrearedOKCount < TransResourceCount) { //如果等待超时,则应该取消当前分布式事务 if (waiteTime >= MAX_WAIT_TIME) { this.TransAbort = true; PrintLog("MSF DTC{0} 1PC waite timeout ({1} ms),transaction Abort.", this.TransIdentity, MAX_WAIT_TIME); } if (this.TransAbort) { return(DistTrans3PCState.Abort); } System.Threading.Thread.Sleep(timeSpan); waiteTime += timeSpan; } //如果每个事务资源服务器执行都成功,进入第二阶段:预提交阶段 return(DistTrans3PCState.PreCommit); } else if (resourceState == DistTrans3PCState.ACK_No_2PC) { return(DistTrans3PCState.Completed); } else if (resourceState == DistTrans3PCState.ACK_Yes_2PC) { //如果收到资源服务器预备提交的回复,得等待所有资源服务器确认回复此信息,然后发出提交指令 //如果等待到超时,也没有等到预提交的全部回复,说明某个资源服务器或者网络出现问题,应该发出终止指令 //注意:这里的等待,应该比资源服务器等待提交指令的时间要短 //当前线程增加一个事务准备成功的计数器 System.Threading.Interlocked.Increment(ref PreCommitOKCount); int waiteTime = 0; int timeSpan = 10;//毫秒 while (PreCommitOKCount < TransResourceCount) { //如果等待超时(10秒),则应该取消当前分布式事务 if (waiteTime >= 10000) { this.TransAbort = true; PrintLog("MSF DTC({0}) 2PC waite timeout ({1} ms),transaction Abort.", this.TransIdentity, waiteTime); } if (this.TransAbort) { return(DistTrans3PCState.Abort); } System.Threading.Thread.Sleep(timeSpan); waiteTime += timeSpan; } //如果每个事务资源服务器都已经回复,进入第三阶段:提交阶段 return(DistTrans3PCState.DoCommit); } else if (resourceState == DistTrans3PCState.Rep_No_3PC) { return(DistTrans3PCState.Completed); } else if (resourceState == DistTrans3PCState.Rep_Yes_3PC) { return(DistTrans3PCState.Completed); } else { return(DistTrans3PCState.Completed); } }
private DistTrans3PCState ProcessDistTrans3PCState <T>(Proxy client, AdoHelper dbHelper, Func <AdoHelper, T> transFunction, DistTrans3PCState s, TaskCompletionSource <T> tcs, string transIdentity) { PrintLog("MSF DTC({0}) Resource at {1} receive DTC Controller state:{2}", transIdentity, DateTime.Now.ToString("HH:mm:ss.fff"), s); if (s == DistTrans3PCState.CanCommit) { try { T t = transFunction(dbHelper); ResourceServerState = DistTrans3PCState.Rep_Yes_1PC; tcs.SetResult(t); } catch (Exception ex) { PrintLog(ex.Message); ResourceServerState = DistTrans3PCState.Rep_No_1PC; tcs.SetException(ex); } //警告:如果自此之后,很长时间没有收到协调服务器的任何回复,本地应回滚事务 new Task(() => { DateTime currOptTime = DateTime.Now; PrintLog("MSF DTC({0}) 1PC,Child moniter task has started at time:{1}", transIdentity, currOptTime.ToString("HH:mm:ss.fff")); while (ResourceServerState != DistTrans3PCState.Completed) { System.Threading.Thread.Sleep(10); if (ResourceServerState != DistTrans3PCState.Rep_Yes_1PC && ResourceServerState != DistTrans3PCState.Rep_No_1PC) { //在1阶段,只要发现通信中断,就应该回滚事务 if (ResourceServerState == DistTrans3PCState.CommunicationInterrupt) { TryRollback(dbHelper); client.Close(); PrintLog("** MSF DTC({0}) 1PC,Child moniter task check Communication Interrupt ,Rollback Transaction,task break!", transIdentity); } else { PrintLog("MSF DTC({0}) 1PC,Child moniter task find DistTrans3PCState has changed,Now is {1},task break!", transIdentity, ResourceServerState); } break; } else { //在1阶段回复消息后,超过一分钟,资源服务器没有收到协调服务器的任何响应,回滚本地事务 if (DateTime.Now.Subtract(currOptTime).TotalSeconds > 60) { TryRollback(dbHelper); client.Close(); PrintLog("** MSF DTC({0}) 1PC,Child moniter task check Opreation timeout,Rollback Transaction,task break!", transIdentity); break; } } } }, TaskCreationOptions.None).Start(); return(ResourceServerState); } else if (s == DistTrans3PCState.PreCommit) { ResourceServerState = DistTrans3PCState.ACK_Yes_2PC; //警告:如果自此之后,如果成功确认资源服务器进入第二阶段,但是很长时间没有收到协调服务器的任何回复,本地应提交事务 new Task(() => { DateTime currOptTime = DateTime.Now; PrintLog("MSF DTC({0}) 2PC,Child moniter task has started at time:{1}", transIdentity, currOptTime.ToString("HH:mm:ss.fff")); while (ResourceServerState != DistTrans3PCState.Completed) { System.Threading.Thread.Sleep(10); if (ResourceServerState != DistTrans3PCState.ACK_Yes_2PC) { //在2阶段,如果在1秒内就检测到通信已经中断,事务控制器可能难以收到预提交确认信息,考虑回滚本地事务 if (ResourceServerState == DistTrans3PCState.CommunicationInterrupt) { if (DateTime.Now.Subtract(currOptTime).TotalMilliseconds < 1000) { TryRollback(dbHelper); PrintLog("** MSF DTC({0}) 2PC,Child moniter find Communication Interrupt ,task break!", transIdentity); } else { //否则,1秒后才发现连接已经断开,预提交确认信号大概率已经发送过去,不用再等,提交本地事务 TryCommit(dbHelper); PrintLog("MSF DTC({0}) 2PC,Child moniter find Communication Interrupt,but ACK_Yes_2PC send ok,tansaction Commit ,task break!", transIdentity); } //已经结束事务,关闭通信连接 client.Close(); } else { //如果通信未中断且已经是其它状态,退出当前子任务 PrintLog("MSF DTC({0}) 2PC,Child moniter task find DistTrans3PCState has changed,Now is {1},task break!", transIdentity, ResourceServerState); } break; } else { //在2阶段,通信未中断,超过30秒,资源服务器没有收到协调服务器的任何响应,提交本地事务 if (DateTime.Now.Subtract(currOptTime).TotalSeconds > 30) { TryCommit(dbHelper); client.Close(); PrintLog("** MSF DTC({0}) 2PC,Child moniter task check Opreation timeout,Commit Transaction,task break!", transIdentity); break; } } } }, TaskCreationOptions.None).Start(); return(ResourceServerState); } else if (s == DistTrans3PCState.Abort) { TryRollback(dbHelper); ResourceServerState = DistTrans3PCState.ACK_No_2PC; return(ResourceServerState); } else if (s == DistTrans3PCState.DoCommit) { if (TryCommit(dbHelper)) { ResourceServerState = DistTrans3PCState.Rep_Yes_3PC; } else { ResourceServerState = DistTrans3PCState.Rep_No_3PC; } return(ResourceServerState); } else { //其它参数,原样返回 ResourceServerState = s; return(s); } }