private void OnLoadReply(Msg_DL_LoadResult msg, PBChannel channel, int src, uint session) { KeyString key = KeyString.Wrap(msg.PrimaryKeys); ConcurrentDictionary <KeyString, LoadRequestInfo> dict; if (m_LoadRequests.TryGetValue(msg.MsgId, out dict)) { LoadRequestInfo info; if (dict.TryGetValue(key, out info)) { if (info.m_Request.SerialNo == msg.SerialNo) { if (null != info.m_Callback) { info.m_Callback(msg); } LoadRequestInfo delInfo; if (dict.TryRemove(key, out delInfo)) { m_LoadRequestPool.Recycle(delInfo); } } } } }
private void DSLoadHandler(Msg_LD_Load msg, PBChannel channel, int handle, uint seq) { try { DataCacheSystem.Instance.LoadActionQueue.QueueAction <Msg_LD_Load, PBChannel, int>(DataCacheSystem.Instance.Load, msg, channel, handle); } catch (Exception e) { var errorReply = new Msg_DL_LoadResult(); errorReply.MsgId = msg.MsgId; errorReply.PrimaryKeys.AddRange(msg.PrimaryKeys); errorReply.SerialNo = msg.SerialNo; errorReply.ErrorNo = Msg_DL_LoadResult.ErrorNoEnum.Exception; errorReply.ErrorInfo = e.Message; channel.Send(errorReply); LogSys.Log(LOG_TYPE.ERROR, "Load data failed. MsgId:{0}, Key:{1} Error:{2} Detail:{3}", msg.MsgId, msg.PrimaryKeys, e.Message, e.StackTrace); } }
internal static void Load(Msg_LD_Load msg, MyAction <Msg_DL_LoadResult> callback) { Msg_DL_LoadResult ret = new Msg_DL_LoadResult(); ret.MsgId = msg.MsgId; ret.PrimaryKeys.AddRange(msg.PrimaryKeys); ret.SerialNo = msg.SerialNo;; ret.ErrorNo = Msg_DL_LoadResult.ErrorNoEnum.Success; if (DataCacheConfig.IsPersistent) { try { for (int i = 0; i < msg.LoadRequests.Count; ++i) { Msg_LD_SingleLoadRequest req = msg.LoadRequests[i]; switch (req.LoadType) { case Msg_LD_SingleLoadRequest.LoadTypeEnum.LoadAll: { int start = req.Start; int count = req.Count; List <GeneralRecordData> datas = DataDML.LoadAll(req.MsgId, start, count); foreach (GeneralRecordData data in datas) { Msg_DL_SingleRowResult result = new Msg_DL_SingleRowResult(); result.MsgId = req.MsgId; result.PrimaryKeys.AddRange(data.PrimaryKeys); result.ForeignKeys.AddRange(data.ForeignKeys); result.DataVersion = data.DataVersion; result.Data = data.Data; ret.Results.Add(result); } } break; case Msg_LD_SingleLoadRequest.LoadTypeEnum.LoadSingle: { GeneralRecordData data = DataDML.LoadSingle(req.MsgId, req.Keys); Msg_DL_SingleRowResult result = new Msg_DL_SingleRowResult(); result.MsgId = req.MsgId; if (data != null) { result.PrimaryKeys.AddRange(data.PrimaryKeys); result.ForeignKeys.AddRange(data.ForeignKeys); result.DataVersion = data.DataVersion; result.Data = data.Data; } else { result.PrimaryKeys.AddRange(msg.PrimaryKeys); result.ForeignKeys.Clear(); result.DataVersion = -1; result.Data = null; ret.ErrorNo = Msg_DL_LoadResult.ErrorNoEnum.NotFound; } ret.Results.Add(result); } break; case Msg_LD_SingleLoadRequest.LoadTypeEnum.LoadMulti: { List <GeneralRecordData> dataList = DataDML.LoadMulti(req.MsgId, req.Keys); foreach (GeneralRecordData data in dataList) { Msg_DL_SingleRowResult result = new Msg_DL_SingleRowResult(); result.MsgId = req.MsgId; result.PrimaryKeys.AddRange(data.PrimaryKeys); result.ForeignKeys.AddRange(data.ForeignKeys); result.DataVersion = data.DataVersion; result.Data = data.Data; ret.Results.Add(result); } } break; } } } catch (Exception ex) { ret.ErrorNo = Msg_DL_LoadResult.ErrorNoEnum.PostError; ret.ErrorInfo = ex.Message; LogSys.Log(LOG_TYPE.ERROR, ConsoleColor.Red, "Load data from mysql ERROR. MsgId:{0}, Key:{1}\nErrorMessage:{2}\nStackTrace:{3}", msg.MsgId, msg.PrimaryKeys, ex.Message, ex.StackTrace); } finally { DataCacheSystem.Instance.QueueAction(callback, ret); } } else { ret.ErrorNo = Msg_DL_LoadResult.ErrorNoEnum.NotFound; ret.ErrorInfo = string.Empty; DataCacheSystem.Instance.QueueAction(callback, ret); } }
private void OnTick() { long curTime = TimeUtility.GetLocalMilliseconds(); if (m_LastTickTime != 0) { long elapsedTickTime = curTime - m_LastTickTime; if (elapsedTickTime > c_WarningTickTime) { LogSys.Log(LOG_TYPE.MONITOR, "DataCacheThread Tick:{0}", elapsedTickTime); } } m_LastTickTime = curTime; if (m_LastLogTime + 60000 < curTime) { m_LastLogTime = curTime; DebugPoolCount((string msg) => { LogSys.Log(LOG_TYPE.INFO, "DataCacheThread.DispatchActionQueue {0}", msg); }); DebugActionCount((string msg) => { LogSys.Log(LOG_TYPE.MONITOR, "DataCacheThread.DispatchActionQueue {0}", msg); }); LogSys.Log(LOG_TYPE.MONITOR, "DataCacheThread.ThreadActionQueue Current Action {0}", m_Thread.CurActionNum); LogSys.Log(LOG_TYPE.MONITOR, "DataCacheThread Load Request Count {0} Save Request Count {1}", CalcLoadRequestCount(), CalcSaveRequestCount()); } if (UserServerConfig.DataStoreAvailable == true) { if (m_LastOperateTickTime + c_OperateTickInterval < curTime) { m_LastOperateTickTime = curTime; //Load操作 foreach (var pair in m_LoadRequests) { int msgId = pair.Key; ConcurrentDictionary <KeyString, LoadRequestInfo> dict = pair.Value; foreach (var reqPair in dict) { KeyString primaryKey = reqPair.Key; LoadRequestInfo req = reqPair.Value; if (req.m_LastSendTime + UserServerConfig.DSRequestTimeout < curTime) { m_WaitDeletedLoadRequests.Add(primaryKey, req.m_Request.SerialNo); Msg_DL_LoadResult result = new Msg_DL_LoadResult(); result.MsgId = msgId; result.PrimaryKeys.AddRange(primaryKey.Keys); result.SerialNo = req.m_Request.SerialNo; result.ErrorNo = Msg_DL_LoadResult.ErrorNoEnum.TimeoutError; result.ErrorInfo = "Timeout Error"; if (null != req.m_Callback) { DispatchAction(req.m_Callback, result); } } } foreach (var delPair in m_WaitDeletedLoadRequests) { LoadRequestInfo info; if (dict.TryRemove(delPair.Key, out info)) { if (info.m_Request.SerialNo == delPair.Value) { m_LoadRequestPool.Recycle(info); } else { dict.TryAdd(delPair.Key, info); } } } m_WaitDeletedLoadRequests.Clear(); } //Save操作 foreach (var pair in m_SaveRequestQueues) { int msgId = pair.Key; ConcurrentDictionary <KeyString, ConcurrentQueue <SaveRequestInfo> > dict = pair.Value; foreach (var reqPair in dict) { KeyString primaryKey = reqPair.Key; ConcurrentQueue <SaveRequestInfo> saveReqQueue = reqPair.Value; SaveRequestInfo req; if (saveReqQueue.TryPeek(out req)) { if (req.m_LastSendTime + UserServerConfig.DSRequestTimeout < curTime) { //超时,重新发送 LogSys.Log(LOG_TYPE.ERROR, "DataCacheThread. SaveRequest timeout. MsgId:{0}, PrimaryKey:{1}, SerialNo:{2}", msgId, KeyString.Wrap(req.m_Request.PrimaryKeys), req.m_Request.SerialNo); m_DataStoreChannel.Send(req.m_Request); req.m_LastSendTime = curTime; } } if (dict.Count > c_MaxRecordPerMessage && saveReqQueue.Count == 0) { m_WaitDeleteSaveRequests.Add(primaryKey); } } foreach (KeyString key in m_WaitDeleteSaveRequests) { lock (m_SaveRequestQueuesLock) { ConcurrentQueue <SaveRequestInfo> queue; if (dict.TryGetValue(key, out queue)) { if (queue.Count == 0) { ConcurrentQueue <SaveRequestInfo> dummy; dict.TryRemove(key, out dummy); } } } } m_WaitDeleteSaveRequests.Clear(); } } if (m_LastDSConnectTime + c_DSConnectInterval < curTime) { m_LastDSConnectTime = curTime; if (m_CurrentStatus != ConnectStatus.Connected) { ConnectDataStore(); } } } }
//==========================通过QueueAction调用的方法=========================================== //注意!回调函数目前在缓存线程与db线程都可能调用,回调函数的实现需要是线程安全的(目前一般都是发消息,满足此条件)。 internal void Load(Msg_LD_Load msg, PBChannel channel, int handle) { //首先在缓存中查找数据,若未找到,则到DB中查找 bool isLoadCache = true; Msg_DL_LoadResult ret = new Msg_DL_LoadResult(); ret.MsgId = msg.MsgId; ret.PrimaryKeys.AddRange(msg.PrimaryKeys); ret.SerialNo = msg.SerialNo; ret.ErrorNo = 0; for (int i = 0; i < msg.LoadRequests.Count; ++i) { Msg_LD_SingleLoadRequest req = msg.LoadRequests[i]; KeyString loadKey = KeyString.Wrap(req.Keys); switch (req.LoadType) { case Msg_LD_SingleLoadRequest.LoadTypeEnum.LoadAll: { isLoadCache = false; } break; case Msg_LD_SingleLoadRequest.LoadTypeEnum.LoadSingle: { InnerCacheItem item = m_InnerCacheSystem.Find(req.MsgId, loadKey); if (item != null) { Msg_DL_SingleRowResult result = new Msg_DL_SingleRowResult(); result.MsgId = req.MsgId; result.PrimaryKeys.AddRange(req.Keys); result.DataVersion = 0; //TODO: 这个DataVersion有用吗? result.Data = item.DataMessage; ret.Results.Add(result); } else { isLoadCache = false; } } break; case Msg_LD_SingleLoadRequest.LoadTypeEnum.LoadMulti: { List <InnerCacheItem> itemList = m_InnerCacheSystem.FindByForeignKey(req.MsgId, loadKey); foreach (var item in itemList) { Msg_DL_SingleRowResult result = new Msg_DL_SingleRowResult(); result.MsgId = req.MsgId; result.PrimaryKeys.AddRange(req.Keys); result.DataVersion = 0; //TODO: 这个DataVersion有用吗? result.Data = item.DataMessage; ret.Results.Add(result); } } break; } } if (isLoadCache) { channel.Send(ret); LogSys.Log(LOG_TYPE.INFO, "Load data from cache. MsgId:{0}, Key:{1}", msg.MsgId, KeyString.Wrap(msg.PrimaryKeys).ToString()); } else { //查找DB交给DBLoad线程操作 DbThreadManager.Instance.LoadActionQueue.QueueAction(DataLoadImplement.Load, msg, (MyAction <Msg_DL_LoadResult>)((Msg_DL_LoadResult result) => { if (result.ErrorNo == Msg_DL_LoadResult.ErrorNoEnum.Success) { foreach (Msg_DL_SingleRowResult row in result.Results) { m_InnerCacheSystem.AddOrUpdate(row.MsgId, KeyString.Wrap(row.PrimaryKeys), KeyString.Wrap(row.ForeignKeys), row.Data); } } channel.Send(result); LogSys.Log(LOG_TYPE.INFO, "Load data from database. MsgId:{0}, Key:{1}", msg.MsgId, KeyString.Wrap(msg.PrimaryKeys).ToString()); })); } }