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; } }
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; } } }
// 同步 // 注:中途遇到异常(例如 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 }); } }
// 第二阶段:根据操作日志进行同步 // 注:中途遇到异常(例如 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); } }
// 对每个日志文件,每个日志记录进行循环 // 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); }
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; }
// 对每个日志文件,每个日志记录进行循环 // 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); }
// 对每个日志文件,每个日志记录进行循环 // 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); } }
// 导出数据 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() + " 条"); }
// 导入数据 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; }