Esempio n. 1
0
        // 第二阶段:根据操作日志进行同步
        // 注:中途遇到异常(例如 Loader 抛出异常),可能会丢失 INSERT_BATCH 条以内的日志记录写入 operlog 表
        // parameters:
        //      strLastDate   处理中断或者结束时返回最后处理过的日期
        //      last_index  处理或中断返回时最后处理过的位置。以后继续处理的时候可以从这个偏移开始
        // return:
        //      -1  出错
        //      0   中断
        //      1   完成
        public static async Task <ReplicationResult> DoReplication(
            string strStartDate,
            string strEndDate,
            LogType logType,
            // string serverVersion,
            CancellationToken token)
        {
            string strLastDate = "";
            long   last_index  = -1; // -1 表示尚未处理

            // bool bUserChanged = false;
            ProcessInfo info = new ProcessInfo();

            // strStartDate 里面可能会包含 ":1-100" 这样的附加成分
            StringUtil.ParseTwoPart(strStartDate,
                                    ":",
                                    out string strLeft,
                                    out string strRight);
            strStartDate = strLeft;

            if (string.IsNullOrEmpty(strStartDate) == true)
            {
                return(new ReplicationResult
                {
                    Value = -1,
                    ErrorInfo = "DoReplication() 出错: strStartDate 参数值不应为空"
                });
            }

            LibraryChannel channel     = App.CurrentApp.GetChannel();
            var            old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromSeconds(10);

            try
            {
                int nRet = OperLogLoader.MakeLogFileNames(strStartDate,
                                                          strEndDate,
                                                          true, // 是否包含扩展名 ".log"
                                                          out List <string> dates,
                                                          out string strWarning,
                                                          out string strError);
                if (nRet == -1)
                {
                    return(new ReplicationResult
                    {
                        Value = -1,
                        ErrorInfo = strError
                    });
                }

                if (dates.Count > 0 && string.IsNullOrEmpty(strRight) == false)
                {
                    dates[0] = dates[0] + ":" + strRight;
                }


                using (BiblioCacheContext context = new BiblioCacheContext())
                {
                    context.Database.EnsureCreated();

                    ProgressEstimate estimate = new ProgressEstimate();

                    OperLogLoader loader = new OperLogLoader
                    {
                        Channel = channel,
                        Stop    = null, //  this.Progress;
                                        // loader.owner = this;
                        Estimate  = estimate,
                        Dates     = dates,
                        Level     = 0,
                        AutoCache = false,
                        CacheDir  = "",
                        LogType   = logType,
                        Filter    = "setReaderInfo,borrow,return,setSystemParameter,writeRes", // 借书还书时候都会修改读者记录
                        // ServerVersion = serverVersion
                    };

                    //TimeSpan old_timeout = channel.Timeout;
                    //channel.Timeout = new TimeSpan(0, 2, 0);   // 二分钟

                    // loader.Prompt += Loader_Prompt;
                    try
                    {
                        // int nRecCount = 0;

                        string strLastItemDate = "";
                        long   lLastItemIndex  = -1;
                        // TODO: 计算遍历耗费的时间。如果太短了,要想办法让调主知道这一点,放缓重新调用的节奏,以避免 CPU 和网络资源太高
                        foreach (OperLogItem item in loader)
                        {
                            token.ThrowIfCancellationRequested();

                            //if (stop != null)
                            //    stop.SetMessage("正在同步 " + item.Date + " " + item.Index.ToString() + " " + estimate.Text + "...");

                            if (string.IsNullOrEmpty(item.Xml) == true)
                            {
                                goto CONTINUE;
                            }

                            XmlDocument dom = new XmlDocument();
                            try
                            {
                                dom.LoadXml(item.Xml);
                            }
                            catch (Exception ex)
                            {
                                /*
                                 * if (this.HasLoaderPrompt())
                                 * {
                                 *  strError = logType.ToString() + "日志记录 " + item.Date + " " + item.Index.ToString() + " XML 装入 DOM 的时候发生错误: " + ex.Message;
                                 *  MessagePromptEventArgs e = new MessagePromptEventArgs
                                 *  {
                                 *      MessageText = strError + "\r\n\r\n是否跳过此条继续处理?\r\n\r\n(确定: 跳过;  取消: 停止全部操作)",
                                 *      IncludeOperText = true,
                                 *      // + "\r\n\r\n是否跳过此条继续处理?",
                                 *      Actions = "yes,cancel"
                                 *  };
                                 *  Loader_Prompt(channel, e);
                                 *  if (e.ResultAction == "cancel")
                                 *      throw new ChannelException(channel.ErrorCode, strError);
                                 *  else if (e.ResultAction == "yes")
                                 *      continue;
                                 *  else
                                 *  {
                                 *      // no 也是抛出异常。因为继续下一批代价太大
                                 *      throw new ChannelException(channel.ErrorCode, strError);
                                 *  }
                                 * }
                                 * else
                                 */
                                throw new ChannelException(channel.ErrorCode, strError);
                            }

                            string strOperation = DomUtil.GetElementText(dom.DocumentElement, "operation");
                            if (strOperation == "setReaderInfo")
                            {
                                var trace_result = TraceSetReaderInfo(
                                    dom,
                                    info);
                                if (trace_result.Value == -1)
                                {
                                    WpfClientInfo.WriteErrorLog("同步 " + item.Date + " " + item.Index.ToString() + " 时出错: " + trace_result.ErrorInfo);
                                }
                            }
                            else if (strOperation == "borrow" || strOperation == "return")
                            {
                                var trace_result = await TraceBorrowOrReturn(
                                    dom,
                                    info);

                                if (trace_result.Value == -1)
                                {
                                    WpfClientInfo.WriteErrorLog("同步 " + item.Date + " " + item.Index.ToString() + " 时出错: " + trace_result.ErrorInfo);
                                }
                            }
                            else if (strOperation == "setSystemParameter")
                            {
                                var trace_result = TraceSetSystemParameter(
                                    dom,
                                    info);
                                if (trace_result.Value == -1)
                                {
                                    WpfClientInfo.WriteErrorLog("同步 " + item.Date + " " + item.Index.ToString() + " 时出错: " + trace_result.ErrorInfo);
                                }
                            }
                            else if (strOperation == "writeRes")
                            {
                                var trace_result = TraceWriteRes(
                                    dom,
                                    info);
                                if (trace_result.Value == -1)
                                {
                                    WpfClientInfo.WriteErrorLog("同步 " + item.Date + " " + item.Index.ToString() + " 时出错: " + trace_result.ErrorInfo);
                                }
                            }
                            else
                            {
                                continue;
                            }

#if NO
                            if (nRet == -1)
                            {
                                strError = "同步 " + item.Date + " " + item.Index.ToString() + " 时出错: " + strError;

                                /*
                                 * if (this.HasLoaderPrompt())
                                 * {
                                 *  MessagePromptEventArgs e = new MessagePromptEventArgs
                                 *  {
                                 *      MessageText = strError + "\r\n\r\n是否跳过此条继续处理?\r\n\r\n(确定: 跳过;  取消: 停止全部操作)",
                                 *      IncludeOperText = true,
                                 *      // + "\r\n\r\n是否跳过此条继续处理?",
                                 *      Actions = "yes,cancel"
                                 *  };
                                 *  Loader_Prompt(channel, e);
                                 *  if (e.ResultAction == "cancel")
                                 *      throw new Exception(strError);
                                 *  else if (e.ResultAction == "yes")
                                 *      continue;
                                 *  else
                                 *  {
                                 *      // no 也是抛出异常。因为继续下一批代价太大
                                 *      throw new Exception(strError);
                                 *  }
                                 * }
                                 * else
                                 */
                                throw new ChannelException(channel.ErrorCode, strError);
                            }
#endif

                            // lProcessCount++;
CONTINUE:
                            // 便于循环外获得这些值
                            strLastItemDate = item.Date;
                            lLastItemIndex  = item.Index + 1;

                            // index = 0;  // 第一个日志文件后面的,都从头开始了
                        }
                        // 记忆
                        strLastDate = strLastItemDate;
                        last_index  = lLastItemIndex;
                    }
                    finally
                    {
                        // loader.Prompt -= Loader_Prompt;
                        channel.Timeout = old_timeout;
                    }
                }

                return(new ReplicationResult
                {
                    Value = last_index == -1 ? 0 : 1,
                    LastDate = strLastDate,
                    LastIndex = last_index,
                    ProcessInfo = info
                });
            }
            catch (ChannelException ex)
            {
                return(new ReplicationResult
                {
                    Value = -1,
                    ErrorInfo = ex.Message,
                    ProcessInfo = info
                });
            }
            catch (InterruptException ex)
            {
                // 2019/7/4
                return(new ReplicationResult
                {
                    Value = -1,
                    ErrorInfo = ex.Message,
                    ProcessInfo = info
                });
            }
            catch (Exception ex)
            {
                string strError = "DoReplication() exception: " + ExceptionUtil.GetDebugText(ex);
                return(new ReplicationResult
                {
                    Value = -1,
                    ErrorInfo = strError,
                    ProcessInfo = info
                });
            }
            finally
            {
                channel.Timeout = old_timeout;
                App.CurrentApp.ReturnChannel(channel);
            }
        }
Esempio n. 2
0
        // 同步
        // 注:中途遇到异常(例如 Loader 抛出异常),可能会丢失 INSERT_BATCH 条以内的日志记录写入 operlog 表
        // parameters:
        //      strLastDate   处理中断或者结束时返回最后处理过的日期
        //      last_index  处理或中断返回时最后处理过的位置。以后继续处理的时候可以从这个偏移开始
        // return:
        //      -1  出错
        //      0   中断
        //      1   完成
        public static ReplicationResult DoReplication(
            LibraryChannel channel,
            string strStartDate,
            string strEndDate,
            LogType logType,
            CancellationToken token)
        {
            string strLastDate = "";
            long   last_index  = -1; // -1 表示尚未处理

            // bool bUserChanged = false;

            // strStartDate 里面可能会包含 ":1-100" 这样的附加成分
            StringUtil.ParseTwoPart(strStartDate,
                                    ":",
                                    out string strLeft,
                                    out string strRight);
            strStartDate = strLeft;

            if (string.IsNullOrEmpty(strStartDate) == true)
            {
                return(new ReplicationResult
                {
                    Value = -1,
                    ErrorInfo = "DoReplication() 出错: strStartDate 参数值不应为空"
                });
            }

            try
            {
                List <string> dates = null;
                int           nRet  = OperLogLoader.MakeLogFileNames(strStartDate,
                                                                     strEndDate,
                                                                     true, // 是否包含扩展名 ".log"
                                                                     out dates,
                                                                     out string strWarning,
                                                                     out string strError);
                if (nRet == -1)
                {
                    return(new ReplicationResult
                    {
                        Value = -1,
                        ErrorInfo = strError
                    });
                }

                if (dates.Count > 0 && string.IsNullOrEmpty(strRight) == false)
                {
                    dates[0] = dates[0] + ":" + strRight;
                }

                channel.Timeout = new TimeSpan(0, 1, 0);   // 一分钟


                // using (SQLiteConnection connection = new SQLiteConnection(this._connectionString))
                {
                    ProgressEstimate estimate = new ProgressEstimate();

                    OperLogLoader loader = new OperLogLoader
                    {
                        Channel = channel,
                        Stop    = null, //  this.Progress;
                                        // loader.owner = this;
                        Estimate  = estimate,
                        Dates     = dates,
                        Level     = 2, // Program.MainForm.OperLogLevel;
                        AutoCache = false,
                        CacheDir  = "",
                        LogType   = logType,
                        Filter    = "setReaderInfo"
                    };

                    loader.Prompt += Loader_Prompt;
                    try
                    {
                        // int nRecCount = 0;

                        string strLastItemDate = "";

                        long lLastItemIndex = -1;
                        foreach (OperLogItem item in loader)
                        {
                            token.ThrowIfCancellationRequested();

                            //if (stop != null)
                            //    stop.SetMessage("正在同步 " + item.Date + " " + item.Index.ToString() + " " + estimate.Text + "...");

                            if (string.IsNullOrEmpty(item.Xml) == true)
                            {
                                goto CONTINUE;
                            }

                            XmlDocument dom = new XmlDocument();
                            try
                            {
                                dom.LoadXml(item.Xml);
                            }
                            catch (Exception ex)
                            {
#if NO
                                DialogResult result = System.Windows.Forms.DialogResult.No;
                                strError = logType.ToString() + "日志记录 " + item.Date + " " + item.Index.ToString() + " XML 装入 DOM 的时候发生错误: " + ex.Message;
                                string strText = strError;

                                this.Invoke((Action)(() =>
                                {
                                    result = MessageBox.Show(this,
                                                             strText + "\r\n\r\n是否跳过此条记录继续处理?",
                                                             "ReportForm",
                                                             MessageBoxButtons.YesNo,
                                                             MessageBoxIcon.Question,
                                                             MessageBoxDefaultButton.Button1);
                                }));

                                if (result == System.Windows.Forms.DialogResult.No)
                                {
                                    return(-1);
                                }

                                // 记入日志,继续处理
                                this.GetErrorInfoForm().WriteHtml(strError + "\r\n");
                                continue;
#endif

                                if (Prompt != null)
                                {
                                    strError = logType.ToString() + "日志记录 " + item.Date + " " + item.Index.ToString() + " XML 装入 DOM 的时候发生错误: " + ex.Message;
                                    MessagePromptEventArgs e = new MessagePromptEventArgs
                                    {
                                        MessageText     = strError + "\r\n\r\n是否跳过此条继续处理?\r\n\r\n(确定: 跳过;  取消: 停止全部操作)",
                                        IncludeOperText = true,
                                        // + "\r\n\r\n是否跳过此条继续处理?",
                                        Actions = "yes,cancel"
                                    };
                                    Prompt(channel, e);
                                    if (e.ResultAction == "cancel")
                                    {
                                        throw new ChannelException(channel.ErrorCode, strError);
                                    }
                                    else if (e.ResultAction == "yes")
                                    {
                                        continue;
                                    }
                                    else
                                    {
                                        // no 也是抛出异常。因为继续下一批代价太大
                                        throw new ChannelException(channel.ErrorCode, strError);
                                    }
                                }
                                else
                                {
                                    throw new ChannelException(channel.ErrorCode, strError);
                                }
                            }

                            string strOperation = DomUtil.GetElementText(dom.DocumentElement, "operation");
                            if (strOperation == "setReaderInfo")
                            {
                                nRet = TraceSetReaderInfo(
                                    dom,
                                    out strError);
                            }
                            else
                            {
                                continue;
                            }

                            if (nRet == -1)
                            {
                                strError = "同步 " + item.Date + " " + item.Index.ToString() + " 时出错: " + strError;

                                if (Prompt != null)
                                {
                                    MessagePromptEventArgs e = new MessagePromptEventArgs
                                    {
                                        MessageText     = strError + "\r\n\r\n是否跳过此条继续处理?\r\n\r\n(确定: 跳过;  取消: 停止全部操作)",
                                        IncludeOperText = true,
                                        // + "\r\n\r\n是否跳过此条继续处理?",
                                        Actions = "yes,cancel"
                                    };
                                    Prompt(channel, e);
                                    if (e.ResultAction == "cancel")
                                    {
                                        throw new Exception(strError);
                                    }
                                    else if (e.ResultAction == "yes")
                                    {
                                        continue;
                                    }
                                    else
                                    {
                                        // no 也是抛出异常。因为继续下一批代价太大
                                        throw new Exception(strError);
                                    }
                                }
                                else
                                {
                                    throw new ChannelException(channel.ErrorCode, strError);
                                }
                            }

                            // lProcessCount++;
CONTINUE:
                            // 便于循环外获得这些值
                            strLastItemDate = item.Date;
                            lLastItemIndex  = item.Index + 1;

                            // index = 0;  // 第一个日志文件后面的,都从头开始了
                        }
                        // 记忆
                        strLastDate = strLastItemDate;
                        last_index  = lLastItemIndex;
                    }
                    finally
                    {
                        loader.Prompt -= Loader_Prompt;
                    }
                }

                return(new ReplicationResult
                {
                    Value = last_index == -1 ? 0 : 1,
                    LastDate = strLastDate,
                    LastIndex = last_index
                });
            }
            catch (Exception ex)
            {
                string strError = "ReportForm DoReplication() exception: " + ExceptionUtil.GetDebugText(ex);
                return(new ReplicationResult {
                    Value = -1, ErrorInfo = strError
                });
            }
        }
Esempio n. 3
0
        // return:
        //      -1  出错
        //      0   中断
        //      1   完成
        int ProcessOperLogs(ServerReplicationStart breakpoint,
                            bool bContinueWhenError,
                            Delegate_saveBreakPoint func_saveBreakPoint,
                            string strStyle,
                            out string strError)
        {
            strError = "";

            DateTime now = DateTime.Now;

            string        strStartDate = breakpoint.Date; // +":" + breakpoint.Offset.ToString();
            string        strEndDate   = DateTimeUtil.DateTimeToString8(now);
            List <string> filenames    = null;
            string        strWarning   = "";
            // 根据日期范围,发生日志文件名
            // parameters:
            //      strStartDate    起始日期。8字符
            //      strEndDate  结束日期。8字符
            // return:
            //      -1  错误
            //      0   成功
            int nRet = OperLogLoader.MakeLogFileNames(strStartDate,
                                                      strEndDate,
                                                      true, // true,
                                                      out filenames,
                                                      out strWarning,
                                                      out strError);

            if (nRet == -1)
            {
                return(-1);
            }

            if (String.IsNullOrEmpty(strWarning) == false)
            {
                // 可能有超过当天日期的被舍弃
            }

#if NO
            if (filenames.Count > 0 && string.IsNullOrEmpty(strEndRange) == false)
            {
                filenames[filenames.Count - 1] = filenames[filenames.Count - 1] + ":" + strEndRange;
            }
            if (filenames.Count > 0 && string.IsNullOrEmpty(strStartRange) == false)
            {
                filenames[0] = filenames[0] + ":" + strStartRange;
            }
#endif
            if (filenames.Count > 0 && breakpoint.Index > 0)
            {
                filenames[0] = filenames[0] + ":" + breakpoint.Index.ToString() + "-";
            }

            string strTempFileName = "";
            strTempFileName = this.App.GetTempFileName("attach");

#if NO
            LibraryChannel channel = new LibraryChannel();
            channel.Timeout      = TimeSpan.FromSeconds(30);
            channel.Url          = this.m_strUrl;
            channel.BeforeLogin += new BeforeLoginEventHandle(Channel_BeforeLogin);
#endif
            LibraryChannel channel = this.GetChannel();

            _stop.BeginLoop();
            try
            {
                DateTime lastSaveTime = DateTime.Now;
                TimeSpan delta        = TimeSpan.FromMinutes(1);

                OperLogLoader loader = new OperLogLoader();
                loader.Channel = channel;
                loader.Stop    = this._stop;
                // loader.estimate = estimate;
                loader.Dates            = filenames;
                loader.Level            = 0; //  0 完整级别
                loader.ReplicationLevel = true;
                loader.AutoCache        = false;
                loader.CacheDir         = "";
                // loader.Filter = "borrow,return,setReaderInfo,setBiblioInfo,setEntity,setOrder,setIssue,setComment,amerce,passgate,getRes";
                loader.LogType = LogType.OperLog;

                foreach (OperLogItem item in loader)
                {
                    if (this.Stopped)
                    {
                        strError = "用户中断";
                        return(0);
                    }
                    string date = item.Date;

                    // 处理
                    // this.AppendResultText("--" + date + "\r\n");
                    this.SetProgressText(date + ":" + item.Index.ToString());

                    Stream attachment = null;
                    try
                    {
                        if (item.AttachmentLength != 0)
                        {
                            // return:
                            //      -1  出错
                            //      0   没有找到日志记录
                            //      >0  附件总长度
                            long lRet = loader.DownloadAttachment(item,
                                                                  strTempFileName,
                                                                  out strError);
                            if (lRet == -1 || lRet == 0)
                            {
                                strError = "做日志记录 " + item.Date + " " + (item.Index).ToString() + " 时,下载附件部分发生错误:" + strError;
                                this.AppendResultText("*** " + strError + "\r\n");

                                if (// this.RecoverLevel == RecoverLevel.Logic &&
                                    bContinueWhenError == false)
                                {
                                    return(-1);
                                }
                                goto CONTINUE;
                            }
                            attachment = File.Open(strTempFileName, FileMode.Open);
                        }

                        nRet = this.DoOperLogRecord(
                            this.RecoverLevel,
                            item.Xml,
                            attachment,
                            strStyle,
                            out strError);
                        if (nRet == -1)
                        {
                            strError = "做日志记录 " + item.Date + " " + (item.Index).ToString() + " 时发生错误:" + strError;
                            this.AppendResultText("*** " + strError + "\r\n");

                            // 2007/6/25
                            // 如果为纯逻辑恢复(并且 bContinueWhenError 为 false),遇到错误就停下来。这便于进行测试。
                            // 若不想停下来,可以选择“逻辑+快照”型,或者设置 bContinueWhenError 为 true
                            if (// this.RecoverLevel == RecoverLevel.Logic &&
                                bContinueWhenError == false)
                            {
                                return(-1);
                            }
                        }
                    }
                    finally
                    {
                        if (attachment != null)
                        {
                            attachment.Close();
                            attachment = null;
                        }
                    }

CONTINUE:
                    breakpoint.Date  = date;
                    breakpoint.Index = item.Index + 1;

                    // 中途记忆断点
                    if (DateTime.Now - lastSaveTime >= delta)
                    {
                        if (func_saveBreakPoint != null)
                        {
                            func_saveBreakPoint(breakpoint);
                        }
                        lastSaveTime = DateTime.Now;
                    }
                }

                return(1);
            }
            catch (InterruptException)
            {
                strError = "用户中断";
                return(0);
            }
            catch (ChannelException ex)
            {
                strError = "处理过程出错: " + ex.Message;
                return(-1);
            }
            catch (Exception ex)
            {
                strError = "ProcessOperLogs() 出现异常: " + ExceptionUtil.GetDebugText(ex);
                return(-1);
            }
            finally
            {
                if (File.Exists(strTempFileName))
                {
                    File.Delete(strTempFileName);
                }

                _stop.EndLoop();
#if NO
                channel.BeforeLogin -= new BeforeLoginEventHandle(Channel_BeforeLogin);
                channel.Close();
#endif
                this.ReturnChannel(channel);
            }
        }