internal void SetBreakPoint(CorModule module, string className, string methodName, INotification _lisenter) { BreakPointInfo breakpoint = new BreakPointInfo(module.Name, className, methodName, null, _lisenter); if (!breakStringVsBP.ContainsKey(breakpoint.Identifier)){ int token = 0; CorFunction fun = null; try{ module.Importer.FindTypeDefByName(className, 0, out token); } catch (Exception){ throw new BreakPointException(className + " class is not found in" + module.Name); } MetaType type = new MetaType(module.Importer, token); try{ List<BreakPointInfo> bps = new List<BreakPointInfo>(); foreach (MetadataMethodInfo methodInfo in type.GetMethods(methodName)){ BreakPointInfo bp = new BreakPointInfo(module.Name, className, methodName, null, _lisenter); fun = module.GetCorFuntion((uint)methodInfo.MetadataToken); bp.bpoint = fun.CreateBreakPoint(); bp.bpoint.Activate(); bps.Add(bp); } if(bps.Count > 0){ breakStringVsBP.Add(bps[0].Identifier, bps); } } catch (Exception) { throw new BreakPointException(methodName + " Method is not found in" + className); } } }
public void EnableBreakPoint(ulong address, BreakPointInfo info) { if (BreakPoints.ContainsKey(address)) { // breakpoints should be enabled only once BreakPoints[address].Description = info.Description; } else { Console.WriteLine("enabling breakpoint: " + info.Description); info.ShouldEnable = true; BreakPoints[address] = info; _enabledBreakPoints[address] = info; } }
// 通过字符串构造 public static BreakPointInfo Build(string strText) { Hashtable table = StringUtil.ParseParameters(strText); BreakPointInfo info = new BreakPointInfo(); info.DbName = (string)table["dbname"]; info.RecID = (string)table["recid"]; info.Function = (string)table["function"]; info.BackupFileName = (string)table["backup_filename"]; return(info); }
// 保存断点信息,并保存 this.StartInfos void SaveBreakPoint(BreakPointInfo infos, bool bClearStartInfos) { // 写入断点文件 this.App.WriteBatchTaskBreakPointFile(this.Name, infos.ToString() + "|||" + ToString(this.StartInfos)); if (bClearStartInfos) { this.StartInfos = new List <BatchTaskStartInfo>(); // 避免残余信息对后一轮运行发生影响 } }
// 读出断点信息,和恢复 this.StartInfos // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 int ReadBreakPoint(out BreakPointInfo breakpoint, out string strError) { strError = ""; breakpoint = null; // List<BatchTaskStartInfo> start_infos = null; string strText = ""; // 从断点记忆文件中读出信息 // return: // -1 error // 0 file not found // 1 found int nRet = this.App.ReadBatchTaskBreakPointFile(this.DefaultName, out strText, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { strError = "启动失败。因当前还没有断点信息,请指定为其他方式运行"; return(0); } string strStartInfos = ""; string strBreakPoint = ""; StringUtil.ParseTwoPart(strText, "|||", out strBreakPoint, out strStartInfos); // 可能会抛出异常 breakpoint = BreakPointInfo.Build(strBreakPoint); #if NO start_infos = FromString(strStartInfos); if (start_infos != null) { this.StartInfos = start_infos; } #endif return(1); }
// 通过字符串构造 public static BreakPointInfo Build(string strText) { Hashtable table = StringUtil.ParseParameters(strText); BreakPointInfo info = new BreakPointInfo(); info.Date = (string)table["date"]; if (info.Date.Length != 8) { throw new ArgumentException("strText 中 date 参数值应为 8 字符", "strText"); } info.Offset = Convert.ToInt64((string)table["offset"]); return(info); }
// 保存断点信息 void SaveBreakPoint(BreakPointInfo info, bool bClearStartInfos) { if (info == null || (info != null && string.IsNullOrEmpty(info.DbName) == true && string.IsNullOrEmpty(info.RecID) == true)) { this.App.RemoveBatchTaskBreakPointFile(this.Name); } else { // 写入断点文件 this.App.WriteBatchTaskBreakPointFile(this.Name, info.ToString()); } if (bClearStartInfos) { this.StartInfos = new List <BatchTaskStartInfo>(); // 避免残余信息对后一轮运行发生影响 } }
// parameters: // strBackupFileName 备份文件名。扩展名应为 .dp2bak // return: // -1 出错 // 0 处理被中断 // 1 成功 int BackupDatabase( RmsChannel channel, string strRecPathFileName, BreakPointInfo info, string strBackupFileName, out BreakPointInfo breakpoint, out string strError) { strError = ""; breakpoint = new BreakPointInfo(); breakpoint.BackupFileName = strBackupFileName; this._stop.BeginLoop(); try { ExportUtil export_util = new ExportUtil(); export_util.SafeMode = true; export_util.TempDir = this.App.TempDir; int nRet = export_util.Begin(null, strBackupFileName, out strError); if (nRet == -1) { return(-1); } try { List <string> lines = new List <string>(); using (StreamReader sr = new StreamReader(strRecPathFileName, Encoding.UTF8)) { long lTotalLength = sr.BaseStream.Length; // 跳过断点位置前,以前已经处理过的行 if (info != null && string.IsNullOrEmpty(info.DbName) == false && string.IsNullOrEmpty(info.RecID) == false) { while (true) { if (this.Stopped == true) { strError = "中断"; WriteStateFile(strBackupFileName, "abort"); // 表示文件创建过程被中断。文件内容不完整 return(0); } string line = sr.ReadLine(); if (line == null) { break; } string strDbName = ResPath.GetDbName(line); string strID = ResPath.GetRecordId(line); if (info.DbName == strDbName && info.RecID == strID) { break; } } } this.AppendResultText("开始写入大备份文件" + strBackupFileName + "\r\n"); while (true) { if (this.Stopped == true) { strError = "中断"; WriteStateFile(strBackupFileName, "abort"); // 表示文件创建过程被中断。文件内容不完整 return(0); } string line = sr.ReadLine(); if (line != null) { lines.Add(line); } if (lines.Count >= BATCH_SIZE || (line == null && lines.Count > 0)) { RmsBrowseLoader loader = new RmsBrowseLoader(); loader.Channel = channel; loader.Format = "id,xml,timestamp,metadata"; loader.RecPaths = lines; foreach (Record record in loader) { if (this.Stopped == true) { strError = "中断"; WriteStateFile(strBackupFileName, "abort"); // 表示文件创建过程被中断。文件内容不完整 return(0); } // TODO: 检查 RecordBody 是否为 null nRet = export_util.ExportOneRecord( channel, this._stop, this.App.WsUrl, record.Path, record.RecordBody.Xml, record.RecordBody.Metadata, record.RecordBody.Timestamp, out strError); if (nRet == -1) { WriteStateFile(strBackupFileName, "error"); // 表示文件创建过程出错 return(-1); } breakpoint.DbName = ResPath.GetDbName(record.Path); breakpoint.RecID = ResPath.GetRecordId(record.Path); long lCurrent = sr.BaseStream.Position; SetProgressText(m_nRecordCount.ToString() + " " + record.Path + " " + GetPercent((double)lCurrent, lTotalLength)); // 每 100 条显示一行 if ((m_nRecordCount % 100) == 0) { this.AppendResultText("已输出记录 " + record.Path + " " + (m_nRecordCount + 1).ToString() + "\r\n"); } m_nRecordCount++; } lines.Clear(); } if (line == null) { break; } } Debug.Assert(lines.Count == 0, ""); breakpoint = null; } } finally { export_util.End(); } WriteStateFile(strBackupFileName, "finish"); // 表示文件已经创建完成 return(1); } catch (Exception ex) { strError = "BackupDatabase() 出现异常: " + ExceptionUtil.GetDebugText(ex); WriteStateFile(strBackupFileName, "error"); // 表示文件创建过程出错 return(-1); } finally { this._stop.EndLoop(); } }
// 一次操作循环 public override void Worker() { // 系统挂起的时候,不运行本线程 if (this.App.ContainsHangup("LogRecover") == true) { return; } if (this.App.PauseBatchTask == true) { return; } // REDO_TASK: try { string strError = ""; int nRet = 0; if (this.App.LibraryCfgDom == null || this.App.LibraryCfgDom.DocumentElement == null) { return; } BatchTaskStartInfo startinfo = this.StartInfo; if (startinfo == null) { startinfo = new BatchTaskStartInfo(); // 按照缺省值来 } BackupTaskStart param = BackupTaskStart.FromString(startinfo.Start); string strDbNameList = param.DbNameList; #if NO string strDbNameList = ""; int nRet = ParseStart(startinfo.Start, out strDbNameList, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } #endif // 下一次 loop 进入的时候自动就是 continue (从断点继续) startinfo.Start = ""; #if NO // string strFunction = ""; nRet = ParseTaskParam(startinfo.Param, out strFunction, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } #endif // if (String.IsNullOrEmpty(strDbNameList) == true) if (strDbNameList == "continue") { // 从断点继续循环 strDbNameList = "continue"; } string strRecPathFileName = Path.Combine(this.App.BackupDir, "recpath.txt"); string strBackupFileName = ""; if (string.IsNullOrEmpty(param.BackupFileName) == true) { strBackupFileName = Path.Combine(this.App.BackupDir, this.App.LibraryName + "_" + BackupTaskStart.GetDefaultBackupFileName()); } else { strBackupFileName = Path.Combine(this.App.BackupDir, CanonializeBackupFileName(param.BackupFileName)); } // 构造用于复制然后同步的断点信息 // BreakPointCollection all_breakpoints = BreakPointCollection.BuildFromDbNameList(strDbNameList, strFunction); // 进行处理 BreakPointInfo breakpoint = null; this.AppendResultText("*********\r\n"); RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); if (strDbNameList == "continue") { // 按照断点信息处理 this.AppendResultText("从上次断点位置继续\r\n"); // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 nRet = ReadBreakPoint(out breakpoint, out strError); if (nRet == -1) { goto ERROR1; } if (nRet == 0) { // return; // TODO: 此时如何让等待结束?并且返回启动出错信息 goto ERROR1; } strBackupFileName = breakpoint.BackupFileName; if (string.IsNullOrEmpty(strBackupFileName)) { strError = "从上次断点开始运行时,发现 BackupFileName 为空,只好放弃运行"; goto ERROR1; } // WriteStateFile(strBackupFileName, "creating"); // 表示文件正在创建中 PrepareBackupFileName(strBackupFileName, true); this.AppendResultText("(从断点继续)本次大备份文件为 " + strBackupFileName + "\r\n"); } else { { BreakPointInfo temp_breakpoint = null; // 删除上次的大备份文件 // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 nRet = ReadBreakPoint(out temp_breakpoint, out strError); if (nRet == -1) { goto ERROR1; } if (nRet == 1) { string strLastBackupFileName = temp_breakpoint.BackupFileName; if (string.IsNullOrEmpty(strLastBackupFileName) == false) { DeleteDataFiles(strLastBackupFileName); this.AppendResultText("自动删除上次创建的大备份文件 " + strLastBackupFileName + "\r\n"); } } temp_breakpoint = null; } // 先从远端复制整个数据库,然后从开始复制时的日志末尾进行同步 this.AppendResultText("指定的数据库\r\n"); DeleteDataFiles(strBackupFileName); PrepareBackupFileName(strBackupFileName, false); this.AppendResultText("本次大备份文件为 " + strBackupFileName + "\r\n"); // 采纳先前创建好的复制并继续的断点信息 // breakpoints = all_breakpoints; // 建立数据库定义文件 { string strDefFileName = GetDatabaseDefFileName(strBackupFileName); nRet = CreateDatabaseDefFile(channel, strDbNameList, strDefFileName, out strError); if (nRet == -1) { this.AppendResultText("创建数据库定义文件失败: " + strError + "\r\n"); WriteStateFile(strDefFileName, null); // 表示文件创建出错 return; } } // 建立要获取的记录路径文件 nRet = CreateRecPathFile(channel, strDbNameList, strRecPathFileName, out strError); if (nRet == -1) { this.AppendResultText("创建记录路径文件失败: " + strError + "\r\n"); WriteStateFile(strBackupFileName, null); // 表示文件创建出错 return; } } // Debug.Assert(breakpoints != null, ""); this.AppendResultText("计划进行的处理:\r\n---\r\n" + (breakpoint == null ? "备份全部数据库" : breakpoint.GetSummary()) + "\r\n---\r\n\r\n"); m_nRecordCount = 0; BreakPointInfo output_breakpoint = null; // for (int i = 0; i < breakpoints.Count; i++) { // BreakPointInfo info = breakpoints[i]; // return: // -1 出错 // 0 处理被中断 // 1 成功 nRet = BackupDatabase( channel, strRecPathFileName, breakpoint, strBackupFileName, out output_breakpoint, out strError); if (nRet == -1 || nRet == 0) { // 保存断点文件 SaveBreakPoint(output_breakpoint, true); goto ERROR1; } // breakpoints.Remove(info); // i--; // 保存断点文件 SaveBreakPoint(output_breakpoint, false); try { File.Delete(strRecPathFileName); } catch { } } // TODO: 如果集合为空,需要删除断点信息文件 // 正常结束,复位断点 if (this.StartInfos.Count == 0) { // this.App.RemoveBatchTaskBreakPointFile(this.Name); this.ClearTask(); } this.StartInfo.Start = ""; // AppendResultText("针对消息库 " + strMessageDbName + " 的循环结束。共处理 " + nRecCount.ToString() + " 条记录。\r\n"); // TODO: 在断点文件中记载 StartInfos 内容 this.AppendResultText("大备份结束。结果在文件 " + strBackupFileName + " 中\r\n"); #if NO { // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 nRet = ReadBreakPoint(out breakpoints, out strError); if (nRet == -1) { goto ERROR1; } // 如果有累积的任务,还需要继续执行 if (nRet == 1 && this.StartInfos.Count > 0) { this.StartInfo = this.StartInfos[0]; this.StartInfos.RemoveAt(0); goto REDO_TASK; } } #endif DoPendingCommands(strBackupFileName); return; ERROR1: this.ErrorInfo = strError; this.AppendResultText(strError + "\r\n"); this.SetProgressText(strError); DoPendingCommands(strBackupFileName); return; } finally { } }
// 一次操作循环 public override void Worker() { // 系统挂起的时候,不运行本线程 if (this.App.ContainsHangup("LogRecover") == true) { return; } if (this.App.PauseBatchTask == true) { return; } this.Loop = true; // 2017/10/16 BatchTaskStartInfo startinfo = this.StartInfo; if (startinfo == null) { startinfo = new BatchTaskStartInfo(); // 按照缺省值来 } string strError = ""; int nRet = 0; ServerReplicationStart start = ServerReplicationStart.FromString(startinfo.Start); ServerReplicationParam param = ServerReplicationParam.FromString(startinfo.Param); #if NO long lStartIndex = 0; // 开始位置 string strStartFileName = ""; // 开始文件名 nRet = ParseReplicationStart(startinfo.Start, out lStartIndex, out strStartFileName, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } // string strRecoverLevel = ""; bool bClearFirst = false; bool bContinueWhenError = false; nRet = ParseReplicationParam(startinfo.Param, out strRecoverLevel, out bClearFirst, out bContinueWhenError, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } #endif this.App.WriteErrorLog(this.Name + " 任务启动。"); // 获得源 dp2library 服务器配置信息 { nRet = GetSourceServerCfg(out strError); if (nRet == -1) { goto ERROR1; } nRet = CheckUID(out strError); if (nRet == -1) { goto ERROR1; } } #if NO // 当为容错恢复级别时,检查当前全部读者库的检索点是否符合要求 if (this.RecoverLevel == LibraryServer.RecoverLevel.Robust) { // 检查全部读者库的检索途径,看是否满足都有“所借册条码号”这个检索途径的这个条件 // return: // -1 出错 // 0 不满足 // 1 满足 nRet = this.App.DetectReaderDbFroms(out strError); if (nRet == -1) { this.AppendResultText("检查读者库检索点时发生错误: " + strError + "\r\n"); return; } if (nRet == 0) { this.AppendResultText("在容错恢复级别下,当前读者库中有部分或全部读者库缺乏“所借册条码号”检索点,无法进行日志恢复。请按照日志恢复要求,刷新所有读者库的检索点配置,然后再进行日志恢复\r\n"); return; } } #endif // TODO: 检查当前是否有 重建检索点 的后台任务正在运行,或者还有没有运行完的部分。 // 要求重建检索点的任务运行完以后才能执行日志恢复任务 #if NO if (bClearFirst == true) { nRet = this.App.ClearAllDbs(this.RmsChannels, out strError); if (nRet == -1) { this.AppendResultText("清除全部数据库记录时发生错误: " + strError + "\r\n"); return; } } #endif // 进行处理 // BreakPointInfo breakpoint = null; #if NO if (string.IsNullOrEmpty(start.StartFileName) == false && start.StartFileName != "continue") { breakpoint = new BreakPointInfo(start.StartFileName.Substring(0, 8), start.StartIndex); } #endif this.AppendResultText("*********\r\n"); if (start.Date == "continue" || string.IsNullOrEmpty(start.Date)) { // 按照断点信息处理 this.AppendResultText("从上次断点位置继续\r\n"); // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 nRet = ReadBreakPoint(out start, out param, out strError); if (nRet == -1) { goto ERROR1; } if (nRet == 0) { // return; goto ERROR1; } // 此后返回前可以用 start 写入断点文件了 } else { // 先从远端复制整个数据库,然后从开始复制时的日志末尾进行同步 this.AppendResultText("指定的数据库\r\n"); // 采纳先前创建好的复制并继续的断点信息 } Debug.Assert(start != null, ""); this.AppendResultText("计划进行的处理:\r\n---\r\n" + start.GetSummary() + "\r\n---\r\n\r\n"); // TODO: 处理中途可以定期保存断点文件,这样可以在掉电等情况下也能尽量保证后续从断点位置附近开始处理 // return: // -1 出错 // 0 中断 // 1 完成 nRet = ProcessOperLogs(start, param.ContinueWhenError, (s) => { SaveBreakPoint(s, param); }, param == null ? "" : param.Style, out strError); if (nRet == -1 || nRet == 0) { // 保存断点文件 // 迫使后面循环处理的时候,从断点位置继续 goto ERROR2; } #if NO bool bStart = false; if (String.IsNullOrEmpty(strStartFileName) == true) { // 做所有文件 bStart = true; } // 列出所有日志文件 DirectoryInfo di = new DirectoryInfo(this.App.OperLog.Directory); FileInfo[] fis = di.GetFiles("*.log"); // BUG!!! 以前缺乏排序。2008/2/1 Array.Sort(fis, new FileInfoCompare()); for (int i = 0; i < fis.Length; i++) { if (this.Stopped == true) { break; } string strFileName = fis[i].Name; this.AppendResultText("检查文件 " + strFileName + "\r\n"); if (bStart == false) { // 从特定文件开始做 if (string.CompareOrdinal(strStartFileName, strFileName) <= 0) // 2015/9/12 从等号修改为 Compare { bStart = true; if (lStartIndex < 0) { lStartIndex = 0; } // lStartIndex = Convert.ToInt64(startinfo.Param); } } if (bStart == true) { nRet = DoOneLogFile(strFileName, lStartIndex, bContinueWhenError, out strError); if (nRet == -1) { goto ERROR1; } lStartIndex = 0; // 第一个文件以后的文件就全做了 } } #endif this.AppendResultText("循环结束\r\n"); this.App.WriteErrorLog("日志恢复 任务结束。"); // 保存断点文件 SaveBreakPoint(start, param); this.StartInfo = BuildStartInfo(null, param); // 迫使后面循环处理的时候,从断点位置继续 return; ERROR1: this.AppendResultText(strError + "\r\n任务因出错而中断。\r\n"); return; ERROR2: // 保存断点文件 SaveBreakPoint(start, param); this.StartInfo = BuildStartInfo(null, param); // 迫使后面循环处理的时候,从断点位置继续 this.AppendResultText(strError + "\r\n任务因出错而中断。\r\n"); return; }
int RebuildDatabase(BreakPointInfo info, out string strError) { strError = ""; RmsChannel channel = RmsChannels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; return(-1); } // 恢复为最大范围 string strStartNo = "1"; string strEndNo = "9999999999"; string strOutputStartNo = ""; string strOutputEndNo = ""; if (string.IsNullOrEmpty(info.RecID) == false) { strStartNo = info.RecID; } // 校验起止号 // return: // 0 不存在记录 // 1 存在记录 int nRet = VerifyRange(channel, info.DbName, strStartNo, strEndNo, out strOutputStartNo, out strOutputEndNo, out strError); if (nRet == -1) { return(-1); } if (nRet == 0) { return(0); } strStartNo = strOutputStartNo; strEndNo = strOutputEndNo; Int64 nStart; Int64 nEnd; Int64 nCur; if (Int64.TryParse(strStartNo, out nStart) == false) { strError = "数据库 '" + info.DbName + "' 起始记录 ID '" + strStartNo + "' 不合法"; return(-1); } if (Int64.TryParse(strEndNo, out nEnd) == false) { strError = "数据库 '" + info.DbName + "' 结束记录 ID '" + strEndNo + "' 不合法"; return(-1); } // Refresh数据库定义 long lRet = channel.DoRefreshDB( "begin", info.DbName, false, // bClearKeysAtBegin == true ? true : false, out strError); if (lRet == -1) { return(-1); } string strID = strStartNo; try { bool bFirst = true; // 是否为第一次取记录 // 循环 for (; ;) { if (this.Stopped == true) { strError = "中断"; return(-1); } // string strDirectionComment = ""; string strStyle = ""; strStyle = "timestamp,outputpath"; // 优化 strStyle += ",forcedeleteoldkeys"; if (bFirst == true) { // 注:如果不校验首号,只有强制循环的情况下,才能不需要next风格 strStyle += ""; } else { strStyle += ",next"; // strDirectionComment = "的后一条记录"; } string strPath = info.DbName + "/" + strID; string strOutputPath = ""; bool bFoundRecord = false; bool bNeedRetry = true; int nRedoCount = 0; REDO_REBUILD: // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 lRet = channel.DoRebuildResKeys(strPath, strStyle, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { if (bFirst == true) { // 如果不要强制循环,此时也不能结束,否则会让用户以为数据库里面根本没有数据 // AutoCloseMessageBox.Show(this, "您为数据库 " + info.DbName + " 指定的首记录 " + strID + strDirectionComment + " 不存在。\r\n\r\n(注:为避免出现此提示,可在操作前勾选“校准首尾ID”)\r\n\r\n按 确认 继续向后找..."); bFirst = false; goto CONTINUE; } else { Debug.Assert(bFirst == false, ""); if (bFirst == true) { strError = "记录 " + strID + "(后一条) 不存在。处理结束。"; } else { strError = "记录 " + strID + " 是最末一条记录。处理结束。"; } return(0); } } else if (channel.ErrorCode == ChannelErrorCode.EmptyRecord) { bFirst = false; // bFoundRecord = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); goto CONTINUE; } // 允许重试 if (bNeedRetry == true) { if (nRedoCount < 10) { nRedoCount++; goto REDO_REBUILD; } } else { return(-1); } } // end of nRet == -1 bFirst = false; bFoundRecord = true; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); info.RecID = strID; // 记忆 // 每 100 条显示一行 if ((m_nRecordCount % 100) == 0) { this.AppendResultText("已重建检索点 记录 " + strOutputPath + " " + (m_nRecordCount + 1).ToString() + "\r\n"); } #if NO if (String.IsNullOrEmpty(strRealStartNo) == true) { strRealStartNo = strID; } strRealEndNo = strID; #endif CONTINUE: // 是否超过循环范围 if (Int64.TryParse(strID, out nCur) == false) { strError = "数据库 '" + info.DbName + "' 当前记录 ID '" + strID + "' 不合法"; return(-1); } #if NO try { nCur = Convert.ToInt64(strID); } catch { // ??? nCur = 0; } #endif if (nCur > nEnd) { break; } if (bFoundRecord == true) { m_nRecordCount++; } // // SetProgressText((nCur - nStart + 1).ToString()); // 对已经作过的进行判断 if (nCur >= nEnd) { break; } } } finally { #if NO if (bClearKeysAtBegin == true) { // 结束Refresh数据库定义 lRet = channel.DoRefreshDB( "end", info.DbName, false, // 此参数此时无用 out strError); if (lRet == -1) { return(-1); } } #endif } return(0); }
// 一次操作循环 public override void Worker() { // 系统挂起的时候,不运行本线程 if (this.App.ContainsHangup("LogRecover") == true) { return; } if (this.App.PauseBatchTask == true) { return; } REDO_TASK: try { string strError = ""; if (this.App.LibraryCfgDom == null || this.App.LibraryCfgDom.DocumentElement == null) { return; } BatchTaskStartInfo startinfo = this.StartInfo; if (startinfo == null) { startinfo = new BatchTaskStartInfo(); // 按照缺省值来 } string strDbNameList = ""; int nRet = ParseStart(startinfo.Start, out strDbNameList, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } // 下一次 loop 进入的时候自动就是 continue (从断点继续) startinfo.Start = ""; // string strRecoverLevel = ""; bool bClearFirst = false; nRet = ParseTaskParam(startinfo.Param, out strRecoverLevel, out bClearFirst, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } // 下一次 loop 进入的时候什么动作有没有,避免重复前一次的清除数据库动作 startinfo.Param = ""; if (bClearFirst == true) { // 清除全部同步的本地库 } if (String.IsNullOrEmpty(strDbNameList) == true) { // 从断点继续循环 strDbNameList = "continue"; } // 构造用于复制然后同步的断点信息 BreakPointCollcation all_breakpoints = BreakPointCollcation.BuildFromDbNameList(strDbNameList); // 进行处理 BreakPointCollcation breakpoints = null; this.AppendResultText("*********\r\n"); if (strDbNameList == "continue") { // 按照断点信息处理 this.AppendResultText("从上次断点位置继续\r\n"); // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 nRet = ReadBreakPoint(out breakpoints, out strError); if (nRet == -1) { goto ERROR1; } if (nRet == 0) { return; } } else { // 先从远端复制整个数据库,然后从开始复制时的日志末尾进行同步 this.AppendResultText("指定的数据库\r\n"); // 采纳先前创建好的复制并继续的断点信息 breakpoints = all_breakpoints; } Debug.Assert(breakpoints != null, ""); this.AppendResultText("计划进行的处理:\r\n---\r\n" + breakpoints.GetSummary() + "\r\n---\r\n\r\n"); if (this.StartInfos.Count > 0) { this.AppendResultText("等待队列:\r\n---\r\n" + GetSummary(this.StartInfos) + "\r\n---\r\n\r\n"); } m_nRecordCount = 0; for (int i = 0; i < breakpoints.Count; i++) { BreakPointInfo info = breakpoints[i]; nRet = RebuildDatabase(info, out strError); if (nRet == -1) { // 保存断点文件 SaveBreakPoint(breakpoints, true); goto ERROR1; } breakpoints.Remove(info); i--; // 保存断点文件 SaveBreakPoint(breakpoints, false); } // TODO: 如果集合为空,需要删除断点信息文件 // 正常结束,复位断点 if (this.StartInfos.Count == 0) { this.App.RemoveBatchTaskBreakPointFile(this.Name); } this.StartInfo.Start = ""; // AppendResultText("针对消息库 " + strMessageDbName + " 的循环结束。共处理 " + nRecCount.ToString() + " 条记录。\r\n"); // TODO: 在断点文件中记载 StartInfos 内容 #if NO // 按照断点信息进行处理 foreach (XmlNode server in server_nodes) { string strServerName = DomUtil.GetAttr(server, "name"); // 找到断点信息 BreakPointInfo info = breakpoints.GetBreakPoint(strServerName); if (info == null) { continue; } if (string.IsNullOrEmpty(info.BiblioDbName) == false) { // 从数据库复制 // 列出中心服务器的全部可用数据库,然后进行复制 // 断点书目库名表示从这个库开始向后复制 // 从远端复制一个数据库 // 函数返回后, info 信息可能会被改变,需要及时保存到断点文件中,便于以后重新启动批处理 // return: // -1 出错 // 0 中断 // 1 完成 nRet = CopyDatabase(server, ref info, out strError); // 保存断点文件 SaveBreakPoint(breakpoints); if (nRet == -1) { goto ERROR1; } if (nRet == 0) { goto STOP; } // 表示复制已经成功结束 info.BiblioDbName = ""; info.RecID = ""; // 保存断点文件 SaveBreakPoint(breakpoints); } if (string.IsNullOrEmpty(info.Date) == false) { string strLastDate = ""; long last_index = -1; nRet = ProcessServer(server, info.Date, strEndDate, info.Index, out strLastDate, out last_index, out strError); // 记忆 if (string.IsNullOrEmpty(strLastDate) == false) { Debug.Assert(last_index != -1, ""); info.Date = strLastDate; info.Index = last_index; // 注:从同步的角度来说,同步永远不会结束,所以不会清除 Date 和 Index } // 保存断点文件 SaveBreakPoint(breakpoints); if (nRet == -1) { this.AppendResultText("发生错误:" + strError + "\r\n"); } if (nRet == 0) { goto STOP; } SetProgressText("完成"); } } #endif this.AppendResultText("本轮处理结束\r\n"); { // return: // -1 出错 // 0 没有发现断点信息 // 1 成功 nRet = ReadBreakPoint(out breakpoints, out strError); if (nRet == -1) { goto ERROR1; } // 如果有累积的任务,还需要继续执行 if (nRet == 1 && this.StartInfos.Count > 0) { this.StartInfo = this.StartInfos[0]; this.StartInfos.RemoveAt(0); goto REDO_TASK; } } return; ERROR1: this.AppendResultText(strError + "\r\n"); return; } finally { } #if NO STOP: if (this.App.PauseBatchTask == true) { this.Loop = true; // 如果因为暂停而中断,既的后面还要重新开始 SetProgressText("暂时中断"); this.AppendResultText("暂时中断\r\n"); } else { this.Loop = false; SetProgressText("中断"); this.AppendResultText("中断\r\n"); } #endif }
// for deserialization public void AddBreakPoint(ulong address, BreakPointInfo info) { BreakPoints[address] = info; if (info.ShouldEnable) { _enabledBreakPoints[address] = info; } }