葉水全
摘要:結(jié)合測繪成果管理中需要處理大量EDB文件,針對文件存儲空間的大小問題以及分發(fā)的效率進行了思考與總結(jié)。通過對原有大比例尺地形圖的存儲進行了優(yōu)化,針對EDB文件的格式特點,提出一種新的壓縮和管理方法,即用Oracle 11g數(shù)據(jù)庫和7z壓縮技術(shù),提高測繪檔案管理中大比例尺地形圖的分發(fā)速度,降低了數(shù)據(jù)管理的存儲需求。為今后相關(guān)工作的開展提供了較大的便利與可靠的支持。
關(guān)鍵詞:EDB文件;7Z壓縮;Oracle數(shù)據(jù)庫存儲;C++開發(fā)
一、前言
從2005年開始,重慶市勘測院全面使用北京山維科技股份有限公司的EPS地理信息工作站進行大比例尺1∶500地形圖采集與存儲。作為其數(shù)據(jù)保存的主要形式,檔案管理工作中積累了數(shù)量龐大的EDB文件(*.edb),包括工程項目文件和國家標(biāo)準基本比例尺文件,其年度歸檔數(shù)已超過10萬,每年的存儲空間增長量接近1TB。這種小文件形式的文件存儲,不僅會造成存儲空間的迅速擴大,更會影響后期數(shù)據(jù)的分發(fā)效率。在檔案搜索和分發(fā)時,相同的大比例尺文件名存在多個時期的多個版本,數(shù)據(jù)眾多,且每年度存儲位置分散,加重了數(shù)據(jù)追溯困難。因此,為了方便存儲EDB文件,筆者做了以下優(yōu)化:增加上載入口時的自動冗余清理,按EPS平臺的規(guī)則清理EDB文件中的冗余內(nèi)容,縮小數(shù)據(jù)大?。皇褂?z壓縮技術(shù),在傳輸和存儲過程中進一步縮小數(shù)據(jù)大小;使用Oracle數(shù)據(jù)庫存儲EDB文件。
二、功能實現(xiàn)
(一)EDB冗余清理
EDB格式作為EPS地理信息工作站數(shù)據(jù)承載格式,其底層是一個Access數(shù)據(jù)庫,使用GeoPointTB、GeoLineTB、GeoAreaTB表存儲圖形數(shù)據(jù),使用MarkNoteTB表存儲注記數(shù)據(jù),使用UserLayerTB、AttrLinkInfoTB表管理圖形關(guān)聯(lián)屬性表,使用FeatureCode、SymbolScriptTB、NoteTemplateTB表實現(xiàn)圖形符號化[1]。EPS地理信息工作站為防止采集和編繪過程中數(shù)據(jù)因故障丟失,每條數(shù)據(jù)記錄都真實地保存至上述表格。同時,為保證整個加工過程的可追述,整個數(shù)據(jù)記錄過程都是增量的,即數(shù)據(jù)存入表格后將永遠存在而不會刪除。在用戶視角的軟件操作窗口中,需要表達一個對象刪除時,“刪除”動作在數(shù)據(jù)存儲的底層映射為對象的Mark屬性值做累加運算;如果用戶有回退操作則可以通過減去累加值完成還原。
于是EDB文件就會越來越大,例如,一個普通的大比例尺文件一般為6Mb,在清理前可能有20Mb,甚至極個別達到30Mb,數(shù)據(jù)存儲量最大增至5~6倍于原文件。歸檔后,采集和編繪的過程操作已經(jīng)完成。為了節(jié)約存儲空間,應(yīng)該將Mark字段標(biāo)記為“刪除”的那些數(shù)據(jù)條目從EDB文件中刪除。此處以DAO(DATA ACESS OBJECTS)方式為例,連接EDB數(shù)據(jù)文件,將表中冗余過程記錄直接刪除,C++核心函數(shù)如下:
Int EDBCompress(CString edbPath){
CDaoDatabase* m_pDB = new CDaoDatabase;
CString strDeleteTab = _T( "DELETE * From [tab] where Mark Mod 2 = 0");
……
strSQL = strDeleteTab;
strSQL.Replace( "[tab]", strTabNames[i]);
m_pDB->Execute( strSQL, dbConsistent );
……
}
(二)7z數(shù)據(jù)壓縮
7-Zip是基于GNU LGPL授權(quán)協(xié)議的開源壓縮軟件[2],可以自由地整合到現(xiàn)有的軟件系統(tǒng)中。它的壓縮格式.7z具有較高的壓縮比,較Zip壓縮格式有30%-70%能力提升,較商業(yè)軟件WinRAR在壓縮比方面也略有優(yōu)勢(圖1),在辦公自動化數(shù)據(jù)集成中一般優(yōu)先使用。
筆者將數(shù)據(jù)解壓縮功能集成到系統(tǒng)中,在7z的SDK開發(fā)文檔中,推薦使用其開源接口SzAr_Extract,其接口如下:
SZ_RESULT SzAr_Extract(
CArchiveDatabaseEx *db,
ILookInStream *inStream,
UInt32 fileIndex,? ? ? ? ?/* index of file */
UInt32 *blockIndex,? ? ? ?/* index of solid block */
Byte **outBuffer,? ? ? ? ?/* pointer to pointer to output buffer */
size_t *outBufferSize,? ? /* buffer size for output buffer */
size_t *offset,? ? ? ? ? ?/* offset of stream for required file in *outBuffer */
size_t *outSizeProcessed, /* size of file in *outBuffer */
ISzAlloc *allocMain,
ISzAlloc *allocTemp
);
為了將內(nèi)存中的7z數(shù)據(jù)生成EDB文件,需要一些定制。在7z的源代碼項目Client7z“7z1900-src\CPP\7zip\UI\Client7z”(7-Zip 19.00為例)里,在Client7Z.cpp補充一個由內(nèi)存至文件的解壓函數(shù),并將此Client7Z項目以lib的形式編譯進入現(xiàn)有系統(tǒng)中即可。補充的內(nèi)存解壓函數(shù)如下:
int decode_memory2f(const Byte * memory_data, size_t memory_size, const char * save_folder) {
……
CBufInStream *bufInStreamSpec = new CBufInStream;
CMyComPtr
bufInStreamSpec->Init(memory_data, memory_size);
CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
CMyComPtr
……
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
CMyComPtr
extractCallbackSpec->Init(archive, folderName);
extractCallbackSpec->PasswordIsDefined = false;
HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
if (result != S_OK) return 2;
return 0;
}
(三)Oracle數(shù)據(jù)庫存儲
原有的數(shù)據(jù)成果以文件的形式保存在服務(wù)器,雖然管理成本低,但再利用的效率不高。筆者依托Oracle數(shù)據(jù)的大數(shù)據(jù)文件的管理能力,在Oracle11g數(shù)據(jù)庫中,按照海量數(shù)據(jù)庫的架構(gòu)創(chuàng)建存儲表[3],按實際的工作節(jié)奏每一年度建一個內(nèi)容存儲表。例如,2020年版的創(chuàng)建表SQL如下:
-- 創(chuàng)建存儲表
CREATE TABLE eps_repos_2020(
id NUMBER(12,0) PRIMARY KEY,
name VARCHAR2(100 char),
data_format VARCHAR2(60 char),
save_format VARCHAR2(60 char),
save_code VARCHAR2(60 char),
blob_chip BLOB,
update_date DATE DEFAULT sysdate NOT NULL
)
并且,在下載時方便復(fù)原EDB文件,需要在Oracle的下載接口中一并使用7z解壓。筆者在Oracle11g數(shù)據(jù)庫接口中使用了Oracle Instant Client連接遠程數(shù)據(jù)庫[4],Oracle OCI(Oracle Call interface)模塊和其輕封裝ocilib(Vincent Roginer)作為開發(fā)模塊[5]。使用Oracle連接池技術(shù),其Oracle連接池子函數(shù)如下:
void fileDw_byPool_subWorker(OCI_Thread *thread, void *data) {
fileDw_byPool_argument * pf = (fileDw_byPool_argument*)data;
OCI_Connection *cn = OCI_PoolGetConnection(pf->pool, NULL);
……
wchar_t name_out = { 0 };
if (false == _download_7zblob(cn, pf->db_object_target, id, pf->savedir, name_out)) {
……
}
OCI_ConnectionFree(cn);
}
其中,數(shù)據(jù)庫BLOB下載函數(shù)如下:
bool _download_7zblob(OCI_Connection *cn, const otext * db_object_target, big_uint id, const otext * savedir, wchar_t * name_out) {
bool rs = false;
const otext sql_format1[] = OTEXT("SELECT blob_chip FROM %s WHERE id = %%lu");
……
if (FALSE != OCI_ImmediateFmt(cn, sql_format2, id, OCI_ARG_LOB, blob)) {
rs = fwrite2_blob_7z_onlyone(blob, savedir, name_out);
//wprintf( L"%s OK\n", name);
}
OCI_LobFree(blob);
return rs;
}
其中,數(shù)據(jù)庫7z解壓為EDB文件的函數(shù)如下:
bool fwrite2_blob_7z_onlyone(OCI_Lob * blob, const otext * savedir, wchar_t * name_out) { // Y.S.Q 2018-05-17
……
unsigned char * buff = new unsigned char[len];
if (FALSE != OCI_LobRead2(blob, buff, &rd, &rd)) {
if (len == rd) {
err = decode_memory2f(buff, len, savedir, name_out);
}
}
……
}
三、測試與性型分析
筆者在Visual Studio 2017創(chuàng)建從數(shù)據(jù)庫下載EDB文件的C++項目fileDw_byPool.vcxproj,并包含Client7z項目的lib和ocilib項目的lib,編譯為exe執(zhí)行程序。其中fdwp32.exe是主程序,7z.dll提供解壓縮功能,fdwp32.xml是數(shù)據(jù)庫的信息及參數(shù),oracle11203目錄是數(shù)據(jù)庫Oracle Instant Client功能目錄。
以下是筆者優(yōu)化后的分發(fā)機制與舊模式的比較:
1.下載速度。隨機選擇了100個EDB文件作為下載清單,在兩臺同配置的普通電腦上,一臺使用舊模式下載數(shù)據(jù),一臺使用優(yōu)化后的下載機制。前者的平均下載時間為14秒(圖2中的單點)。后者基于ORACLE連接池開啟了數(shù)據(jù)庫多線程模式。從圖2(豎軸時間秒,橫軸線程池數(shù))的函數(shù)曲線可以發(fā)現(xiàn),4線程模式時間為6秒,提高了2.5倍的下載速度。
2.存儲空間。以某年度全部基本比例尺EDB文件為例,舊模式下為服務(wù)器文件共享,文件個數(shù)為10.5萬,存儲大小584GB;優(yōu)化后的Oracle數(shù)據(jù)庫表空間大小52GB,約為11倍的存儲空間優(yōu)化。
四、結(jié)語
基本比例尺數(shù)據(jù)的管理一直是重慶市勘測院測繪檔案保管的重要工作。面對數(shù)十年長期積累的大比尺EDB格式數(shù)據(jù)成果,本文分別從存儲空間和分發(fā)效率兩方面入手,按內(nèi)容特性對文件精簡其存儲大??;使用7z壓縮方法進一步降低存儲空間的大小;利用Oracle數(shù)據(jù)庫的線程池技術(shù)優(yōu)化分發(fā)速度。實際訪問效率相比于傳統(tǒng)的文件共享方式快2~3倍,服務(wù)器存儲空間節(jié)約85%以上;與此同時,借用了Oracle數(shù)據(jù)庫的海量存儲能力以及安全訪問機制,提升了測繪成果管理中針對EDB格式的大比例尺數(shù)據(jù)的存儲與分發(fā)能力。
參考文獻
[1]Igor Pavlov.7-Zip SDK[EB/OL].[2021-12-22].https://www.7-zip.org/.
[2]楊亮亮.Oracle數(shù)據(jù)庫處理海量數(shù)據(jù)的技術(shù)分析[J].信息技術(shù)與信息化.2020(11):25-27.
[3]吳政,李成名,等.Oracle數(shù)據(jù)庫矢柵數(shù)據(jù)一體化存儲與管理[J].測繪學(xué)報.2017,46(5):639-648.
[4]ORACLE. Oracle Call Interface Programmer's Guide[EB/OL].[2021-12-22].https://docs.oracle.com/en/database/oracle/oracle-database/21/lnoci/index.html.
[5]Vincent Rogier.C and C++ Driver for Oracle[EB/OL].[2021-12-22].http://vrogier.github.io/ocilib/.