Inheritance: global::ProtoBuf.IExtensible
 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);
        }
    }
 internal void DSPLoadUserCallback(Msg_DL_LoadResult ret, string accountId, string nickname)
 {
     AccountInfo accountInfo = m_AccountSystem.FindAccountById(accountId);
     if (accountInfo == null) {
         return;
     }
     ulong userGuid = 0;// accountInfo.UserGuid;
     if (Msg_DL_LoadResult.ErrorNoEnum.Success == ret.ErrorNo) {
         TableUserInfo dataUser = null;
         foreach (var result in ret.Results) {
             object _msg;
             if (DbDataSerializer.Decode(result.Data, DataEnum2Type.Query(result.MsgId), out _msg)) {
                 DataEnum msgEnum = (DataEnum)result.MsgId;
                 switch (msgEnum) {
                     case DataEnum.TableUserInfo:
                         dataUser = _msg as TableUserInfo;
                         break;
                     default:
                         LogSys.Log(LOG_TYPE.ERROR, ConsoleColor.Red, "Decode user data ERROR. Wrong message id. UserGuid:{0}, WrongId:{1}", userGuid, msgEnum);
                         break;
                 }
             }
         }
         #region 由数据库数据构建UserInfo
         UserInfo ui = NewUserInfo();
         //基础数据
         ui.FromProto(dataUser);
         ui.SetMoneyForDB(dataUser.Money);
         ui.SetGoldForDB(dataUser.Gold);
         #endregion
         ui.NodeName = accountInfo.NodeName;
         this.DoUserLogin(ui);
         NodeMessage replyMsg = new NodeMessage(LobbyMessageDefine.RoleEnterResult, ui.AccountId, ui.Guid);
         GameFrameworkMessage.RoleEnterResult protoData = CreateRoleEnterResultMsg(ui);
         protoData.Result = RoleEnterResult.RoleEnterResultEnum.Success;
         replyMsg.m_ProtoData = protoData;
         NodeMessageDispatcher.SendNodeMessage(accountInfo.NodeName, replyMsg);
     } else if (Msg_DL_LoadResult.ErrorNoEnum.NotFound == ret.ErrorNo) {
         CreateRole(accountId, nickname, 1);
     } else {
         NodeMessage replyMsg = new NodeMessage(LobbyMessageDefine.RoleEnterResult, accountInfo.AccountId, userGuid);
         GameFrameworkMessage.RoleEnterResult protoData = new GameFrameworkMessage.RoleEnterResult();
         protoData.Result = RoleEnterResult.RoleEnterResultEnum.UnknownError;
         replyMsg.m_ProtoData = protoData;
         NodeMessageDispatcher.SendNodeMessage(accountInfo.NodeName, replyMsg);
     }
     LogSys.Log(LOG_TYPE.INFO, "UserProcessScheduler-OnRoleEnter-EndLoadUser. AccountId:{0}, UserGuid:{1}, Result:{2}",
       accountId, userGuid, ret.ErrorNo);
 }
 //==========================通过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());
         }));
     }
 }
 internal void DSPLoadAccountCallback(string accountId, Msg_DL_LoadResult ret)
 {
     AccountInfo accountInfo = m_AccountSystem.FindAccountById(accountId);
     if (accountInfo == null) {
         return;
     }
     NodeMessage replyMsg = new NodeMessage(LobbyMessageDefine.AccountLoginResult, accountId);
     GameFrameworkMessage.AccountLoginResult protoMsg = new GameFrameworkMessage.AccountLoginResult();
     protoMsg.m_AccountId = accountId;
     protoMsg.m_Result = AccountLoginResult.AccountLoginResultEnum.Error;
     try {
         if (ret.ErrorNo == Msg_DL_LoadResult.ErrorNoEnum.Success) {
             foreach (var result in ret.Results) {
                 object _msg;
                 if (DbDataSerializer.Decode(result.Data, DataEnum2Type.Query(result.MsgId), out _msg)) {
                     DataEnum msgEnum = (DataEnum)result.MsgId;
                     switch (msgEnum) {
                         case DataEnum.TableAccount:
                             accountInfo.TableAccount.FromProto(_msg as TableAccount);
                             break;
                         default:
                             LogSys.Log(LOG_TYPE.ERROR, ConsoleColor.Red, "Decode account data ERROR. Wrong message id. Account:{0}, WrongId:{1}", result.PrimaryKeys[0], msgEnum);
                             break;
                     }
                 }
             }
             if (accountInfo.TableAccount.IsBanned) {
                 //账号被封停
                 protoMsg.m_Result = AccountLoginResult.AccountLoginResultEnum.Banned;
             } else {
                 accountInfo.CurrentState = AccountState.Online;
                 accountInfo.LastLoginTime = TimeUtility.CurTimestamp;
                 m_AccountSystem.AddAccountById(accountId, accountInfo);
                 LogSys.Log(LOG_TYPE.INFO, ConsoleColor.Green, "LoginStep_4a: Account login SUCCESS . AccountId:{0}, LogicServerId:{1}, AccountId:{2}", accountId, 0, accountId);
                 protoMsg.m_Result = AccountLoginResult.AccountLoginResultEnum.Success;
                 protoMsg.m_UserGuid = accountInfo.UserGuid;
             }
         } else if (ret.ErrorNo == Msg_DL_LoadResult.ErrorNoEnum.NotFound) {
             //账号首次进入游戏
             LogSys.Log(LOG_TYPE.INFO, ConsoleColor.Green, "LoginStep_4b: Load account NotFound . AccountId:{0}, LogicServerId:{1}, AccountId:{2}", accountId, 0, accountId);
             accountInfo.CurrentState = AccountState.Online;
             accountInfo.TableAccount.AccountId = accountId;
             accountInfo.TableAccount.IsBanned = false;
             m_AccountSystem.AddAccountById(accountId, accountInfo);
             protoMsg.m_Result = AccountLoginResult.AccountLoginResultEnum.FirstLogin;
             protoMsg.m_UserGuid = accountInfo.UserGuid;
             //norm log
             accountInfo.LastLoginTime = TimeUtility.CurTimestamp;
         } else {
             //数据加载失败
             LogSys.Log(LOG_TYPE.INFO, ConsoleColor.Yellow, "LoginStep_4c: Load account FAILED . AccountId:{0}, LogicServerId:{1}, AccountId:{2}", accountId, 0, accountId);
         }
     } catch (Exception ex) {
         LogSys.Log(LOG_TYPE.INFO, ConsoleColor.Red, "ERROR LoginStep_4d. AccountId:{0}, LogicServerId:{1}, AccountId:{2}\nERROR Message:{3}\nStackTrace:{4}",
                     accountId, 0, accountId, ex.Message, ex.StackTrace);
     } finally {
         if (protoMsg.m_Result != AccountLoginResult.AccountLoginResultEnum.Success && protoMsg.m_Result != AccountLoginResult.AccountLoginResultEnum.FirstLogin) {
             m_AccountSystem.RemoveAccountById(accountId);
         }
         replyMsg.m_ProtoData = protoMsg;
         NodeMessageDispatcher.SendNodeMessage(accountInfo.NodeName, replyMsg);
     }
 }