Ejemplo n.º 1
0
        void document_SetProgress(object sender, SetProgressEventArgs e)
        {
            Application.DoEvents();

            if (e.Value == -1)
            {
                this.estimate.SetRange(e.Start, e.End);

                this.stop.SetProgressRange(e.Start, e.End);

                this.progressBar_records.Minimum = (int)e.Start;
                this.progressBar_records.Maximum = (int)e.End;
            }
            else
            {
                if ((this.m_lCount++ % 10) == 1)
                {
                    this.stop.SetMessage("剩余时间 " + ProgressEstimate.Format(this.estimate.Estimate(e.Value)) + " 已经过时间 " + ProgressEstimate.Format(this.estimate.delta_passed));
                }

                this.stop.SetProgressValue(e.Value);
                // this.stop.SetMessage(e.Value.ToString() + " - " + (((double)e.Value / (double)e.End) * 100).ToString() + "%");

                this.progressBar_records.Value = (int)e.Value;
            }
        }
Ejemplo n.º 2
0
        public IEnumerator GetEnumerator()
        {
            string strError       = "";
            string strRange       = "0-9999999999";
            long   lTotalCount    = 0;  // 总命中数
            long   lExportCount   = 0;
            string strTimeMessage = "";

            DigitalPlatform.Stop stop = this.Stop;

            StopStyle old_style = StopStyle.None;

            if (stop != null)
            {
                old_style    = stop.Style;
                stop.Style   = StopStyle.EnableHalfStop; // API的间隙才让中断。避免获取结果集的中途,因为中断而导致 Session 失效,结果集丢失,进而无法 Retry 获取
                stop.OnStop += stop_OnStop;
            }
            ProgressEstimate estimate = new ProgressEstimate();

            try
            {
                int i_path = 0;
                foreach (string path in this.Paths)
                {
                    ResPath respath = new ResPath(path);

                    string strQueryXml = "<target list='" + respath.Path
                                         + ":" + "__id'><item><word>" + strRange + "</word><match>exact</match><relation>range</relation><dataType>number</dataType><maxCount>-1</maxCount></item><lang>chi</lang></target>";

                    cur_channel = Channels.CreateTempChannel(respath.Url);
                    Debug.Assert(cur_channel != null, "Channels.GetChannel() 异常");

                    try
                    {
                        long lRet = cur_channel.DoSearch(strQueryXml,
                                                         "default",
                                                         out strError);
                        if (lRet == -1)
                        {
                            strError = "检索数据库 '" + respath.Path + "' 时出错: " + strError;
                            throw new Exception(strError);
                        }

                        if (lRet == 0)
                        {
                            strError = "数据库 '" + respath.Path + "' 中没有任何数据记录";
                            continue;
                        }

                        lTotalCount += lRet;    // 总命中数

                        estimate.SetRange(0, lTotalCount);
                        if (i_path == 0)
                        {
                            estimate.StartEstimate();
                        }

                        if (stop != null)
                        {
                            stop.SetProgressRange(0, lTotalCount);
                        }

                        SearchResultLoader loader = new SearchResultLoader(cur_channel,
                                                                           stop,
                                                                           this.ResultSetName,
                                                                           this.FormatList,
                                                                           this.Lang);
                        loader.BatchSize = this.BatchSize;

                        foreach (KernelRecord record in loader)
                        {
                            if (stop != null)
                            {
                                stop.SetProgressValue(lExportCount + 1);
                            }
                            lExportCount++;

                            yield return(record);
                        }

                        strTimeMessage = "总共耗费时间: " + estimate.GetTotalTime().ToString();
                    }
                    finally
                    {
                        cur_channel.Close();
                        cur_channel = null;
                    }
                    // MessageBox.Show(this, "位于服务器 '" + respath.Url + "' 上的数据库 '" + respath.Path + "' 内共有记录 " + lTotalCount.ToString() + " 条,本次导出 " + lExportCount.ToString() + " 条。" + strTimeMessage);

                    i_path++;
                }
            }
            finally
            {
                if (stop != null)
                {
                    stop.Style   = old_style;
                    stop.OnStop -= stop_OnStop;
                }
            }
        }
Ejemplo n.º 3
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
                });
            }
        }
Ejemplo n.º 4
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);
            }
        }
Ejemplo n.º 5
0
        // 对每个日志文件,每个日志记录进行循环
        // return:
        //      0   普通返回
        //      1   要全部中断
        int DoTask1Loop(out string strError)
        {
            strError = "";
            int nRet = 0;
            // long lRet = 0;

            List <string> LogFileNames = null;

            // TODO: 是否需要检查起止日期是否为空值?空值是警告还是就当作今天?

            string strStartDate = DateTimeUtil.DateTimeToString8(this.dateControl_start.Value);
            string strEndDate   = DateTimeUtil.DateTimeToString8(this.dateControl_end.Value);

            string strWarning = "";

            // 根据日期范围,发生日志文件名
            // parameters:
            //      strStartDate    起始日期。8字符
            //      strEndDate  结束日期。8字符
            // return:
            //      -1  错误
            //      0   成功
            nRet = MakeLogFileNames(strStartDate,
                                    strEndDate,
                                    true,
                                    out LogFileNames,
                                    out strWarning,
                                    out strError);
            if (nRet == -1)
            {
                return(-1);
            }

            if (String.IsNullOrEmpty(strWarning) == false)
            {
                MessageBox.Show(this, strWarning);
            }

#if NO
            string strStyle = "";
            if (this.MainForm.AutoCacheOperlogFile == true)
            {
                strStyle = "autocache";
            }
#endif

            ProgressEstimate estimate = new ProgressEstimate();

#if NO
            nRet = OperLogForm.ProcessFiles(this,
                                            stop,
                                            estimate,
                                            Channel,
                                            LogFileNames,
                                            this.MainForm.OperLogLevel,
                                            strStyle,
                                            this.MainForm.OperLogCacheDir,
                                            null,         // param,
                                            procDoRecord, // DoRecord,
                                            out strError);
            if (nRet == -1)
            {
                return(-1);
            }
#endif

            OperLogLoader loader = new OperLogLoader();
            loader.Channel   = this.Channel;
            loader.Stop      = this.Stop;
            loader.owner     = this;
            loader.estimate  = estimate;
            loader.FileNames = LogFileNames;
            loader.nLevel    = this.MainForm.OperLogLevel;
            loader.AutoCache = false;
            loader.CacheDir  = "";


            List <OperLogLine> lines = new List <OperLogLine>();

            foreach (OperLogItem item in loader)
            {
                string strXml = item.Xml;

                if (string.IsNullOrEmpty(strXml) == true)
                {
                    continue;
                }

                {
                    XmlDocument dom = new XmlDocument();
                    try
                    {
                        dom.LoadXml(strXml);
                    }
                    catch (Exception ex)
                    {
                        strError = "Load Xml to DOM error: " + ex.Message;
                        return(-1);
                    }

                    string strOperation = DomUtil.GetElementText(dom.DocumentElement, "operation");
                    if (strOperation != "borrow" && strOperation != "return")
                    {
                        continue;
                    }

                    string strAction   = DomUtil.GetElementText(dom.DocumentElement, "action");
                    string strOperator = DomUtil.GetElementText(dom.DocumentElement, "operator");

#if NO
                    XmlNode nodeItem   = null;
                    string  strItemXml = DomUtil.GetElementText(dom.DocumentElement,
                                                                "itemRecord", out nodeItem);
                    string strItemRecPath = "";
                    if (nodeItem != null)
                    {
                        strItemRecPath = DomUtil.GetAttr(nodeItem, "recPath");
                    }

                    // 册记录相关的书目记录路径,这个后面统一提取,就不用日志记录中的数据了
#endif
                    XmlNode nodeReader   = null;
                    string  strReaderXml = DomUtil.GetElementText(dom.DocumentElement,
                                                                  "readerRecord", out nodeReader);
                    string strReaderRecPath = DomUtil.GetAttr(nodeReader, "recPath");
                    string strReaderDbName  = Global.GetDbName(strReaderRecPath);
                    // TODO: 根据读者库名获得馆代码
                    string strLibraryCode = "";

                    string strItemBarcode = DomUtil.GetElementText(dom.DocumentElement,
                                                                   "itemBarcode");
                    string strReaderBarcode = DomUtil.GetElementText(dom.DocumentElement,
                                                                     "readerBarcode");
                    string strOperTime = DomUtil.GetElementText(dom.DocumentElement,
                                                                "operTime");

                    OperLogLine line = new OperLogLine();
                    line.ItemBarcode = strItemBarcode;
                    // 馆藏地点需要另行获得
                    line.ReaderBarcode = strReaderBarcode;
                    line.OperTime      = strOperTime;
                    line.LibraryCode   = strLibraryCode;

                    lines.Add(line);
                }


                if (lines.Count > 300)
                {
                    // 写入数据库一次

                    lines.Clear();
                }
            }

            if (lines.Count > 0)
            {
                // 写入数据库一次
            }

            return(nRet);
        }
Ejemplo n.º 6
0
        public IEnumerator GetEnumerator()
        {
            string strError = "";
            int    nRet     = 0;

            long lRet = 0;

            if (this.Date.Length != 8)
            {
                throw new ArgumentException("FileName 成员值的长度应该是 8 字符");
            }

            if ((this.LogType & LogType.AccessLog) != 0 &&
                (this.LogType & LogType.OperLog) != 0)
            {
                throw new ArgumentException("OperLogItemLoader 的 LogType 只能使用一种类型");
            }

            if (this.Stop != null && this.Estimate != null)
            {
                this.Stop.SetMessage("正在装入日志文件 " + this.Date + " 中的记录。"
                                     + "剩余时间 " + ProgressEstimate.Format(Estimate.Estimate(lProgressValue)) + " 已经过时间 " + ProgressEstimate.Format(Estimate.delta_passed));
            }

            string strXml = "";
            long   lAttachmentTotalLength = 0;

            byte[] attachment_data = null;

            long lFileSize = 0;

            if (lServerFileSize == -1)
            {
                long _lServerFileSize = 0;

                string strStyle = "level-" + Level.ToString();
                if ((this.LogType & LogType.AccessLog) != 0)
                {
                    strStyle += ",accessLog";
                }

                // 获得服务器端日志文件尺寸
                lRet = this.Channel.GetOperLog(
                    this.Stop,
                    this.Date,
                    -1, // lIndex,
                    -1, // lHint,
                    strStyle,
                    "", // strFilter
                    out strXml,
                    out _lServerFileSize,
                    0,  // lAttachmentFragmentStart,
                    0,  // nAttachmentFramengLength,
                    out attachment_data,
                    out lAttachmentTotalLength,
                    out strError);
                // 2015/11/25
                if (lRet == -1)
                {
                    throw new ChannelException(this.Channel.ErrorCode, strError);
                }

                this.lServerFileSize = _lServerFileSize;

                if (lRet == 0)
                {
                    yield break;
                }
                // 2015/11/25
                if (_lServerFileSize == -1)
                {
                    yield break;    // 此类型的日志尚未启用
                }
            }

            Stream stream           = null;
            bool   bCacheFileExist  = false;
            bool   bRemoveCacheFile = false; // 是否要自动删除未全部完成的本地缓存文件

            bool bAutoCache = this.AutoCache;

            if (bAutoCache == true)
            {
                string strFileName = this.Date;
                if ((this.LogType & LogType.AccessLog) != 0)
                {
                    strFileName = this.Date + ".a";
                }

                nRet = PrepareCacheFile(
                    this.CacheDir,
                    strFileName,    // this.FileName,
                    lServerFileSize,
                    out bCacheFileExist,
                    out stream,
                    out strError);
                if (nRet == -1)
                {
                    throw new Exception(strError);
                }

                if (bCacheFileExist == false && stream != null)
                {
                    bRemoveCacheFile = true;
                }
            }

            try
            {
                if (bCacheFileExist == true)
                {
                    lFileSize = stream.Length;
                }
                else
                {
                    lFileSize = lServerFileSize;
                }

                // stop.SetProgressRange(0, lTotalSize);

                if (String.IsNullOrEmpty(Range) == true)
                {
                    Range = "0-" + (long.MaxValue - 1).ToString();    // "0-9999999999";
                }
                RangeList rl = new RangeList(Range);

                for (int i = 0; i < rl.Count; i++)
                {
                    RangeItem ri = (RangeItem)rl[i];

                    // 让 100- 这样的 range 可以使用
                    if (ri.lLength == -1)
                    {
                        ri.lLength = long.MaxValue - ri.lStart;
                    }

                    OperLogInfo[] records       = null;
                    long          lStartRecords = 0;

                    long lHint     = -1;
                    long lHintNext = -1;
                    for (long lIndex = ri.lStart; lIndex < ri.lStart + ri.lLength; lIndex++)
                    {
                        // Application.DoEvents();

                        if (this.Stop != null && this.Stop.State != 0)
                        {
                            strError = "用户中断";
                            throw new InterruptException(strError);
                            // yield break; ?
                        }

                        if (lIndex == ri.lStart)
                        {
                            lHint = -1;
                        }
                        else
                        {
                            lHint = lHintNext;
                        }

                        if (bCacheFileExist == true)
                        {
                            if (lHint == -1)
                            {
                                // return:
                                //      -1  error
                                //      0   成功
                                //      1   到达文件末尾或者超出
                                nRet = LocationRecord(stream,
                                                      lIndex,
                                                      out strError);
                                if (nRet == -1)
                                {
                                    throw new Exception(strError);
                                }
                            }
                            else
                            {
                                // 根据暗示找到
                                if (lHint == stream.Length)
                                {
                                    break;
                                }

                                if (lHint > stream.Length)
                                {
                                    strError = "lHint参数值不正确";
                                    throw new Exception(strError);
                                }
                                if (stream.Position != lHint)
                                {
                                    stream.Seek(lHint, SeekOrigin.Begin);
                                }
                            }

                            nRet = ReadCachedEnventLog(
                                stream,
                                out strXml,
                                out lAttachmentTotalLength,
                                out strError);
                            if (nRet == -1)
                            {
                                throw new Exception(strError);
                            }
                            lHintNext = stream.Position;
                        }
                        else
                        {
                            if (records == null || lIndex /*- ri.lStart*/ >= lStartRecords + records.Length)
                            {
                                int nCount = -1;
                                if (ri.lLength >= Int32.MaxValue)
                                {
                                    nCount = -1;    // 500;   // -1;
                                }
                                else
                                {
                                    nCount = (int)ri.lLength;   // Math.Min(500, (int)ri.lLength);
                                }
                                string strStyle = "level-" + Level.ToString();
                                if ((this.LogType & LogType.AccessLog) != 0)
                                {
                                    strStyle += ",accessLog";
                                }

                                // 2017/10/9
                                if (this.ReplicationLevel == true)
                                {
                                    strStyle += ",supervisor";  // 注:当前账户中还应该包含 replicatoin 权限才能真正获得日志记录中的密码字段
                                }
                                if (string.IsNullOrEmpty(this.ServerVersion) == false &&
                                    StringUtil.CompareVersion(this.ServerVersion, "3.17") >= 0)
                                {
                                    strStyle += ",wait";
                                }

REDO:
                                // 获得日志
                                // return:
                                //      -1  error
                                //      0   file not found
                                //      1   succeed
                                //      2   超过范围,本次调用无效
                                lRet = this.Channel.GetOperLogs(
                                    this.Stop,
                                    this.Date + ".log",
                                    lIndex,
                                    lHint,
                                    nCount,
                                    strStyle,
                                    this.Filter, // strFilter
                                    out records,
                                    out strError);
                                if (lRet == -1)
                                {
#if NO
                                    DialogResult result = MessageBox.Show(owner,
                                                                          "获取日志信息 (" + this.FileName + " " + lIndex.ToString() + ") 的操作发生错误: " + strError + "\r\n\r\n是否重试操作?\r\n\r\n(是: 重试;  否: 跳过本次操作,继续后面的操作; 放弃: 停止全部操作)",
                                                                          "OperLogItemLoader",
                                                                          MessageBoxButtons.YesNoCancel,
                                                                          MessageBoxIcon.Question,
                                                                          MessageBoxDefaultButton.Button1);
                                    if (result == DialogResult.Yes)
                                    {
                                        goto REDO;
                                    }
                                    if (result == DialogResult.Cancel)
                                    {
                                        throw new Exception(strError);
                                    }
                                    else
                                    {
                                        // TODO: 是否要在listview中装入一条表示出错的行?
                                        lHintNext = -1;
                                        continue;
                                    }
#endif
                                    if (this.Prompt != null)
                                    {
                                        MessagePromptEventArgs e = new MessagePromptEventArgs();
                                        e.MessageText = "获取 " + this._logType.ToString() + " 日志信息 (" + this.Date + " " + lIndex.ToString() + ") 的操作发生错误: " + strError;
                                        e.Actions     = "yes,no,cancel";
                                        this.Prompt(this, e);
                                        if (e.ResultAction == "cancel")
                                        {
                                            throw new InterruptException(strError);
                                        }
                                        else if (e.ResultAction == "yes")
                                        {
                                            if (this.Stop != null)
                                            {
                                                this.Stop.Continue();
                                            }
                                            goto REDO;
                                        }
                                        else
                                        {
                                            lHintNext = -1;
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        throw new ChannelException(this.Channel.ErrorCode, strError);
                                    }
                                }
                                if (lRet == 0)
                                {
                                    yield break;
                                }

                                if (lRet == 2)
                                {
                                    break;
                                }

                                // records数组表示的起点位置
                                lStartRecords = lIndex /* - ri.lStart*/;
                            }

                            OperLogInfo info = records[lIndex - lStartRecords];

                            strXml    = info.Xml;
                            lHintNext = info.HintNext;
                            lAttachmentTotalLength = info.AttachmentLength;

                            // 写入本地缓存的日志文件
                            if (stream != null)
                            {
                                try
                                {
                                    WriteCachedEnventLog(
                                        stream,
                                        strXml,
                                        lAttachmentTotalLength);
                                }
                                catch (Exception ex)
                                {
                                    strError = "写入本地缓存文件的时候出错: " + ex.Message;
                                    throw new Exception(strError);
                                }
                            }
                        }

#if NO
                        // 2011/12/30
                        // 日志记录可能动态地增加了,超过了原先为ProgressBar设置的范围
                        if (lFizeTotalSize < (int)lHintNext)
                        {
                            lFizeTotalSize = lHintNext;

                            stop.SetProgressRange(0, lFizeTotalSize);
                        }
#endif
                        if (lHintNext >= 0)
                        {
                            // 校正
                            if (lProgressValue + lHintNext >= lSize)    // > 2017/12/4 修改为 >=
                            {
                                lSize = lProgressValue + lHintNext;

                                if (this.Stop != null)
                                {
                                    this.Stop.SetProgressRange(0, lSize);
                                }
                                if (this.Estimate != null)
                                {
                                    Estimate.SetRange(0, lSize);
                                }
                            }

                            this.Stop?.SetProgressValue(lProgressValue + lHintNext);
                        }

                        if (lIndex % 100 == 0)
                        {
                            if (this.Stop != null && this.Estimate != null)
                            {
                                Estimate.Text = "剩余时间 " + ProgressEstimate.Format(Estimate.Estimate(lProgressValue + lHintNext)) + " 已经过时间 " + ProgressEstimate.Format(Estimate.delta_passed);
                                this.Stop.SetMessage("正在装入日志文件 " + this.Date + " 中的记录 " + lIndex.ToString() + " 。"
                                                     + Estimate.Text);
                            }
                        }

                        {
                            OperLogItem item = new OperLogItem
                            {
                                Xml              = strXml,
                                Index            = lIndex,
                                Date             = this.Date.Substring(0, 8),
                                AttachmentLength = lAttachmentTotalLength
                            };
                            yield return(item);
                        }
                    }
                }

                // 创建本地缓存的日志文件的 metadata 文件
                if (bCacheFileExist == false && stream != null)
                {
                    string strFileName = this.Date;
                    if ((this.LogType & LogType.AccessLog) != 0)
                    {
                        strFileName = this.Date + ".a";
                    }

                    nRet = CreateCacheMetadataFile(
                        this.CacheDir,
                        strFileName,    // this.FileName,
                        lServerFileSize,
                        out strError);
                    if (nRet == -1)
                    {
                        throw new Exception(strError);
                    }
                }

                bRemoveCacheFile = false;   // 不删除
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }

                if (bRemoveCacheFile == true)
                {
                    string strFileName = this.Date;
                    if ((this.LogType & LogType.AccessLog) != 0)
                    {
                        strFileName = this.Date + ".a";
                    }

                    string strError1 = "";
                    nRet = DeleteCacheFile(
                        this.CacheDir,
                        strFileName,    // this.FileName,
                        out strError1);
                    if (nRet == -1)
                    {
                        // MessageBox.Show(owner, strError1);
                        if (this.Prompt != null)
                        {
                            MessagePromptEventArgs e = new MessagePromptEventArgs();
                            e.MessageText = strError1;
                            e.Actions     = "ok";
                            this.Prompt(this, e);
                        }
                    }
                }
            }

            lProgressValue += lFileSize;
        }
Ejemplo n.º 7
0
        // 对每个日志文件,每个日志记录进行循环
        // return:
        //      0   普通返回
        //      1   要全部中断
        int DoLoop(
            OperLogForm.Delegate_doRecord procDoRecord,
            out string strError)
        {
            strError = "";
            int nRet = 0;
            // long lRet = 0;

            List <string> LogFileNames = null;

            // TODO: 是否需要检查起止日期是否为空值?空值是警告还是就当作今天?

            string strStartDate = DateTimeUtil.DateTimeToString8(this.dateControl_start.Value);
            string strEndDate   = DateTimeUtil.DateTimeToString8(this.dateControl_end.Value);

            string strWarning = "";

            // 根据日期范围,发生日志文件名
            // parameters:
            //      strStartDate    起始日期。8字符
            //      strEndDate  结束日期。8字符
            // return:
            //      -1  错误
            //      0   成功
            nRet = OperLogLoader.MakeLogFileNames(strStartDate,
                                                  strEndDate,
                                                  true,
                                                  out LogFileNames,
                                                  out strWarning,
                                                  out strError);
            if (nRet == -1)
            {
                return(-1);
            }

            if (String.IsNullOrEmpty(strWarning) == false)
            {
                MessageBox.Show(this, strWarning);
            }

            string strStyle = "";

            if (Program.MainForm.AutoCacheOperlogFile == true)
            {
                strStyle = "autocache";
            }

            ProgressEstimate estimate = new ProgressEstimate();

            nRet = OperLogForm.ProcessFiles(this,
                                            stop,
                                            estimate,
                                            Channel,
                                            LogFileNames,
                                            Program.MainForm.OperLogLevel,
                                            strStyle,
                                            "",           // strFilter
                                            Program.MainForm.OperLogCacheDir,
                                            null,         // param,
                                            procDoRecord, // DoRecord,
                                            out strError);
            if (nRet == -1)
            {
                return(-1);
            }

            return(nRet);
        }
Ejemplo n.º 8
0
        // 对每个日志文件,每个日志记录进行循环
        // return:
        //      -1  出错
        //      0   普通返回
        //      1   要全部中断
        int DoLoop(
            OperLogForm.Delegate_doRecord procDoRecord,
            out string strError)
        {
            strError = "";
            int nRet = 0;
            // long lRet = 0;

            List <string> LogFileNames = null;

            // TODO: 是否需要检查起止日期是否为空值?空值是警告还是就当作今天?

            string strStartDate = DateTimeUtil.DateTimeToString8(this.dateControl_start.Value);
            string strEndDate   = DateTimeUtil.DateTimeToString8(this.dateControl_end.Value);


            // 根据日期范围,发生日志文件名
            // parameters:
            //      strStartDate    起始日期。8字符
            //      strEndDate  结束日期。8字符
            // return:
            //      -1  错误
            //      0   成功
            nRet = OperLogLoader.MakeLogFileNames(strStartDate,
                                                  strEndDate,
                                                  true,
                                                  out LogFileNames,
                                                  out string strWarning,
                                                  out strError);
            if (nRet == -1)
            {
                return(-1);
            }

            if (String.IsNullOrEmpty(strWarning) == false)
            {
                MessageBox.Show(this, strWarning);
            }

            string strStyle = "";

            if (Program.MainForm.AutoCacheOperlogFile == true)
            {
                strStyle = "autocache";
            }

            ProgressEstimate estimate = new ProgressEstimate();

            LibraryChannel channel     = this.GetChannel();
            TimeSpan       old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromSeconds(10);
            try
            {
#if NO
                nRet = OperLogForm.ProcessFiles(this,
                                                stop,
                                                estimate,
                                                channel,
                                                LogFileNames,
                                                Program.MainForm.OperLogLevel,
                                                strStyle,
                                                "",           // strFilter
                                                Program.MainForm.OperLogCacheDir,
                                                null,         // param,
                                                procDoRecord, // DoRecord,
                                                out strError);
                if (nRet == -1)
                {
                    return(-1);
                }

                return(nRet);
#endif
                bool bAccessLog = StringUtil.IsInList("accessLog", strStyle);

                OperLogLoader loader = new OperLogLoader();
                loader.Channel   = channel;
                loader.Stop      = this.Progress;
                loader.Estimate  = estimate;
                loader.Dates     = LogFileNames;
                loader.Level     = Program.MainForm.OperLogLevel;
                loader.AutoCache = StringUtil.IsInList("autocache", strStyle);    // false;
                loader.CacheDir  = Program.MainForm.OperLogCacheDir;
                loader.LogType   = bAccessLog ? LogType.AccessLog : LogType.OperLog;
                // loader.Filter = "borrow,return";

                loader.Prompt -= new MessagePromptEventHandler(loader_Prompt);
                loader.Prompt += new MessagePromptEventHandler(loader_Prompt);

                foreach (OperLogItem item in loader)
                {
                    if (stop != null && stop.State != 0)
                    {
                        strError = "用户中断";
                        return(1);
                    }

                    if (stop != null)
                    {
                        stop.SetMessage("正在获取 " + item.Date + " " + item.Index.ToString() + " " + estimate.Text + "...");
                    }

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

                    nRet = procDoRecord(item.Date + ".log",
                                        item.Xml,
                                        false, // bInCacheFile,
                                        0,
                                        item.Index,
                                        item.AttachmentLength,
                                        null,
                                        out strError);
                    if (nRet == -1)
                    {
                        return(-1);
                    }
                }

                return(0);
            }
            catch (InterruptException ex)
            {
                strError = ex.Message;
                return(1);
            }
            finally
            {
                channel.Timeout = old_timeout;
                this.ReturnChannel(channel);
            }
        }
Ejemplo n.º 9
0
        // 导出数据
        void menu_export(object sender, System.EventArgs e)
        {
            string strError = "";

            string strTimeMessage = "";
            long lTotalCount = 0;	// 总命中数
            long lExportCount = 0;	// 已经传出的数量

            if (this.SelectedNode == null)
            {
                strError = "尚未选择要要导出数据的数据库节点";
                goto ERROR1;
            }

            if (this.SelectedNode.ImageIndex != RESTYPE_DB)
            {
                strError = "所选择的节点不是数据库类型。请选择要导出数据的数据库节点。";
                goto ERROR1;
            }

            ResPath respath = new ResPath(this.SelectedNode);

            // 询问导出数据的范围
            ExportDataDialog data_range_dlg = new ExportDataDialog();
            data_range_dlg.DbPath = respath.Path;
            data_range_dlg.AllRecords = true;
            data_range_dlg.StartPosition = FormStartPosition.CenterScreen;
            data_range_dlg.ShowDialog(this);

            if (data_range_dlg.DialogResult != DialogResult.OK)
                return;

            string strRange = "0-9999999999";
            if (data_range_dlg.AllRecords == false)
                strRange = data_range_dlg.StartID + "-" + data_range_dlg.EndID;

            // 获得输出文件名
            SaveFileDialog dlg = new SaveFileDialog();

            dlg.Title = "请指定要保存的数据文件名";
            dlg.CreatePrompt = false;
            dlg.OverwritePrompt = false;
            dlg.FileName = "";
            dlg.FilterIndex = 1;

            dlg.Filter = "备份文件 (*.dp2bak)|*.dp2bak|XML文件 (*.xml)|*.xml|ISO2709文件 (*.iso;*.mrc)|*.iso;*.mrc|All files (*.*)|*.*";

            dlg.RestoreDirectory = true;

            if (dlg.ShowDialog(this) != DialogResult.OK)
                return;

            ExportUtil export_util = new ExportUtil();


            string strQueryXml = "<target list='" + respath.Path
    + ":" + "__id'><item><word>"+strRange+"</word><match>exact</match><relation>range</relation><dataType>number</dataType><maxCount>-1</maxCount></item><lang>chi</lang></target>";


            RmsChannel cur_channel = Channels.CreateTempChannel(respath.Url);
            Debug.Assert(cur_channel != null, "Channels.GetChannel() 异常");

#if NO
            DigitalPlatform.Stop stop = null;

            if (stopManager != null)
            {
                stop = new DigitalPlatform.Stop();

                stop.Register(this.stopManager, true);	// 和容器关联

                stop.OnStop += new StopEventHandler(this.DoStop);
                stop.Initial("正在导出数据 " + respath.FullPath);
                stop.BeginLoop();
            }
#endif
            DigitalPlatform.Stop stop = PrepareStop("正在导出数据 " + respath.FullPath);

            stop.OnStop -= new StopEventHandler(this.DoStop);   // 去掉缺省的回调函数
            stop.OnStop += (sender1, e1) =>
            {
                    if (cur_channel != null)
                        cur_channel.Abort();
                };

            try
            {
                long lRet = cur_channel.DoSearch(strQueryXml,
    "default",
    out strError);
                if (lRet == -1)
                {
                    strError = "检索数据库 '"+respath.Path+"' 时出错: " + strError;
                    goto ERROR1;
                }

                if (lRet == 0)
                {
                    strError = "数据库 '" + respath.Path + "' 中没有任何数据记录";
                    goto ERROR1;	// not found
                }

                stop.Style = StopStyle.EnableHalfStop;  // API的间隙才让中断。避免获取结果集的中途,因为中断而导致 Session 失效,结果集丢失,进而无法 Retry 获取

                lTotalCount = lRet;	// 总命中数
                long lThisCount = lTotalCount;
                long lStart = 0;

                ProgressEstimate estimate = new ProgressEstimate();

                estimate.SetRange(0, lTotalCount);
                estimate.StartEstimate();

                stop.SetProgressRange(0, lTotalCount);

                int nRet = export_util.Begin(this,
    dlg.FileName,
    out strError);
                if (nRet == -1)
                    goto ERROR1;

                DialogResult last_one_result = DialogResult.Yes;    // 前一次对话框选择的方式
                bool bDontAskOne = false;
                int nRedoOneCount = 0;
                DialogResult last_get_result = DialogResult.Retry;    // 前一次对话框选择的方式
                bool bDontAskGet = false;
                int nRedoGetCount = 0;

                for (; ; )
                {
                    Application.DoEvents();	// 出让界面控制权

                    if (stop.State != 0)
                    {
                        DialogResult result = MessageBox.Show(this,
                            "确实要中断当前批处理操作?",
                            "导出数据",
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Question,
                            MessageBoxDefaultButton.Button2);
                        if (result == DialogResult.Yes)
                        {
                            strError = "用户中断";
                            goto ERROR1;
                        }
                        else
                        {
                            stop.Continue();
                        }
                    }

                    string strStyle = "id,xml,timestamp";
                    if (export_util.FileType == ExportFileType.BackupFile)
                        strStyle = "id,xml,timestamp,metadata";

                    nRedoGetCount = 0;
                REDO_GET:
                    Record[] searchresults = null;
                    lRet = cur_channel.DoGetSearchResult(
                        "default",
                        lStart,
                        lThisCount,
                        strStyle,
                        this.Lang,
                        stop,
                        out searchresults,
                        out strError);
                    if (lRet == -1)
                    {
                        if (stop.State != 0)    // 已经中断
                            goto ERROR1;

                        // 自动重试有次数限制,避免进入死循环
                        if (bDontAskGet == true && last_get_result == DialogResult.Retry
                            && nRedoGetCount < 3)
                        {
                            nRedoGetCount++;
                            goto REDO_GET;
                        }

                        DialogResult result = MessageDlg.Show(this,
    "获取检索结果时 (偏移量 " + lStart + ") 出错:\r\n---\r\n"
    + strError + "\r\n---\r\n\r\n是否重试获取操作?\r\n\r\n注:\r\n[重试] 重新获取\r\n[中断] 中断整个批处理",
    "导出数据",
    MessageBoxButtons.RetryCancel,
    MessageBoxDefaultButton.Button1,
    ref bDontAskOne,
    new string[] { "重试", "中断" });
                        last_get_result = result;

                        if (result == DialogResult.Retry)
                        {
                            nRedoGetCount = 0;
                            goto REDO_GET;
                        }

                        Debug.Assert(result == DialogResult.Cancel, ""); 

                        strError = "获取检索结果时出错: " + strError;
                        goto ERROR1;
                    }

                    for (int i = 0; i < searchresults.Length; i++)
                    {
                        Record record = searchresults[i];

                        if (i == 0)
                        {
                            stop.SetMessage("正在输出记录 " + record.Path + ",已输出 " + lExportCount.ToString() + " 条。"
        + "剩余时间 " + ProgressEstimate.Format(estimate.Estimate(lExportCount)) + " 已经过时间 " + ProgressEstimate.Format(estimate.delta_passed));
                        }
                        nRedoOneCount = 0;

                    REDO_ONE:
                        nRet = export_util.ExportOneRecord(
                            cur_channel,
                            stop,
                            respath.Url,
                            record.Path,
                            record.RecordBody.Xml,
                            record.RecordBody.Metadata,
                            record.RecordBody.Timestamp,
                            out strError);
                        if (nRet == -1)
                        {
                            if (stop.State != 0)    // 已经中断
                                goto ERROR1;

                            // 重试、跳过、中断?
                            // 重试的时候,注意保持文件最后位置,不要留下残余的尾部
                            // MessageBoxButtons.AbortRetryIgnore  YesNoCancel
                            if (bDontAskOne == true && last_one_result == DialogResult.No)
                                continue;   // TODO: 最好在日志文件中记载跳过的记录。或者批处理结束后显示出来

                            // 自动重试有次数限制,避免进入死循环
                            if (bDontAskOne == true && last_one_result == DialogResult.Yes
                                && nRedoOneCount < 3)
                            {
                                nRedoOneCount++;
                                goto REDO_ONE;
                            }

                            DialogResult result = MessageDlg.Show(this,
                                "导出记录 '" + record.Path + "' 时出错:\r\n---\r\n"
                                + strError + "\r\n---\r\n\r\n是否重试导出操作?\r\n\r\n注:\r\n[重试] 重新导出这条记录\r\n[跳过] 忽略导出这条记录,但继续后面的处理\r\n[中断] 中断整个批处理",
                                "导出数据",
                                MessageBoxButtons.YesNoCancel,
                                MessageBoxDefaultButton.Button1,
                                ref bDontAskOne,
                                new string [] {"重试","跳过","中断"});
                            last_one_result = result;

                            if (result == DialogResult.Yes)
                            {
                                nRedoOneCount = 0;
                                goto REDO_ONE;
                            }

                            if (result == DialogResult.No)
                                continue;

                            Debug.Assert(result == DialogResult.Cancel, ""); 

                            goto ERROR1;
                        }

                        stop.SetProgressValue(lExportCount + 1);
                        lExportCount++;
                    }

                    if (lStart + searchresults.Length >= lTotalCount)
                        break;

                    lStart += searchresults.Length;
                    lThisCount -= searchresults.Length;
                }

                strTimeMessage = "总共耗费时间: " + estimate.GetTotalTime().ToString();
            }
            finally
            {
                EndStop(stop);
#if NO
                if (stopManager != null)
                {
                    stop.EndLoop();
                    stop.OnStop -= new StopEventHandler(this.DoStop);
                    stop.Initial("");

                    stop.Unregister();	// 和容器脱离关联
                }
#endif
                cur_channel.Close();
                cur_channel = null;

                export_util.End();
            }

            MessageBox.Show(this, "位于服务器 '" + respath.Url + "' 上的数据库 '" + respath.Path + "' 内共有记录 " + lTotalCount.ToString() + " 条,本次导出 " + lExportCount.ToString() + " 条。" + strTimeMessage);
            return;
        ERROR1:
            MessageBox.Show(this, strError);
            if (lExportCount > 0)
                MessageBox.Show(this, "数据库内共有记录 " + lTotalCount.ToString() + " 条,本次导出 " + lExportCount.ToString() + " 条");
        }
Ejemplo n.º 10
0
        // 导入数据
        int ImportData(bool bFastMode = false)
        {
            string strError = "";
            string strTimeMessage = "";
            int CHUNK_SIZE = 150 * 1024;    // 70

            if (this.SelectedNode == null)
            {
                strError = "尚未选择要要导入数据的数据库节点";
                goto ERROR0;
            }

            if (this.SelectedNode.ImageIndex != RESTYPE_DB)
            {
                strError = "所选择的节点不是数据库类型。请选择要导入数据的数据库节点。";
                goto ERROR0;
            }

            if (bFastMode == true)
            {
                DialogResult result = MessageBox.Show(this,
        "警告:\r\n在快速导入期间,相关数据库会进入一种锁定状态,对数据库的其他检索和修改操作暂时会被禁止,直到处理完成。\r\n\r\n请问确实要进行快速导入么?",
        "导入数据",
        MessageBoxButtons.YesNo,
        MessageBoxIcon.Question,
        MessageBoxDefaultButton.Button2);
                if (result == DialogResult.No)
                    return 0;
            }

            OpenFileDialog dlg = new OpenFileDialog();

            dlg.Title = "请指定要导入的数据文件";
            dlg.FileName = "";
            dlg.Filter = "备份文件 (*.dp2bak)|*.dp2bak|XML文件 (*.xml)|*.xml|ISO2709文件 (*.iso;*.mrc)|*.iso;*.mrc|All files (*.*)|*.*";
            dlg.RestoreDirectory = true;

            if (dlg.ShowDialog() != DialogResult.OK)
            {
                return 0;
            }

            long lTotalCount = 0;

            ImportUtil import_util = new ImportUtil();
            int nRet = import_util.Begin(this,
                this.AppInfo,
                dlg.FileName,
                out strError);
            if (nRet == -1 || nRet == 1)
                goto ERROR0;

#if NO
            ResPath respath = new ResPath(this.SelectedNode);
            this.channel = Channels.GetChannel(respath.Url);
            Debug.Assert(channel != null, "Channels.GetChannel() 异常");
#endif
            // 缺省的目标数据库路径
            ResPath default_target_respath = new ResPath(this.SelectedNode);
            RmsChannel cur_channel = Channels.CreateTempChannel(default_target_respath.Url);
            Debug.Assert(cur_channel != null, "Channels.GetChannel() 异常");

            List<string> target_dburls = new List<string>();
#if NO
            DigitalPlatform.Stop stop = null;

            if (stopManager != null)
            {
                stop = new DigitalPlatform.Stop();

                stop.Register(this.stopManager, true);	// 和容器关联

                stop.OnStop += new StopEventHandler(this.DoStop);
                stop.Initial("正在导入数据 " + respath.FullPath);
                stop.BeginLoop();
            }
#endif
            DigitalPlatform.Stop stop = PrepareStop("正在导入数据 ...");  // + default_target_respath.FullPath);
            stop.OnStop -= new StopEventHandler(this.DoStop);   // 去掉缺省的回调函数
            stop.OnStop += (sender1, e1) =>
            {
                if (cur_channel != null)
                    cur_channel.Abort();
            };
            stop.Style = StopStyle.EnableHalfStop;  // API的间隙才让中断。避免获取结果集的中途,因为中断而导致 Session 失效,结果集丢失,进而无法 Retry 获取
            ProgressEstimate estimate = new ProgressEstimate();
            try // open import util
            {
                    bool bDontPromptTimestampMismatchWhenOverwrite = false;
                    DbNameMap map = new DbNameMap();
                    long lSaveOffs = -1;

                    estimate.SetRange(0, import_util.Stream.Length);
                    estimate.StartEstimate();

                    stop.SetProgressRange(0, import_util.Stream.Length);

                    List<UploadRecord> records = new List<UploadRecord>();
                    int nBatchSize = 0;
                    for (int index = 0; ; index++)
                    {
                        Application.DoEvents();	// 出让界面控制权

                        if (stop.State != 0)
                        {
                            DialogResult result = MessageBox.Show(this,
                                "确实要中断当前批处理操作?",
                                "导入数据",
                                MessageBoxButtons.YesNo,
                                MessageBoxIcon.Question,
                                MessageBoxDefaultButton.Button2);
                            if (result == DialogResult.Yes)
                            {
                                strError = "用户中断";
                                goto ERROR1;
                            }
                            else
                            {
                                stop.Continue();
                            }
                        }

                        //string strXml = "";
                        //string strResPath = "";
                        //string strTimeStamp = "";
                        UploadRecord record = null;

                        if (import_util.FileType == ExportFileType.BackupFile)
                        {
                            if (lSaveOffs != -1)
                                import_util.Stream.Seek(lSaveOffs, SeekOrigin.Begin);
                        }

                        nRet = import_util.ReadOneRecord(out record,
                            out strError);
                        if (nRet == -1)
                            goto ERROR1;
                        if (nRet == 1)
                            break;

                        if (import_util.FileType == ExportFileType.BackupFile)
                        {
                            // 保存每次读取后的文件指针位置
                            lSaveOffs = import_util.Stream.Position;
                        }

                        Debug.Assert(record != null, "");
#if NO
                    XmlDocument dom = new XmlDocument();
                    try
                    {
                        dom.LoadXml(strXml);
                    }
                    catch (Exception ex)
                    {
                        strError = "XML装入DOM时出错: " + ex.Message;
                        goto ERROR1;
                    }
                    string strResPath = DomUtil.GetAttr(DpNs.dprms, dom.DocumentElement, "path");
                    string strTimeStamp = DomUtil.GetAttr(DpNs.dprms, dom.DocumentElement, "timestamp");
#endif

                        // 准备目标路径
                        {
                            string strLongPath = record.Url + "?" + record.RecordBody.Path;
#if NO
                        // 根据原始路径准备即将写入的路径
                        // return:
                        //      -1  出错
                        //      0   用户放弃
                        //      1   成功
                        nRet = ImportUtil.PrepareOverwritePath(
                this.Servers,
                this.Channels,
                this,
                ref map,
                ref strLongPath,
                out strError);
                        if (nRet == 0 || nRet == -1)
                            goto ERROR1;
#endif
                            // 根据原始路径准备即将写入的路径
                            // return:
                            //      -1  出错
                            //      0   用户放弃
                            //      1   成功
                            //      2   要跳过本条
                            nRet = ImportUtil.PrepareOverwritePath(
                                this,
                                this.Servers,
                                this.Channels,
                                this.AppInfo,
                                index,
                                default_target_respath.FullPath,
                                ref map,
                                ref strLongPath,
                                out strError);
                            if (nRet == 0 || nRet == -1)
                                goto ERROR1;
                            if (nRet == 2)
                                continue;

                            ResPath respath = new ResPath(strLongPath);
                            record.Url = respath.Url;
                            record.RecordBody.Path = respath.Path;

                            // 记载每个数据库的 URL
                            string strDbUrl = GetDbUrl(strLongPath);
                            if (target_dburls.IndexOf(strDbUrl) == -1)
                            {
                                // 每个数据库要进行一次快速模式的准备操作
                                if (bFastMode == true)
                                {
                                    nRet = ManageKeysIndex(strDbUrl,
                                        "beginfastappend",
                                        "正在对数据库 "+strDbUrl+" 进行快速导入模式的准备工作 ...",
                                        out strError);
                                    if (nRet == -1)
                                        goto ERROR1;
                                }
                                target_dburls.Add(strDbUrl);
                            }
                        }

                        bool bNeedPush = false;
                        // 是否要把积累的记录推送出去进行写入?
                        // 要进行以下检查:
                        // 1) 当前记录和前一条记录之间,更换了服务器
                        // 2) 累积的记录尺寸超过要求
                        // 3) 当前记录是一条超大的记录 (这是因为要保持从文件中读出的顺序来写入(例如追加时候的号码增量顺序),就必须在单条写入本条前,先写入积累的那些记录)
                        if (records.Count > 0)
                        {
                            if (record.TooLarge() == true)
                                bNeedPush = true;
                            else if (nBatchSize + record.RecordBody.Xml.Length > CHUNK_SIZE)
                                bNeedPush = true;
                            else
                            {
                                if (LastUrl(records) != record.Url)
                                    bNeedPush = true;
                            }
                        }


                        if (bNeedPush == true)
                        {
                            // 准备 Channel
                            Debug.Assert(records.Count > 0, "");
                            cur_channel = ImportUtil.GetChannel(this.Channels,
                                stop,
                                LastUrl(records),
                                cur_channel);

                            List<UploadRecord> save_records = new List<UploadRecord>();
                            save_records.AddRange(records);

                            while (records.Count > 0)
                            {
                                // 将 XML 记录成批写入数据库
                                // return:
                                //      -1  出错
                                //      >=0 本次已经写入的记录个数。本函数返回时 records 集合的元素数没有变化(但元素的Path和Timestamp会有变化),如果必要调主可截取records集合中后面未处理的部分再次调用本函数
                                nRet = ImportUtil.WriteRecords(
                                    this,
                                    stop,
                                    cur_channel,
                                    bFastMode,
                                    records,
                                    ref bDontPromptTimestampMismatchWhenOverwrite,
                                    out strError);
                                if (nRet == -1)
                                    goto ERROR1;
                                if (nRet == 0)
                                {
                                    // TODO: 或可以改为单条写入
                                    strError = "WriteRecords() error :" + strError;
                                    goto ERROR1;
                                }
                                Debug.Assert(nRet <= records.Count, "");
                                records.RemoveRange(0, nRet);
                                lTotalCount += nRet;
                            }

                            // 上载对象
                            // return:
                            //      -1  出错
                            //      0   成功
                            nRet = import_util.UploadObjects(
                                stop,
                                cur_channel,
                                save_records,
                                ref bDontPromptTimestampMismatchWhenOverwrite,
                                out strError);
                            if (nRet == -1)
                                goto ERROR1;

                            nBatchSize = 0;
                            stop.SetProgressValue(import_util.Stream.Position);

                            stop.SetMessage("已经写入记录 " + lTotalCount.ToString() + " 条。"
    + "剩余时间 " + ProgressEstimate.Format(estimate.Estimate(import_util.Stream.Position)) + " 已经过时间 " + ProgressEstimate.Format(estimate.delta_passed));

                        }

                        // 如果 记录的 XML 尺寸太大不便于成批上载,需要在单独直接上载
                        if (record.TooLarge() == true)
                        {
                            // 准备 Channel
                            // ResPath respath = new ResPath(record.RecordBody.Path);
                            cur_channel = ImportUtil.GetChannel(this.Channels,
                                stop,
                                record.Url,
                                cur_channel);

                            // 写入一条 XML 记录
                            // return:
                            //      -1  出错
                            //      0   邀请中断整个处理
                            //      1   成功
                            //      2   跳过本条,继续处理后面的
                            nRet = ImportUtil.WriteOneXmlRecord(
                                this,
                                stop,
                                cur_channel,
                                record,
                                ref bDontPromptTimestampMismatchWhenOverwrite,
                                out strError);
                            if (nRet == -1)
                                goto ERROR1;
                            if (nRet == 0)
                                goto ERROR1;

                            List<UploadRecord> temp = new List<UploadRecord>();
                            temp.Add(record);
                            // 上载对象
                            // return:
                            //      -1  出错
                            //      0   成功
                            nRet = import_util.UploadObjects(
                                stop,
                                cur_channel,
                                temp,
                                ref bDontPromptTimestampMismatchWhenOverwrite,
                                out strError);
                            if (nRet == -1)
                                goto ERROR1;

                            lTotalCount += 1;
                            continue;
                        }

                        records.Add(record);
                        if (record.RecordBody != null && record.RecordBody.Xml != null)
                            nBatchSize += record.RecordBody.Xml.Length;
                    }

                    // 最后提交一次
                    if (records.Count > 0)
                    {
                        // 准备 Channel
                        Debug.Assert(records.Count > 0, "");
                        cur_channel = ImportUtil.GetChannel(this.Channels,
                            stop,
                            LastUrl(records),
                            cur_channel);

                        List<UploadRecord> save_records = new List<UploadRecord>();
                        save_records.AddRange(records);

                        while (records.Count > 0)
                        {
                            // 将 XML 记录成批写入数据库
                            // return:
                            //      -1  出错
                            //      >=0 本次已经写入的记录个数。本函数返回时 records 集合的元素数没有变化(但元素的Path和Timestamp会有变化),如果必要调主可截取records集合中后面未处理的部分再次调用本函数
                            nRet = ImportUtil.WriteRecords(
                                this,
                                stop,
                                cur_channel,
                                bFastMode,
                                records,
                                ref bDontPromptTimestampMismatchWhenOverwrite,
                                out strError);
                            if (nRet == -1)
                                goto ERROR1;
                            if (nRet == 0)
                            {
                                strError = "WriteRecords() error :" + strError;
                                goto ERROR1;
                            }
                            Debug.Assert(nRet <= records.Count, "");
                            records.RemoveRange(0, nRet);
                            lTotalCount += nRet;
                        }

                        // 上载对象
                        // return:
                        //      -1  出错
                        //      0   成功
                        nRet = import_util.UploadObjects(
                            stop,
                            cur_channel,
                            save_records,
                            ref bDontPromptTimestampMismatchWhenOverwrite,
                            out strError);
                        if (nRet == -1)
                            goto ERROR1;

                        nBatchSize = 0;
                        stop.SetProgressValue(import_util.Stream.Position);

                        stop.SetMessage("已经写入记录 " + lTotalCount.ToString() + " 条。"
    + "剩余时间 " + ProgressEstimate.Format(estimate.Estimate(import_util.Stream.Position)) + " 已经过时间 " + ProgressEstimate.Format(estimate.delta_passed));

                        records.Clear();
                        nBatchSize = 0;
                    }
            }// close import util
            finally
            {
                if (bFastMode == true)
                {
                    foreach (string url in target_dburls)
                    {
                        string strQuickModeError = "";
                        nRet = ManageKeysIndex(url,
                            "endfastappend",
                            "正在对数据库 " + url + " 进行快速导入模式的收尾工作,请耐心等待 ...",
                            out strQuickModeError);
                        if (nRet == -1)
                            MessageBox.Show(this, strQuickModeError);
                    }
                }

                EndStop(stop);
#if NO
                if (stopManager != null)
                {
                    stop.EndLoop();
                    stop.OnStop -= new StopEventHandler(this.DoStop);
                    stop.Initial("");

                    stop.Unregister();	// 和容器脱离关联
                }
#endif
                cur_channel.Close();
                cur_channel = null;

                import_util.End();
            }

            strTimeMessage = "总共耗费时间: " + estimate.GetTotalTime().ToString();
            MessageBox.Show(this, "文件 " + dlg.FileName + " 内的数据已经成功导入下列数据库:\r\n\r\n" + StringUtil.MakePathList(target_dburls, "\r\n") + "\r\n\r\n共导入记录 " + lTotalCount.ToString() + " 条。\r\n\r\n" + strTimeMessage);
            return 0;
        ERROR0:
            MessageBox.Show(this, strError);
            return -1;
        ERROR1:
            MessageBox.Show(this, strError);
            // 使用了 lTotalCount 和 estimate 以后的报错
            if (lTotalCount > 0)
            {
                strTimeMessage = "总共耗费时间: " + estimate.GetTotalTime().ToString();
                MessageBox.Show(this, "文件 " + dlg.FileName + " 内的部分数据已经成功导入下列数据库:\r\n\r\n" + StringUtil.MakePathList(target_dburls, "\r\n") + "\r\n\r\n共导入记录 " + lTotalCount.ToString() + " 条。\r\n\r\n" + strTimeMessage);
            }
            return -1;
        }