// 追加文本 // 多线程:安全 internal void AppendText(string strRefID, string strText) { if (String.IsNullOrEmpty(strText) == true) { return; } if (m_resultset == null) { return; } m_lock.EnterWriteLock(); try { // 打开当天的内容文件 string strError = ""; int nRet = PrepareContentFileName(out strError); if (nRet == -1) { throw new Exception(strError); } DpRecord record = new DpRecord(strRefID); record.BrowseText = strText; m_resultset.Add(record); } finally { m_lock.ExitWriteLock(); } }
// parameters: // bChangeVersion 是否修改版本号 // lNewVersion 返回修改后的新版本号。如果bChangeVersion==false, 此参数也返回没有发生过变化的版本号 // strContent 返回已经删除的记录的内容 int DeleteItem(DpResultSet resultset, string strRefID, bool bChangeVersion, bool bAllowDeleteNotifyItem, out long lNewVersion, out string strContent, out string strError) { strError = ""; lNewVersion = 0; strContent = ""; for (long i = 0; i < resultset.Count; i++) { DpRecord record = resultset[i]; if (record.ID == strRefID) { strContent = record.BrowseText; if (bAllowDeleteNotifyItem == false && string.IsNullOrEmpty(strContent) == false) { XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strContent); } catch (Exception ex) { strError = "记录内容装入XMLDOM时出错: " + ex.Message; return(-1); } string strClass = DomUtil.GetAttr(dom.DocumentElement, "class"); strClass.Replace(" ", ","); if (StringUtil.IsInList("notify", strClass) == true) { strError = "notify事项不允许删除"; return(-1); } } resultset.RemoveAt((int)i); if (resultset == this.m_resultset) { if (bChangeVersion == true) { this.ContentFileVersion = DateTime.Now.Ticks; // 文件版本发生变化 } lNewVersion = this.ContentFileVersion; } return(1); // deleted } } strError = "refid为 '" + strRefID + "' 的事项没有找到"; return(0); // not found }
void FlushTable(Hashtable temp_table, DpResultSet resultset) { foreach (string path in temp_table.Keys) { this._app_down.Token.ThrowIfCancellationRequested(); DpRecord record_bibliorecpath = new DpRecord(path); resultset.Add(record_bibliorecpath); } }
ChatInfo GetInfo( DpResultSet resultset, long nStart, long nCount, bool bDisplayAllIP) { ChatInfo info = new ChatInfo(); info.Name = this.Name; long nMax = 0; if (nCount == -1) { nMax = resultset.Count; } else { nMax = Math.Min(resultset.Count, nStart + nCount); } if (nMax - nStart > MAX_COUNT_PER_GET) { nMax = nStart + MAX_COUNT_PER_GET; } string strResult = ""; for (long i = nStart; i < nMax; i++) { DpRecord record = resultset[i]; if (bDisplayAllIP == true) { strResult += record.BrowseText; } else { strResult += MaskIP(record.BrowseText); } } info.ResultText = strResult; info.NextStart = nMax; // 结束位置 info.TotalLines = resultset.Count; if (resultset == this.m_resultset) { info.ResultVersion = this.ContentFileVersion; } else { info.ResultVersion = 0; // 暂时无法给出 } return(info); }
// 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 void AppendFingerprintInfo( LibraryChannel channel, DpResultSet resultset, Hashtable update_table, CancellationToken token) { List <string> lines = new List <string>(); foreach (string recpath in update_table.Keys) { lines.Add(recpath); } BrowseLoader loader = new BrowseLoader(); loader.RecPaths = lines; loader.Channel = channel; loader.Format = $"id,cols,format:cfgs/browse_{this.BrowseStyle}"; loader.Prompt += this.Loader_Prompt; foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader) { token.ThrowIfCancellationRequested(); this.ShowMessage("追加 " + record.Path); if (record.Cols == null || record.Cols.Length < 3) { string strError = $"record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_{this.BrowseStyle}"; // TODO: 并发操作的情况下,会在中途出现读者记录被别的前端修改的情况,这里似乎可以continue throw new Exception(strError); } // 如果证条码号为空,无法建立对照关系,要跳过 if (string.IsNullOrEmpty(record.Cols[1]) == true) { continue; } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } }
// 将内存数组写入结果集文件 public static int WriteToResulsetFile( KeyValueCollection items, string strResultsetFilename, out string strError) { strError = ""; DpResultSet resultset = new DpResultSet(false, false); resultset.Create(strResultsetFilename, strResultsetFilename + ".index"); bool bDone = false; try { foreach (KeyValue item in items) { DpRecord record = new DpRecord(item.Value); record.BrowseText = item.Key; resultset.Add(record); } bDone = true; return(0); } finally { if (bDone == true) { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } else { // 否则文件会被删除 resultset.Close(); } } }
// return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // >=0 实际发送给接口程序的事项数目 static int CreateFingerprintCache(DpResultSet resultset, out string strError) { strError = ""; int nRet = 0; ShowMessage("加入高速缓存"); try { if (resultset == null) { // 清空以前的全部缓存内容,以便重新建立 // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // 0 成功 nRet = AddItems( //channel, null, out strError); if (nRet == -1) { return(-1); } if (nRet == -2) { return(-2); } return(0); } int nSendCount = 0; long nCount = resultset.Count; List <FingerprintItem> items = new List <FingerprintItem>(); for (long i = 0; i < nCount; i++) { DpRecord record = resultset[i]; string strTimestamp = ""; string strBarcode = ""; string strFingerprint = ""; ParseResultItemString(record.BrowseText, out strTimestamp, out strBarcode, out strFingerprint); // TODO: 注意读者证条码号为空的,不要发送出去 FingerprintItem item = new FingerprintItem(); item.ReaderBarcode = strBarcode; item.FingerprintString = strFingerprint; items.Add(item); if (items.Count >= 100) { // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // 0 成功 nRet = AddItems( //channel, items, out strError); if (nRet == -1) { return(-1); } if (nRet == -2) { return(-2); } nSendCount += items.Count; items.Clear(); } } if (items.Count > 0) { // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // 0 成功 nRet = AddItems( //channel, items, out strError); if (nRet == -1) { return(-1); } if (nRet == -2) { return(-2); } nSendCount += items.Count; } // Console.Beep(); // 表示读取成功 return(nSendCount); } finally { } }
// 根据结果集文件初始化指纹高速缓存 // parameters: // resultset 用于初始化的结果集对象。如果为 null,表示希望清空指纹高速缓存 // 一般可用 null 调用一次,然后用多个 resultset 对象逐个调用一次 // return: // -1 出错 // >=0 实际发送给接口程序的事项数目 int CreateFingerprintCache(DpResultSet resultset, out string strError) { strError = ""; int nRet = 0; this.ShowMessage("加入高速缓存"); try { if (resultset == null) { // 清空以前的全部缓存内容,以便重新建立 // return: // 0 成功 // 其他 失败。错误码 nRet = this.AddItems( null, out strError); if (nRet != 0) { return(-1); } return(0); } int nSendCount = 0; long nCount = resultset.Count; List <FingerprintItem> items = new List <FingerprintItem>(); for (long i = 0; i < nCount; i++) { DpRecord record = resultset[i]; //string strTimestamp = ""; //string strBarcode = ""; //string strFingerprint = ""; ParseResultItemString(record.BrowseText, out string strTimestamp, out string strBarcode, out string strFingerprint); // TODO: 注意读者证条码号为空的,不要发送出去 FingerprintItem item = new FingerprintItem { ReaderBarcode = strBarcode, FingerprintString = strFingerprint }; items.Add(item); if (items.Count >= 100) { // return: // 0 成功 // 其他 失败。错误码 nRet = this.AddItems( items, out strError); if (nRet != 0) { return(-1); } nSendCount += items.Count; items.Clear(); } } if (items.Count > 0) { // return: // 0 成功 // 其他 失败。错误码 nRet = this.AddItems( items, out strError); if (nRet != 0) { return(-1); } nSendCount += items.Count; } // Console.Beep(); // 表示读取成功 return(nSendCount); } finally { } }
static void FlushTable(Hashtable temp_table, DpResultSet resultset) { foreach (string path in temp_table.Keys) { DpRecord record_bibliorecpath = new DpRecord(path); resultset.Add(record_bibliorecpath); } }
// 从 dp2Library(其实也可以说dp2Kernel) 端获取结果集 // parameters: // strStyle tobibliorecpath 将实体\期\订购\评注 记录路径转换为书目记录路径,并去重 int GetResultset(LibraryChannel channel, string strResultsetName, string strResultsetFilename, string strStyle, out int nCount, out string strError) { strError = ""; nCount = 0; long lStart = 0; long lRet = 0; m_biblioDbNameTable.Clear(); bool bToBiblioRecPath = StringUtil.IsInList("tobibliorecpath", strStyle); #if NO DpResultSet item_paths = null; if (bToBiblioRecPath == true) item_paths = new DpResultSet(true); // 临时文件会自动丢弃 #endif DpResultSet resultset = new DpResultSet(false, false); resultset.Create(strResultsetFilename, strResultsetFilename + ".index"); bool bDone = false; try { Hashtable temp_table = new Hashtable(); for (; ; ) { if (this.m_bClosed == true || this.Stopped == true) { strError = "中断"; return -1; } Thread.Sleep(1); // List<string> aPath = null; Record[] searchresults = null; string strGetStyle = "id"; if (bToBiblioRecPath == true) strGetStyle = "id,cols,format:@coldef://parent"; // "id,xml"; lRet = channel.GetSearchResult( null, strResultsetName, lStart, -1, // 100 strGetStyle, "zh", out searchresults, out strError); if (lRet == -1) return -1; long lHitCount = lRet; for (int j = 0; j < searchresults.Length; j++) { if ((j % 10) == 9) this.SetProgressText("从检索结果中获得记录路径 " + (lStart + j + 1).ToString() + " 条"); Record rec = searchresults[j]; if (bToBiblioRecPath == false) { DpRecord record = new DpRecord(rec.Path); resultset.Add(record); } else { if (rec.RecordBody != null && rec.RecordBody.Result != null && rec.RecordBody.Result.ErrorCode != ErrorCodeValue.NoError) { strError = "获得结果集位置偏移 " + (lStart + j).ToString() + " 时出错,该记录已被忽略: " + rec.RecordBody.Result.ErrorString; this.AppendResultText(strError + "\r\n"); continue; } string strBiblioRecPath = ""; #if NO // 从册记录XML中获得书目记录路径 // return: // -1 出错 // 1 成功 int nRet = GetBiblioRecPath( rec.Path, rec.RecordBody.Xml, out strBiblioRecPath, out strError); if (nRet == -1) return -1; #endif if (rec.Cols == null || rec.Cols.Length == 0) { strError = "获得结果集位置偏移 " + (lStart + j).ToString() + " 时出错: rec.Cols 为空"; this.AppendResultText(strError + "\r\n"); continue; } // return: // -1 出错 // 1 成功 int nRet = GetBiblioRecPathByParentID( rec.Path, rec.Cols[0], out strBiblioRecPath, out strError); if (nRet == -1) return -1; // 缓冲并局部去重 if (temp_table.Contains(strBiblioRecPath) == false) { temp_table.Add(strBiblioRecPath, null); if (temp_table.Count > 1000) { FlushTable(temp_table, resultset); temp_table.Clear(); } } //DpRecord record = new DpRecord(rec.Path); //item_paths.Add(record); } } if (searchresults.Length <= 0 // < 100 ) break; lStart += searchresults.Length; nCount += searchresults.Length; if (lStart >= lHitCount) break; } if (bToBiblioRecPath == true) { #if NO Hashtable temp_table = new Hashtable(); for (int j = 0; j < item_paths.Count; j++) { // Debug.WriteLine("output " + j.ToString()); DpRecord record = item_paths[j]; string strPath = record.ID; Record rec = searchresults[j]; XmlDocument itemdom = null; int nRet = OpacApplication.LoadToDom(rec.RecordBody.Xml, out itemdom, out strError); if (nRet == -1) { strError = "装载记录 '" + strPath + "' 进入XML DOM时发生错误: " + strError; return -1; } string strBiblioDbName = ""; string strDbName = ResPath.GetDbName(strPath); string strDbType = this.App.GetDbType(strDbName, out strBiblioDbName); if (strDbType == null) { strError = "数据库 '" + strDbName + "' 的类型无法识别"; return -1; } string strParentID = DomUtil.GetElementText(itemdom.DocumentElement, "parent"); string strBiblioRecPath = strBiblioDbName + "/" + strParentID; // 缓冲并局部去重 if (temp_table.Contains(strBiblioRecPath) == false) { temp_table.Add(strBiblioRecPath, null); if (temp_table.Count > 1000) { FlushTable(temp_table, resultset); temp_table.Clear(); } } if ((j % 10) == 9) this.SetProgressText("已转换写入书目记录路径 " + (j + 1).ToString() + " 条"); if ((j % 1000) == 999) this.AppendResultText("已转换写入书目记录路径 "+(j+1).ToString()+" 条" + "\r\n"); /* DpRecord record_bibliorecpath = new DpRecord(strBiblioRecPath); resultset.Add(record_bibliorecpath); * */ } #endif if (temp_table.Count > 0) { FlushTable(temp_table, resultset); temp_table.Clear(); } // 归并后写入结果集文件 resultset.Idle += new IdleEventHandler(biblio_paths_Idle); // 2016/1/23 原来这里是 -=,令人费解 try { this.SetProgressText("正在排序"); this.AppendResultText("开始排序。事项数 " + resultset.Count + "\r\n"); resultset.QuickSort(); this.AppendResultText("结束排序。事项数 " + resultset.Count + "\r\n"); this.SetProgressText("正在去重"); resultset.Sorted = true; // 2012/5/30 this.AppendResultText("开始去重。事项数 " + resultset.Count + "\r\n"); resultset.RemoveDup(); this.AppendResultText("结束去重。事项数 " + resultset.Count + "\r\n"); } catch (InterruptException /*ex*/) { strError = "中断"; return -1; } finally { resultset.Idle -= new IdleEventHandler(biblio_paths_Idle); } } this.SetProgressText("输出结果集完成"); bDone = true; } finally { if (bDone == true) { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } else { // 否则文件会被删除 resultset.Close(); } } return 0; }
// 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 int AppendFingerprintInfo(DpResultSet resultset, Hashtable update_table, out string strError) { strError = ""; int nRet = 0; // 需要获得更新的事项,然后追加到结果集文件的尾部 // 注意,需要定期彻底重建结果集文件,以便回收多余空间 List<string> lines = new List<string>(); foreach (string recpath in update_table.Keys) { lines.Add(recpath); if (lines.Count >= 100) { List<DigitalPlatform.CirculationClient.localhost.Record> records = null; nRet = GetSomeFingerprintData(lines, out records, out strError); if (nRet == -1) return -1; foreach (DigitalPlatform.CirculationClient.localhost.Record record in records) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; // TODO: 并发操作的情况下,会在中途出现读者记录被别的前端修改的情况,这里似乎可以continue return -1; } // 如果证条码号为空,无法建立对照关系,要跳过 if (string.IsNullOrEmpty(record.Cols[1]) == true) continue; DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } lines.Clear(); } } if (lines.Count > 0) { List<DigitalPlatform.CirculationClient.localhost.Record> records = null; nRet = GetSomeFingerprintData(lines, out records, out strError); if (nRet == -1) return -1; foreach (DigitalPlatform.CirculationClient.localhost.Record record in records) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; // TODO: 并发操作的情况下,会在中途出现读者记录被别的前端修改的情况,这里似乎可以continue return -1; } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } } return 0; }
// 从结果集中提取指定范围的记录 // parameter: // lStart 开始序号 // lLength 长度. -1表示从lStart到末尾 // strLang 语言 // strStyle 样式,以逗号分隔,id:表示取id,cols表示取浏览格式 // 如果包含 format:cfgs/browse 这样的子串,表示指定浏览格式 // aRecord 得到的记录数组,成员为类型为Record // strError out参数,返回出错信息 // result: // -1 出错 // >=0 结果集的总数 public long API_GetRecords( DpResultSet resultSet, long lStart, long lLength, string strLang, string strStyle, out Record[] records, out string strError) { records = null; strError = ""; // DpResultSet resultSet = this.DefaultResultSet; if (resultSet == null) { strError = "GetRecords()出错, resultSet 为 null"; return(-1); } long lTotalPackageLength = 0; // 累计计算要输出的XML记录占据的空间 long lOutputLength; // 检查lStart lLength和resultset.Count之间的关系, // 和每批返回最大元素数限制, 综合得出一个合适的尺寸 // return: // -1 出错 // 0 成功 int nRet = ConvertUtil.GetRealLength((int)lStart, (int)lLength, (int)resultSet.Count, SessionInfo.MaxRecordsCountPerApi,//nMaxCount, out lOutputLength, out strError); if (nRet == -1) { return(-1); } bool bKeyCount = StringUtil.IsInList("keycount", strStyle, true); bool bKeyID = StringUtil.IsInList("keyid", strStyle, true); bool bHasID = StringUtil.IsInList("id", strStyle, true); bool bHasCols = StringUtil.IsInList("cols", strStyle, true); bool bHasKey = StringUtil.IsInList("key", strStyle, true); if (bKeyID == true && bHasID == false && bHasCols == false && bHasKey == false) { strError = "strStyle包含了keyid但是没有包含id/key/cols中任何一个,导致API不返回任何内容,操作无意义"; return(-1); } bool bXml = StringUtil.IsInList("xml", strStyle, true); bool bWithResMetadata = StringUtil.IsInList("withresmetadata", strStyle, true); bool bTimestamp = StringUtil.IsInList("timestamp", strStyle, true); bool bMetadata = StringUtil.IsInList("metadata", strStyle, true); string strFormat = StringUtil.GetStyleParam(strStyle, "format"); List <Record> results = new List <Record>(100); long lPos = -1; // 中间保持不透明的值 for (long i = 0; i < lOutputLength; i++) { DpRecord dpRecord = null; long lIndex = lStart + i; if (lIndex == lStart) { dpRecord = resultSet.GetFirstRecord( lIndex, false, out lPos); } else { // 取元素比[]操作速度快 dpRecord = resultSet.GetNextRecord( ref lPos); } if (dpRecord == null) { break; } Record record = new Record(); if (bKeyCount == true) { record.Path = dpRecord.ID; record.Cols = new string[1]; record.Cols[0] = dpRecord.Index.ToString(); #if NO lTotalPackageLength += record.Path.Length; lTotalPackageLength += record.Cols[0].Length; if (lTotalPackageLength > QUOTA_SIZE && i > 0) { // 响应包的尺寸已经超过 1M,并且已经至少包含了一条记录 break; } #endif goto CONTINUE; } DbPath path = new DbPath(dpRecord.ID); Database db = this.app.Dbs.GetDatabaseSafety(path.Name); if (db == null) { strError = "GetDatabaseSafety()从库id '" + path.Name + "' 找数据库对象失败"; return(-1); } // 如果有必要获得记录体 string strXml = ""; string strMetadata = ""; byte[] baTimestamp = null; if (bXml == true || bTimestamp == true || bMetadata == true) { // 获得一条记录的 XML 字符串 // return: // -1 出错 // -4 未找到记录 // -10 记录局部未找到 // 0 成功 long lRet = GetXmlBody( db, path.ID, bXml, bTimestamp, bMetadata, bWithResMetadata, out strXml, out strMetadata, out baTimestamp, out strError); if (lRet <= -1) { record.RecordBody = new RecordBody(); record.RecordBody.Xml = strXml; record.RecordBody.Metadata = strMetadata; record.RecordBody.Timestamp = baTimestamp; Result result = new Result(); result.Value = -1; result.ErrorCode = KernelApplication.Ret2ErrorCode((int)lRet); result.ErrorString = strError; record.RecordBody.Result = result; goto CONTINUE; // return lRet; } #if NO lTotalPackageLength += strXml.Length; if (string.IsNullOrEmpty(strMetadata) == false) { lTotalPackageLength += strMetadata.Length; } if (baTimestamp != null) { lTotalPackageLength += baTimestamp.Length * 2; } if (lTotalPackageLength > QUOTA_SIZE && i > 0) { // 响应包的尺寸已经超过 1M,并且已经至少包含了一条记录 break; } #endif record.RecordBody = new RecordBody(); record.RecordBody.Xml = strXml; record.RecordBody.Metadata = strMetadata; record.RecordBody.Timestamp = baTimestamp; } if (bKeyID == true) { // string strID = ""; string strKey = ""; // strID = dpRecord.ID; strKey = dpRecord.BrowseText; /* * string strText = dpRecord.ID; * nRet = strText.LastIndexOf(","); * if (nRet != -1) * { * strKey = strText.Substring(0, nRet); * strID = strText.Substring(nRet + 1); * } * else * strID = strText; * */ if (bHasID == true) { // GetCaptionSafety()函数先找到指定语言的库名; // 如果没有找到,就找截短形态的语言的库名; // 再找不到,就用第一种语言的库名。 // 如果连一种语言也没有,则返回库id record.Path = db.GetCaptionSafety(strLang) + "/" + path.CompressedID; // lTotalPackageLength += record.Path.Length; } if (bHasKey == true) { record.Keys = BuildKeyFromArray(strKey); // lTotalPackageLength += GetLength(record.Keys); } if (bHasCols == true) { string[] cols; nRet = db.GetCols( strFormat, path.ID10, strXml, 0, out cols); // 2013/1/14 if (nRet == -1) { if (cols != null && cols.Length > 0) { strError = cols[0]; } else { strError = "GetCols() error"; } return(-1); } record.Cols = cols; // lTotalPackageLength += nRet; } goto CONTINUE; } { if (bHasID == true) { // GetCaptionSafety()函数先找到指定语言的库名; // 如果没有找到,就找截短形态的语言的库名; // 再找不到,就用第一种语言的库名。 // 如果连一种语言也没有,则返回库id record.Path = db.GetCaptionSafety(strLang) + "/" + path.CompressedID; // lTotalPackageLength += record.Path.Length; } // 在不是keyid的风格下(例如keycount,空),cols全部是浏览列 if (bHasCols == true) { string[] cols; nRet = db.GetCols( strFormat, path.ID10, strXml, 0, out cols); // 2013/1/14 if (nRet == -1) { if (cols != null && cols.Length > 0) { strError = cols[0]; } else { strError = "GetCols() error"; } return(-1); } record.Cols = cols; // lTotalPackageLength += nRet; } } CONTINUE: lTotalPackageLength += GetLength(record); if (lTotalPackageLength > QUOTA_SIZE && i > 0) { // 响应包的尺寸已经超过 1M,并且已经至少包含了一条记录 break; } // records[i] = record; results.Add(record); Thread.Sleep(0); // 降低CPU耗用? } records = new Record[results.Count]; results.CopyTo(records); return(resultSet.Count); }
// 初始化一个读者库的指纹缓存 // return: // -1 出错 // >=0 实际发送给接口程序的事项数目 static int BuildOneDbCache( LibraryChannel channel, string strDir, string strReaderDbName, CancellationToken token, out string strError) { strError = ""; int nRet = 0; DpResultSet resultset = null; bool bCreate = false; Hashtable timestamp_table = new Hashtable(); // recpath --> fingerprint timestamp ShowMessage(strReaderDbName); // 结果集文件名 string strResultsetFilename = Path.Combine(strDir, strReaderDbName); if (File.Exists(strResultsetFilename) == false) { resultset = new DpResultSet(false, false); resultset.Create(strResultsetFilename, strResultsetFilename + ".index"); bCreate = true; } else { bCreate = false; } // *** 第一阶段, 创建新的结果集文件;或者获取全部读者记录中的指纹时间戳 bool bDone = false; // 创建情形下 是否完成了写入操作 try { /* * long lRet = Channel.SearchReader(stop, * strReaderDbName, * "1-9999999999", * -1, * "__id", * "left", * this.Lang, * null, // strResultSetName * "", // strOutputStyle * out strError); */ long lRet = channel.SearchReader(null, // stop, strReaderDbName, "", -1, "指纹时间戳", "left", ClientInfo.Lang, null, // strResultSetName "", // strOutputStyle out strError); if (lRet == -1) { if (channel.ErrorCode == ErrorCode.AccessDenied) { strError = "用户 " + channel.UserName + " 权限不足: " + strError; } return(-1); } if (lRet == 0) { // TODO: 这时候如果以前有结果集文件还会残留,但不会影响功能正确性,可以改进为把残留的结果集文件删除 return(0); } long lHitCount = lRet; ResultSetLoader loader = new ResultSetLoader(channel, null, null, bCreate == true ? "id,cols,format:cfgs/browse_fingerprint" : "id,cols,format:cfgs/browse_fingerprinttimestamp", ClientInfo.Lang); loader.Prompt += Loader_Prompt; foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader) { token.ThrowIfCancellationRequested(); ShowMessage("正在处理读者记录 " + record.Path); if (bCreate == true) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; return(-1); } if (string.IsNullOrEmpty(record.Cols[0]) == true) { continue; // 读者记录中没有指纹信息 } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } else { if (record.Cols == null || record.Cols.Length < 1) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprinttimestamp"; return(-1); } if (record.Cols.Length < 2) { strError = "record.Cols error ... 需要刷新配置文件 cfgs/browse_fingerprinttimestamp 到最新版本"; return(-1); } if (string.IsNullOrEmpty(record.Cols[0]) == true) { continue; // 读者记录中没有指纹信息 } // 记载时间戳 // timestamp | barcode timestamp_table[record.Path] = record.Cols[0] + "|" + record.Cols[1]; } } #if NO // stop.SetProgressRange(0, lHitCount); long lStart = 0; long lCount = lHitCount; DigitalPlatform.LibraryClient.localhost.Record[] searchresults = null; // 装入浏览格式 for (; ;) { token.ThrowIfCancellationRequested(); lRet = channel.GetSearchResult( null, null, // strResultSetName lStart, lCount, bCreate == true ? "id,cols,format:cfgs/browse_fingerprint" : "id,cols,format:cfgs/browse_fingerprinttimestamp", ClientInfo.Lang, out searchresults, out strError); if (lRet == -1) { return(-1); } if (lRet == 0) { strError = "GetSearchResult() return 0"; return(-1); } Debug.Assert(searchresults != null, ""); Debug.Assert(searchresults.Length > 0, ""); for (int i = 0; i < searchresults.Length; i++) { DigitalPlatform.LibraryClient.localhost.Record record = searchresults[i]; if (bCreate == true) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; return(-1); } if (string.IsNullOrEmpty(record.Cols[0]) == true) { continue; // 读者记录中没有指纹信息 } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } else { if (record.Cols == null || record.Cols.Length < 1) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprinttimestamp"; return(-1); } if (record.Cols.Length < 2) { strError = "record.Cols error ... 需要刷新配置文件 cfgs/browse_fingerprinttimestamp 到最新版本"; return(-1); } if (string.IsNullOrEmpty(record.Cols[0]) == true) { continue; // 读者记录中没有指纹信息 } // 记载时间戳 // timestamp | barcode timestamp_table[record.Path] = record.Cols[0] + "|" + record.Cols[1]; } } lStart += searchresults.Length; lCount -= searchresults.Length; //stop.SetMessage(strReaderDbName + " 包含记录 " + lHitCount.ToString() + " 条,已装入 " + lStart.ToString() + " 条"); if (lStart >= lHitCount || lCount <= 0) { break; } //stop.SetProgressValue(lStart); } #endif if (bCreate == true) { bDone = true; } if (bCreate == true) { // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // >=0 实际发送给接口程序的事项数目 nRet = CreateFingerprintCache(resultset, out strError); if (nRet == -1 || nRet == -2) { return(-1); } return(nRet); } } finally { if (bCreate == true) { Debug.Assert(resultset != null, ""); if (bDone == true) { resultset.Detach(out string strTemp1, out string strTemp2); } else { // 否则文件会被删除 resultset.Close(); } } } // 比对时间戳,更新结果集文件 Hashtable update_table = new Hashtable(); // 需要更新的事项。recpath --> 1 resultset = new DpResultSet(false, false); resultset.Attach(strResultsetFilename, strResultsetFilename + ".index"); try { long nCount = resultset.Count; for (long i = 0; i < nCount; i++) { token.ThrowIfCancellationRequested(); DpRecord record = resultset[i]; string strRecPath = record.ID; ShowMessage("比对 " + strRecPath); // timestamp | barcode string strNewTimestamp = (string)timestamp_table[strRecPath]; if (strNewTimestamp == null) { // 最新状态下,读者记录已经不存在,需要从结果集中删除 resultset.RemoveAt((int)i); i--; nCount--; continue; } // 拆分出证条码号 2013/1/28 string strNewBarcode = ""; nRet = strNewTimestamp.IndexOf("|"); if (nRet != -1) { strNewBarcode = strNewTimestamp.Substring(nRet + 1); strNewTimestamp = strNewTimestamp.Substring(0, nRet); } // 最新读者记录中已经没有指纹信息。例如读者记录中的指纹元素被删除了 if (string.IsNullOrEmpty(strNewTimestamp) == true) { // 删除现有事项 resultset.RemoveAt((int)i); i--; nCount--; timestamp_table.Remove(strRecPath); continue; } // 取得结果集文件中的原有时间戳字符串 string strText = record.BrowseText; // timestamp | barcode | fingerprint nRet = strText.IndexOf("|"); if (nRet == -1) { strError = "browsetext 错误,没有 '|' 字符"; return(-1); } string strOldTimestamp = strText.Substring(0, nRet); // timestamp | barcode | fingerprint string strOldBarcode = strText.Substring(nRet + 1); nRet = strOldBarcode.IndexOf("|"); if (nRet != -1) { strOldBarcode = strOldBarcode.Substring(0, nRet); } // 时间戳发生变化,需要更新事项 if (strNewTimestamp != strOldTimestamp || strNewBarcode != strOldBarcode) { // 如果证条码号为空,无法建立对照关系,要跳过 if (string.IsNullOrEmpty(strNewBarcode) == false) { update_table[strRecPath] = 1; } // 删除现有事项 resultset.RemoveAt((int)i); i--; nCount--; } timestamp_table.Remove(strRecPath); } // 循环结束后,timestamp_table中剩余的是当前结果集文件中没有包含的那些读者记录路径 if (update_table.Count > 0) { // 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 AppendFingerprintInfo( channel, resultset, update_table, token); } // 如果服务器端新增了指纹信息,需要获取后追加到结果集文件尾部 if (timestamp_table.Count > 0) { // 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 AppendFingerprintInfo( channel, resultset, timestamp_table, token); } // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // >=0 实际发送给接口程序的事项数目 nRet = CreateFingerprintCache(resultset, out strError); if (nRet == -1 || nRet == -2) { return(-1); } return(nRet); } finally { resultset.Detach(out string strTemp1, out string strTemp2); } }
const int MAX_COUNT_PER_GET = 100; // 每次最多可以获取的行数 // 获得任务当前信息 // 多线程:安全 // parameters: // bDisplayAllIP 是否显示全部IP地址。如果为false,表示只显示访客的IP地址,并且是掩盖部分的 // return: // -1 error // 0 file not found // 1 succeed public int GetInfo( string strDate, long nStart, long nCount, bool bDisplayAllIP, out ChatInfo info, out string strError) { strError = ""; info = null; if (strDate != this.Date) { // 要获得不是当天的内容 string strFileName = PathUtil.MergePath(DataDirectory, strDate); if (File.Exists(strFileName) == false) { strError = "日期为 '" + strDate + "' 的文件不存在"; return(0); } DpResultSet resultset = new DpResultSet(false, false); resultset.Attach(strFileName, strFileName + ".index"); try { info = GetInfo( resultset, nStart, nCount, bDisplayAllIP); } finally { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } FileInfo fi = new FileInfo(strFileName); info.ResultVersion = fi.LastWriteTimeUtc.Ticks; return(1); } else { m_lock.EnterReadLock(); try { // 打开当天的内容文件 int nRet = PrepareContentFileName(out strError); if (nRet == -1) { return(-1); } #if NO ChatInfo info = new ChatInfo(); info.Name = this.Name; long nMax = 0; if (nCount == -1) { nMax = m_resultset.Count; } else { nMax = Math.Min(m_resultset.Count, nStart + nCount); } if (nMax - nStart > MAX_COUNT_PER_GET) { nMax = nStart + MAX_COUNT_PER_GET; } string strResult = ""; for (long i = nStart; i < nMax; i++) { DpRecord record = m_resultset[i]; if (bDisplayAllIP == true) { strResult += record.BrowseText; } else { strResult += RemoveIP(record.BrowseText); } } info.ResultText = strResult; info.NextStart = nMax; // 结束位置 info.TotalLines = m_resultset.Count; info.ResultVersion = this.ContentFileVersion; return(info); #endif info = GetInfo( this.m_resultset, nStart, nCount, bDisplayAllIP); return(1); } finally { m_lock.ExitReadLock(); } } }
// 创建二级节点 // parameters: // strPureFilename 一级节点的结果集纯文件名。用于构造定位信息 // strConverStyle 对 key 字符串的加工方法 static int BuildSegments( string strSubNodeFilename, string strPureFilename, NodeInfo info, KeyValueCollection items, string strConvertStyle, out string strError) { strError = ""; List <Segment> segments = new List <Segment>(); KeyValue prev_item = null; int nSegmentCount = 0; // 当前段落中的个数 int i = 0; foreach (KeyValue item in items) { if (string.IsNullOrEmpty(strConvertStyle) == false) { item.Key = ConvertKey(strConvertStyle, item.Key); } if (prev_item == null) { goto CONTINUE; } if (prev_item.Key == item.Key) { } else { if (nSegmentCount > 0) { // 创建一段 segments.Add(new Segment(prev_item.Key, i - nSegmentCount, nSegmentCount)); nSegmentCount = 0; } } CONTINUE: prev_item = item; i++; nSegmentCount++; } // 最后一段 if (nSegmentCount > 0) { segments.Add(new Segment(prev_item.Key, i - nSegmentCount, nSegmentCount)); } info.SubCount = segments.Count; // 创建成一个一个的结果集分段观察命令,写入结果集文件 DpResultSet resultset = new DpResultSet(false, false); resultset.Create(strSubNodeFilename, strSubNodeFilename + ".index"); bool bDone = false; try { foreach (Segment segment in segments) { string strCommand = segment.Start.ToString() + "," + segment.Length.ToString(); DpRecord record = new DpRecord(strCommand); record.BrowseText = segment.Name; resultset.Add(record); } bDone = true; info.SubNodePureName = strPureFilename; return(0); } finally { if (bDone == true) { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } else { // 否则文件会被删除 resultset.Close(); } } }
const int _upload_batchSize = 1000; // 上传结果集每批个数 // 写入 dp2kernel 成为永久结果集 int UploadPermanentResultset(RmsChannel channel, string strResultsetName, DpResultSet resultset, out string strError) { strError = ""; // resultset.Clear(); // testing List <RecordBody> records = new List <RecordBody>(); // 结果集为空,也要在 dp2kernel 端创建一个结果集对象 if (resultset.Count == 0) { long lRet = channel.DoWriteRecords(null, records.ToArray(), "createResultset,name:#" + strResultsetName + ",clear,permanent", out RecordBody[] results, out strError); if (lRet == -1) { return(-1); } return(0); } #if DETAIL_LOG this.WriteErrorLog("开始上传结果集到 dp2kernel"); #endif long lPos = -1; // 中间保持不透明的值 bool bFirst = true; for (long i = 0; i < resultset.Count; i++) { DpRecord dpRecord = null; long lIndex = i; if (lIndex == 0) { dpRecord = resultset.GetFirstRecord( lIndex, false, out lPos); } else { // 取元素比[]操作速度快 dpRecord = resultset.GetNextRecord( ref lPos); } if (dpRecord == null) { break; } RecordBody record = new RecordBody(); record.Path = dpRecord.ID; records.Add(record); if (records.Count >= _upload_batchSize || (i >= resultset.Count - 1 && records.Count > 0)) { this._app_down.Token.ThrowIfCancellationRequested(); #if DETAIL_LOG this.WriteErrorLog("一批 " + records.Count); #endif RecordBody[] results = null; long lRet = channel.DoWriteRecords(null, records.ToArray(), "createResultset,name:#~" + strResultsetName + (bFirst ? ",clear" : ""), out results, out strError); if (lRet == -1) { return(-1); } bFirst = false; records.Clear(); } } // 最后一次执行改名、排序 { long lRet = channel.DoWriteRecords(null, null, "renameResultset,oldname:#~" + strResultsetName + ",newname:#" + strResultsetName + ",permanent,sort", out RecordBody[] results, out strError); if (lRet == -1) { return(-1); } } #if DETAIL_LOG this.WriteErrorLog("结束上传结果集"); #endif return(0); }
// 创建FilterInfo数组 // parameters: // strSelectedPath 选定状态的节点的路径。为 {resultsetname}/{offsetstring} 形态 public static FilterInfo[] BuildFilterInfos( string strBaseResultsetName, long lBaseResultCount, string strSelectedPath, // Hashtable keyname_table, GetCaption func_getcaption, List <NodeInfo> nodeinfos, string strTempDir, int nMaxSubNodeCount) { List <FilterInfo> results = new List <FilterInfo>(); string strSelectedResultsetName = ""; string strSelectedOffset = ""; ParseSelectedPath(strSelectedPath, out strSelectedResultsetName, out strSelectedOffset); if (string.IsNullOrEmpty(strBaseResultsetName) == false) { // 初始结果集 FilterInfo info = new FilterInfo(); results.Add(info); info.Name = func_getcaption("初始结果集"); info.Count = lBaseResultCount.ToString(); info.Url = "./searchbiblio.aspx?base=" + HttpUtility.UrlEncode(strBaseResultsetName); if (string.IsNullOrEmpty(strSelectedPath) == true) { info.Selected = true; } } foreach (NodeInfo node in nodeinfos) { // 一级节点 FilterInfo info = new FilterInfo(); results.Add(info); // 将内部名字翻译为当前语言的名字 info.Name = func_getcaption(node.Name); info.Count = node.Count.ToString(); info.Url = "./searchbiblio.aspx?resultset=" + HttpUtility.UrlEncode(node.ResultSetPureName) + "&base=" + HttpUtility.UrlEncode(strBaseResultsetName) + "&title=" + HttpUtility.UrlEncode(RemoveHead(info.Name)); if (string.IsNullOrEmpty(strSelectedOffset) == true) { if (strSelectedResultsetName == node.ResultSetPureName) { info.Selected = true; } } // 一级节点的下级导航信息 info.Type = node.SubNodePureName + "," + node.SubCount + "," + node.SubStart; // 二级节点 if (node.SubCount > 0 && string.IsNullOrEmpty(node.SubNodePureName) == false) { string strResultsetFilename = Path.Combine(strTempDir, node.SubNodePureName); List <FilterInfo> sub_results = new List <FilterInfo>(); // 如果起始位置不是0 if (node.SubStart > 0) { FilterInfo sub_info = new FilterInfo(); sub_results.Add(sub_info); int nStart = node.SubStart - nMaxSubNodeCount; if (nStart < 0) { nStart = 0; } sub_info.Name = "前页..."; sub_info.Count = ""; sub_info.Url = node.SubNodePureName + "," + nStart.ToString(); sub_info.Type = "nav"; // 表示导航命令 } int nTail = Math.Min(node.SubStart + nMaxSubNodeCount, node.SubCount); { DpResultSet resultset = new DpResultSet(false, false); resultset.Attach(strResultsetFilename, strResultsetFilename + ".index"); try { for (int i = node.SubStart; i < nTail; i++) { DpRecord record = resultset[i]; string strOffset = record.ID; string[] parts = strOffset.Split(new char[] { ',' }); if (parts.Length != 2) { continue; } FilterInfo sub_info = new FilterInfo(); sub_results.Add(sub_info); sub_info.Index = (i + 1).ToString(); sub_info.Name = record.BrowseText; sub_info.Count = parts[1]; sub_info.Url = "./searchbiblio.aspx?resultset=" + HttpUtility.UrlEncode(node.ResultSetPureName) + "&offset=" + strOffset + "&base=" + HttpUtility.UrlEncode(strBaseResultsetName) + "&title=" + HttpUtility.UrlEncode(RemoveHead(info.Name) + "/" + sub_info.Name); if (string.IsNullOrEmpty(strSelectedOffset) == false && strSelectedResultsetName == node.ResultSetPureName && strSelectedOffset == strOffset) { sub_info.Selected = true; } } } finally { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } } // 如果没有显示完,则最后包含一个翻页或者延展的锚点 if (nTail < node.SubCount) { FilterInfo sub_info = new FilterInfo(); sub_results.Add(sub_info); sub_info.Name = "更多..."; sub_info.Count = ""; // sub_info.Url = "./searchbiblio.aspx?resultset=" + HttpUtility.UrlEncode(node.SubNodePureName) + "&more=" + nMaxSubNodeCount.ToString(); sub_info.Url = node.SubNodePureName + "," + nTail.ToString(); sub_info.Type = "nav"; // 表示导航命令 if (strSelectedResultsetName == node.ResultSetPureName && strSelectedOffset == "nav") { sub_info.Selected = true; } } else { // 如果“更多”没有显示出来,则把选择点定位到最后一个元素 if (strSelectedResultsetName == node.ResultSetPureName && strSelectedOffset == "nav" && sub_results.Count > 0) { sub_results[sub_results.Count - 1].Selected = true; } } #if NO info.Children = new FilterInfo[sub_results.Count]; sub_results.CopyTo(info.Children); #endif info.Children = sub_results.ToArray(); } } // 对results中的对象进行排序 results.Sort(new FilterInfoComparer()); // 去掉名字中的{}部分 foreach (FilterInfo info in results) { string strName = info.Name; info.Name = RemoveHead(strName); } #if NO FilterInfo[] a = new FilterInfo[results.Count]; results.CopyTo(a); return(a); #endif return(results.ToArray()); }
// 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 static void AppendFingerprintInfo( LibraryChannel channel, DpResultSet resultset, Hashtable update_table, CancellationToken token) { List <string> lines = new List <string>(); foreach (string recpath in update_table.Keys) { lines.Add(recpath); } BrowseLoader loader = new BrowseLoader(); loader.RecPaths = lines; loader.Channel = channel; loader.Format = "id,cols,format:cfgs/browse_fingerprint"; loader.Prompt += Loader_Prompt; foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader) { token.ThrowIfCancellationRequested(); ShowMessage("追加 " + record.Path); if (record.Cols == null || record.Cols.Length < 3) { string strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; // TODO: 并发操作的情况下,会在中途出现读者记录被别的前端修改的情况,这里似乎可以continue throw new Exception(strError); } // 如果证条码号为空,无法建立对照关系,要跳过 if (string.IsNullOrEmpty(record.Cols[1]) == true) { continue; } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } #if NO // 需要获得更新的事项,然后追加到结果集文件的尾部 // 注意,需要定期彻底重建结果集文件,以便回收多余空间 List <string> lines = new List <string>(); foreach (string recpath in update_table.Keys) { lines.Add(recpath); if (lines.Count >= 100) { List <DigitalPlatform.LibraryClient.localhost.Record> records = null; GetSomeFingerprintData( channel, lines, token, out records); foreach (DigitalPlatform.LibraryClient.localhost.Record record in records) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; // TODO: 并发操作的情况下,会在中途出现读者记录被别的前端修改的情况,这里似乎可以continue return(-1); } // 如果证条码号为空,无法建立对照关系,要跳过 if (string.IsNullOrEmpty(record.Cols[1]) == true) { continue; } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } lines.Clear(); } } if (lines.Count > 0) { List <DigitalPlatform.LibraryClient.localhost.Record> records = null; GetSomeFingerprintData( channel, lines, token, out records); foreach (DigitalPlatform.LibraryClient.localhost.Record record in records) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; // TODO: 并发操作的情况下,会在中途出现读者记录被别的前端修改的情况,这里似乎可以continue return(-1); } DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } } return(0); #endif }
// 外部调用 public static int AddToResultset(List<string> aPath, string strResultsetFilename, bool bInsertAtFirst, out string strError) { strError = ""; DpResultSet resultset = null; bool bCreate = false; try { if (File.Exists(strResultsetFilename) == true) { resultset = new DpResultSet(false, false); resultset.Attach(strResultsetFilename, strResultsetFilename + ".index"); } else { bCreate = true; resultset = new DpResultSet(false, false); resultset.Create(strResultsetFilename, strResultsetFilename + ".index"); } } catch (Exception ex) { strError = (bCreate == true ? "创建" : "打开") + "结果集(文件为'" + strResultsetFilename + "')发生错误: " + ex.Message; return -1; } bool bDone = false; try { for (int j = 0; j < aPath.Count; j++) { Thread.Sleep(1); DpRecord record = new DpRecord(aPath[j]); if (bInsertAtFirst == true) resultset.Insert(0, record); else resultset.Add(record); } bDone = true; } finally { if (bDone == true || bCreate == false) { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } else { // 否则文件会被删除 resultset.Close(); } } return 0; }
// 从结果集中提取指定范围的记录 // parameter: // strRanges 范围 // strStyle 样式,以逗号分隔,id:表示取id,cols表示取浏览格式,xml表示取xml记录体 // strLang 语言版本,用来获得记录路径 // richRecords 得到的记录数组,成员为类型为Record // result: // -1 出错 // >=0 结果集的总数 public long API_GetRichRecords( DpResultSet resultset, string strRanges, string strLang, string strStyle, out RichRecord[] richRecords, out string strError) { strError = ""; richRecords = null; int nCurCount = 0; List <RichRecord> aRichRecord = new List <RichRecord>(); string strFormat = StringUtil.GetStyleParam(strStyle, "format"); RangeList rangeList = new RangeList(strRanges); for (int i = 0; i < rangeList.Count; i++) { RangeItem rangeItem = (RangeItem)rangeList[i]; int nStart = (int)rangeItem.lStart; int nLength = (int)rangeItem.lLength; if (nLength == 0) { continue; } // long lPos = 0; // 应该用快速方式,不应用[]??? 2006/3/29 for (int j = 0; j < nLength; j++) { int nRet = 0; DpRecord dpRecord = resultset[j + nStart]; RichRecord richRecord = new RichRecord(); DbPath dbpath = new DbPath(dpRecord.ID); Database db = this.app.Dbs.GetDatabaseSafety(dbpath.Name); if (db == null) //也应放到本条的记录出错信息里 { strError = "没有找到数据库'" + dbpath.Name + "',换语言版本时出错"; richRecord.Result.Value = -1; richRecord.Result.ErrorCode = KernelApplication.Ret2ErrorCode(nRet); richRecord.Result.ErrorString = strError; } else { // 记录路径 if (StringUtil.IsInList("id", strStyle, true) == true || StringUtil.IsInList("path", strStyle, true) == true) { richRecord.Path = db.GetCaptionSafety(strLang) + "/" + dbpath.CompressedID; } // 浏览列 if (StringUtil.IsInList("cols", strStyle, true) == true) { string[] cols = null; nRet = db.GetCols( strFormat, dbpath.ID10, "", 0, out cols); // 2013/1/14 if (nRet == -1) { if (cols != null && cols.Length > 0) { strError = cols[0]; } else { strError = "GetCols() error"; } return(-1); } richRecord.Cols = cols; } bool bXml = false; bool bTimestamp = false; if (StringUtil.IsInList("xml", strStyle, true) == true) { bXml = true; } if (StringUtil.IsInList("timestamp", strStyle, true) == true) { bTimestamp = true; } if (bXml == true || bTimestamp == true) { string strGetStyle = ""; //"data,timestamp"; // ,outputpath, metadata if (bTimestamp == true) { StringUtil.SetInList(ref strGetStyle, "timestamp", true); } if (bXml == true) { StringUtil.SetInList(ref strGetStyle, "data", true); } int nStart0 = 0; int nLength0 = -1; int nMaxLength = 300 * 1024; // 每次最多获取300K int nTotalLength = 0; string strOutputID = ""; byte[] baTotal = null; byte[] baOutputTimestamp = null; int nAdditionError = 0; string strMetadata = ""; for (; ;) { byte[] baData = null; long lRet = db.GetXml(dbpath.ID, "", // strXPath, nStart0, nLength0, nMaxLength, strGetStyle, out baData, out strMetadata, out strOutputID, out baOutputTimestamp, true, out nAdditionError, out strError); if (lRet <= -1) { richRecord.Result.Value = -1; richRecord.Result.ErrorCode = KernelApplication.Ret2ErrorCode(nAdditionError); // nRet? richRecord.Result.ErrorString = strError; goto CONTINUE; } nTotalLength = (int)lRet; // 如果数据体太大 if (nTotalLength > QUOTA_SIZE) { richRecord.Result.Value = -1; richRecord.Result.ErrorCode = ErrorCodeValue.CommonError; richRecord.Result.ErrorString = "数据超过1M"; goto CONTINUE; } baTotal = ByteArray.Add(baTotal, baData); nStart0 += baData.Length; if (nStart0 >= nTotalLength) { break; } } // 记录体 // 转换成字符串 if (StringUtil.IsInList("xml", strStyle, true) == true) { richRecord.Xml = ByteArray.ToString(baTotal); } // 时间戳? if (StringUtil.IsInList("timestamp", strStyle, true) == true) { richRecord.baTimestamp = baOutputTimestamp; } // string strOutputPath = strDbName + "/" + strOutputID; } // 记录体 if (StringUtil.IsInList("xml", strStyle, true) == true) { /* * nRet = db.GetXmlDataSafety(dbpath.ID, * out richRecord.Xml, * out strError); * if (nRet <= -1) * { * richRecord.Result.Value = -1; * richRecord.Result.ErrorCode = RmswsApplication.Ret2ErrorCode(nRet); * richRecord.Result.ErrorString = strError; * } * */ } } CONTINUE: aRichRecord.Add(richRecord); Thread.Sleep(0); nCurCount++; // 如果超出最大范围,则停止 if (nCurCount >= SessionInfo.MaxRecordsCountPerApi) { break; } } } richRecords = new RichRecord[aRichRecord.Count]; for (int i = 0; i < richRecords.Length; i++) { richRecords[i] = aRichRecord[i]; } return(resultset.Count); }
// 初始化一个读者库的指纹缓存 // return: // -1 出错 // >=0 实际发送给接口程序的事项数目 int BuildOneDbCache( string strReaderDbName, out string strError) { strError = ""; int nRet = 0; DpResultSet resultset = null; bool bCreate = false; Hashtable timestamp_table = new Hashtable(); // recpath --> fingerprint timestamp string strDir = this.MainForm.FingerPrintCacheDir; // PathUtil.MergePath(this.MainForm.DataDir, "fingerprintcache"); PathUtil.CreateDirIfNeed(strDir); // 结果集文件名 string strResultsetFilename = PathUtil.MergePath(strDir, strReaderDbName); if (File.Exists(strResultsetFilename) == false) { resultset = new DpResultSet(false, false); resultset.Create(strResultsetFilename, strResultsetFilename + ".index"); bCreate = true; } else bCreate = false; // *** 第一阶段, 创建新的结果集文件;或者获取全部读者记录中的指纹时间戳 bool bDone = false; // 创建情形下 是否完成了写入操作 try { /* long lRet = Channel.SearchReader(stop, strReaderDbName, "1-9999999999", -1, "__id", "left", this.Lang, null, // strResultSetName "", // strOutputStyle out strError); */ long lRet = Channel.SearchReader(stop, strReaderDbName, "", -1, "指纹时间戳", "left", this.Lang, null, // strResultSetName "", // strOutputStyle out strError); if (lRet == -1) { if (Channel.ErrorCode == ErrorCode.AccessDenied) strError = "用户 "+Channel.UserName+" 权限不足: " + strError; return -1; } if (lRet == 0) { // TODO: 这时候如果以前有结果集文件还会残留,但不会影响功能正确性,可以改进为把残留的结果集文件删除 return 0; } long lHitCount = lRet; stop.SetProgressRange(0, lHitCount); long lStart = 0; long lCount = lHitCount; DigitalPlatform.CirculationClient.localhost.Record[] searchresults = null; // 装入浏览格式 for (; ; ) { Application.DoEvents(); // 出让界面控制权 if (stop != null && stop.State != 0) { strError = "用户中断"; return -1; } lRet = Channel.GetSearchResult( stop, null, // strResultSetName lStart, lCount, bCreate == true ? "id,cols,format:cfgs/browse_fingerprint" : "id,cols,format:cfgs/browse_fingerprinttimestamp", this.Lang, out searchresults, out strError); if (lRet == -1) return -1; if (lRet == 0) { strError = "GetSearchResult() return 0"; return -1; } Debug.Assert(searchresults != null, ""); Debug.Assert(searchresults.Length > 0, ""); for (int i = 0; i < searchresults.Length; i++) { DigitalPlatform.CirculationClient.localhost.Record record = searchresults[i]; if (bCreate == true) { if (record.Cols == null || record.Cols.Length < 3) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprint"; return -1; } if (string.IsNullOrEmpty(record.Cols[0]) == true) continue; // 读者记录中没有指纹信息 DpRecord item = new DpRecord(record.Path); // timestamp | barcode | fingerprint item.BrowseText = record.Cols[0] + "|" + record.Cols[1] + "|" + record.Cols[2]; resultset.Add(item); } else { if (record.Cols == null || record.Cols.Length < 1) { strError = "record.Cols error ... 有可能是因为读者库缺乏配置文件 cfgs/browse_fingerprinttimestamp"; return -1; } if (record.Cols.Length < 2) { strError = "record.Cols error ... 需要刷新配置文件 cfgs/browse_fingerprinttimestamp 到最新版本"; return -1; } if (string.IsNullOrEmpty(record.Cols[0]) == true) continue; // 读者记录中没有指纹信息 // 记载时间戳 // timestamp | barcode timestamp_table[record.Path] = record.Cols[0] + "|" + record.Cols[1]; } } lStart += searchresults.Length; lCount -= searchresults.Length; stop.SetMessage(strReaderDbName + " 包含记录 " + lHitCount.ToString() + " 条,已装入 " + lStart.ToString() + " 条"); if (lStart >= lHitCount || lCount <= 0) break; stop.SetProgressValue(lStart); } if (bCreate == true) bDone = true; if (bCreate == true) { // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // >=0 实际发送给接口程序的事项数目 nRet = CreateFingerprintCache(resultset, out strError); if (nRet == -1 || nRet == -2) return -1; return nRet; } } finally { if (bCreate == true) { Debug.Assert(resultset != null, ""); if (bDone == true) { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } else { // 否则文件会被删除 resultset.Close(); } } } // 比对时间戳,更新结果集文件 Hashtable update_table = new Hashtable(); // 需要更新的事项。recpath --> 1 resultset = new DpResultSet(false, false); resultset.Attach(strResultsetFilename, strResultsetFilename + ".index"); try { long nCount = resultset.Count; for (long i = 0; i < nCount; i++) { DpRecord record = resultset[i]; string strRecPath = record.ID; // timestamp | barcode string strNewTimestamp = (string)timestamp_table[strRecPath]; if (strNewTimestamp == null) { // 最新状态下,读者记录已经不存在,需要从结果集中删除 resultset.RemoveAt((int)i); i--; nCount--; continue; } // 拆分出证条码号 2013/1/28 string strNewBarcode = ""; nRet = strNewTimestamp.IndexOf("|"); if (nRet != -1) { strNewBarcode = strNewTimestamp.Substring(nRet + 1); strNewTimestamp = strNewTimestamp.Substring(0, nRet); } // 最新读者记录中已经没有指纹信息。例如读者记录中的指纹元素被删除了 if (string.IsNullOrEmpty(strNewTimestamp) == true) { // 删除现有事项 resultset.RemoveAt((int)i); i--; nCount--; timestamp_table.Remove(strRecPath); continue; } // 取得结果集文件中的原有时间戳字符串 string strText = record.BrowseText; // timestamp | barcode | fingerprint nRet = strText.IndexOf("|"); if (nRet == -1) { strError = "browsetext 错误,没有 '|' 字符"; return -1; } string strOldTimestamp = strText.Substring(0, nRet); // timestamp | barcode | fingerprint string strOldBarcode = strText.Substring(nRet + 1); nRet = strOldBarcode.IndexOf("|"); if (nRet != -1) { strOldBarcode = strOldBarcode.Substring(0, nRet); } // 时间戳发生变化,需要更新事项 if (strNewTimestamp != strOldTimestamp || strNewBarcode != strOldBarcode) { // 如果证条码号为空,无法建立对照关系,要跳过 if (string.IsNullOrEmpty(strNewBarcode) == false) update_table[strRecPath] = 1; // 删除现有事项 resultset.RemoveAt((int)i); i--; nCount--; } timestamp_table.Remove(strRecPath); } // 循环结束后,timestamp_table中剩余的是当前结果集文件中没有包含的那些读者记录路径 if (update_table.Count > 0) { // 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 nRet = AppendFingerprintInfo(resultset, update_table, out strError); if (nRet == -1) return -1; } // 如果服务器端新增了指纹信息,需要获取后追加到结果集文件尾部 if (timestamp_table.Count > 0) { // 获取指纹信息,追加到结果集文件的尾部 // parameters: // update_table key为读者记录路径 nRet = AppendFingerprintInfo(resultset, timestamp_table, out strError); if (nRet == -1) return -1; } // return: // -2 remoting服务器连接失败。驱动程序尚未启动 // -1 出错 // >=0 实际发送给接口程序的事项数目 nRet = CreateFingerprintCache(resultset, out strError); if (nRet == -1 || nRet == -2) return -1; return nRet; } finally { string strTemp1 = ""; string strTemp2 = ""; resultset.Detach(out strTemp1, out strTemp2); } }