DB Environment

 DB Environment -- Berkeley DB來源: 作者: 時間:2007-12-02 Tag: 點擊: 195 Database environment introduction

Berkeley DB 環境用來封裝一個或多個數據庫,日誌文件和區域文件。區域文件是共享內存區,它裏面包括數據庫環境信息像內存池cache頁等。只有數據庫文件可以在不同的字節序機器間移動,日誌文件只能在相同的字節序機器間移動。而區域文件(Region files)常常對於一個特定的機器來說是獨一無二的,可能只能在指定的操作系統的某個版本上移動間移動。


一個環境可以被很多進程和線程共享。一個環境包含其它目錄的資源也是可能的。應用程序經常選擇把資源分佈到其他目錄或磁盤來提高性能或其他原因。儘管如此,默認的,數據庫,共享區(鎖,日誌,內存池和事務共享內存區域)和日誌文件將存儲在同一個同層次目錄中。

意識到所有應用程序共享一個數據庫環境默認的相信彼此非常重要。他們能訪問對方的數據,因爲那些數據在同一個共享內存區,他們也共享資源像buffer空間和鎖。與此同時,任何應用程序使用同一個數據庫,必須共享一個環境,如果想在他們之間保持一致性的話。
Creating a database environment

環境對於bdb的可移植性和靈活性是非常重要的。爲了增強可移植性,和快速災難恢復,建議儘量使用相對路徑。建議使用配置文件放置環境參數而不要直接寫到程序裏,可以避免每次移植時修改和編譯源文件。

bdb 環境由db_env_create 和 DB_ENV->open接口創建和描述,再需要定製的地方,比如把log文件存儲到不同的磁盤驅動器裏,或選擇一個特殊cache大小,應用程序描述這些定製信息通過創建配置文件,或者傳參數給其他DB_ENV 處理函數。

一旦一個環境被創建,被指定相對路徑的數據庫文件,都將相對與環境的home目錄來創建。用相對目錄允許整個環境輕易的移動。簡化了在不同目錄和不同系統中重建和恢復的步驟。

應用程序首先通過db_env_create方法獲得一個環境句柄,然後調用DB_ENV->open來創建或合併數據庫環境。這兒有很多選項你可以在調用DB_ENV->open時設置來定製你的環境。這些選項大致可以分爲四類:

子系統初始化選項:這些標誌指明哪些bdb子系統將因爲環境被初始化,和哪些操作將自動發生當數據庫在環境中被訪問的時候。這些標誌包括 DB_INIT_CDB, DB_INIT_LOCK, DB_INIT_LOG, DB_INIT_MPOOL, and DB_INIT_TXN。The DB_INIT_CDB標誌爲bdb併發數據存儲做初始化工作。其他標誌初始化單個子系統;也就是說,當DB_INIT_LOCK被指定,應用程序讀寫在這個環境中打開的數據庫時,將使用locking子系統以確保它們不覆蓋對方的對數據的改動。

恢復選項:這些包括DB_RECOVER 和 DB_RECOVER_FATAL選項,他們表明在環境被打開要作正常用途使用前,恢復(recovery)將要進行。

命名選項:這包括DB_USE_ENVIRON 和 DB_USE_ENVIRON_ROOT,修改如何在環境中給文件命名。

混雜選項:例如DB_CREATE選項使底層數據庫文件被創建是必需的。更多的應用還指定
僅僅DB_INIT_MPOOL標誌或者指定其它所有4個子系統的初始化標誌(DB_INIT_MPOOL, DB_INIT_LOCK, DB_INIT_LOG, and DB_INIT_TXN)。

以前的配置只是想簡單的用一些基本的訪問方法接口用一個共享底層緩衝池,但是沒有關心當應用程序或系統出現故障時的可恢復性。以後是一些需要提供可恢復性的應用。也有一些很稀少的情況下,其它的初始化標誌組合成爲可能。


DB_RECOVER在當應用程序想在運行的時做一些必需的數據庫恢復的時候被指定。也就是說,是否在上次運行時,系統或應用程序出現了故障,想在再次運行前使數據恢復到可用狀態。不過,在沒有任何數據需要恢復的情況下,指定這個標誌也不爲錯。

DB_RECOVER_FATAL 標誌有更特殊的用途。它執行災難性的數據庫恢復,通常需要做一些初始化的安排;也就是歸檔log文件被帶回到文件系統。應用程序通常不指定這個標誌,取而代之的是,在這種很稀有的情況下,db_recover 公用程序將會派上用場不用你自己寫。
下面是一個簡單的爲事務程序打開一個數據庫環境的例子:


DB_ENV *
db_setup(home, data_dir, errfp, progname)
char *home, *data_dir, *progname;
FILE *errfp;
{
DB_ENV *dbenv;
int ret;
/*
* Create an environment and initialize it for additional error
* reporting.
*/
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(errfp, "%s: %s/n", progname, db_strerror(ret));
return (NULL);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
/*
* Specify the shared memory buffer pool cachesize: 5MB.
* Databases are in a subdirectory of the environment home.
*/
if ((ret = dbenv->set_cachesize(dbenv, 0, 5 * 1024 * 1024, 0)) != 0) {
dbenv->err(dbenv, ret, "set_cachesize");
goto err;
}
if ((ret = dbenv->set_data_dir(dbenv, data_dir)) != 0) {
dbenv->err(dbenv, ret, "set_data_dir: %s", data_dir);
goto err;
}
/* Open the environment with full transactional support. */
if ((ret = dbenv->open(dbenv, home, DB_CREATE |
  DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN, 0)) != 0) {
dbenv->err(dbenv, ret, "environment open: %s", home);
goto err;
}
return (dbenv);
err: (void)dbenv->close(dbenv, 0);
return (NULL);

Opening databases within the environment

一旦環境被創建,數據庫句柄將可能在這個環境中打開,這由db_create函數通過指定特定的環境作爲參數來實現。
文件命名,數據庫操作,和錯誤處理等都將因爲這個指定的環境而被做。例如,如果DB_INIT_LOCK 或 DB_INIT_CDB 標誌被指定,當環境被創建或被合併時,數據庫操作將爲應用程序自動的執行所有必要的鎖操作。
下面是一個簡單的例子,在一個環境中打開兩個數據庫:
DB_ENV *dbenv;
DB *dbp1, *dbp2;
int ret;
dbenv = NULL;
dbp1 = dbp2 = NULL;
/*
* Create an environment and initialize it for additional error
* reporting.
*/
if ((ret = db_env_create(&dbenv, 0)) != 0) {
fprintf(errfp, "%s: %s/n", progname, db_strerror(ret));
return (ret);
}
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, progname);
/* Open an environment with just a memory pool. */
if ((ret =
  dbenv->open(dbenv, home, DB_CREATE | DB_INIT_MPOOL, 0)) != 0) {
dbenv->err(dbenv, ret, "environment open: %s", home);
goto err;
}
/* Open database #1. */
if ((ret = db_create(&dbp1, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "database create");
goto err;
}
if ((ret = dbp1->open(dbp1,
  NULL, DATABASE1, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbenv->err(dbenv, ret, "DB->open: %s", DATABASE1);
goto err;
}
/* Open database #2. */
if ((ret = db_create(&dbp2, dbenv, 0)) != 0) {
dbenv->err(dbenv, ret, "database create");
goto err;
}
if ((ret = dbp2->open(dbp2,
  NULL, DATABASE2, NULL, DB_HASH, DB_CREATE, 0664)) != 0) {
dbenv->err(dbenv, ret, "DB->open: %s", DATABASE2);
goto err;
}
return (0);
err: if (dbp2 != NULL)
(void)dbp2->close(dbp2, 0);
if (dbp1 != NULL)
(void)dbp2->close(dbp1, 0);
(void)dbenv->close(dbenv, 0);
return (1);
}

Error support

db_strerror能根據一個bdb的一個錯誤返回值返回一個指向錯誤信息的指針。它可以處理系統的錯誤返回值也能處理bdb特有的返回值。
例如:
int ret;
if ((ret = dbenv->set_cachesize(dbenv, 0, 32 * 1024, 1)) != 0) {
fprintf(stderr, "set_cachesize failed: %s/n", db_strerror(ret));
return (1);
}

這兒也有兩個附加的錯誤處理函數:DB_ENV->err 和 DB_ENV->errx。
DB_ENV->err函數追加標準錯誤字符串到已構造好的信息,而DB_ENV->errx不那樣。
錯誤信息可以通過DB_ENV->set_errpfx被配置成總包含一個固定的東西,例如,應用程序名稱。還可以把錯誤信息輸入到一個指定的文件中,例如:
int ret;
dbenv->set_errfile(dbenv, errfp);
dbenv->set_errpfx(dbenv, program_name);
if ((ret = dbenv->open(dbenv, home,
  DB_CREATE | DB_INIT_LOG | DB_INIT_TXN | DB_USE_ENVIRON, 0))
  != 0) {
dbenv->err(dbenv, ret, "open: %s", home);
dbenv->errx(dbenv,"contact your system administrator:
  session ID was %d",session_id);
return (1);
}
例如應用程序名爲"my_app", 環境的home目錄爲 "/tmp/home",出錯信息將是這樣的:
my_app: open: /tmp/home: Permission denied.
my_app: contact your system administrator: session ID was 2

DB_CONFIG configuration file

幾乎所有可以指定給DB_ENV那些方法的配置信息,也都能通過一個配置文件來指定。如果一被命名爲DB_CONFIG的文件存在於數據庫hone目錄下,它將會一行行的按NAME VALUE的格式讀入。
NAME和VALUE之間用一個或者多個空格來分割。凡是那一行的開頭是空格或#的,都將被忽略爲註釋。
NAME VALUE具體值可以在對用的方法中查到例如DB_ENV->set_data_dir。

DB_CONFIG 配置文件的目的是允許管理員定製不依賴於應用程序的環境。例如,可以移動數據庫log文件和數據文件到不同的地方,而不用重新編譯應用程序。另外,因爲 DB_CONFIG文件是當數據庫環境被打開時讀取的,它可以用來覆蓋在那以前配置的規則。例如,可以定義一個更合理的cache大小,來覆蓋以前已經編譯到程序中的值。


本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/database/20071202/8691.html

 

 

File naming

下面介紹幾種可能的爲bdb指定文件命名信息的方法。
db_home: 爲DB_ENV->open的db_home參數指定一個非NULL值,它的值將會用來作爲數據庫的home,以後的文件命名都是相對這個路徑的。

DB_HOME:爲環境變量DB_HOME指定值,DB_ENV->open被調用時候,讀取這個值,把它作爲數據庫home,以後的文件命名都是相對這個路徑的。

DB_ENV 方法:這有三個方法可以影響文件命名。DB_ENV->set_data_dir可以爲數據庫文件指定一個目錄。DB_ENV-> set_lg_dir方法可以爲log文件指定目錄。DB_ENV->set_tmp_dir爲創建的臨時文件指定一個目錄。例如,一個應用程序可以將數據文件,日誌文件等分別放在不同的目錄下。

DB_CONFIG文件:相同的指定給DB_ENV 方法的信息,也可以用DB_CONFIG 配置文件來指定。

我覺得指定的優先級從高到低應該是這樣的:DB_ENV,DB_CONFIG,db_home,DB_HOME,default。如果以上的值爲絕對路徑,那麼home就是那個絕對路徑。如果以上的值爲相對路徑,那麼將根據當前的工作目錄算出home路徑。如果什麼都沒指定,那麼默認的是現在的工作目錄爲 home。
例子:
情況一:把所有的文件都放在目錄/a/database下:
dbenv->open(dbenv, "/a/database", flags, mode);

情況二:把臨時文件放在/b/temporary,把所有其他文件放在/a/database:
dbenv->set_tmp_dir(dbenv, "/b/temporary");
dbenv->open(dbenv, "/a/database", flags, mode);

情況三:把數據文件放在/a/database/datadir,日誌文件放在/a/database/logdir所有其他文件放在/a/database:
dbenv->set_lg_dir(dbenv, "logdir");
dbenv->set_data_dir(dbenv, "datadir");
dbenv->open(dbenv, "/a/database", flags, mode);

情況四:
把數據文件放在/a/database/data1和/b/data2,所有其他文件放在/a/database.
任何數據文件將被創建在/b/data2目錄下,因爲它是第一個被指定的數據目錄:
dbenv->set_data_dir(dbenv, "/b/data2");
dbenv->set_data_dir(dbenv, "data1");
dbenv->open(dbenv, "/a/database", flags, mode);

。。。。。

Shared memory regions


每個在環境中的bdb子系統都被一個或多個區域(regions),或大塊的內存來描述。區域包括所有的每進程和每線程共享信息,(包括互斥)
,這些組成了bdb環境。這些區域將下列在三種內存類型中的一種中被創建,這取決於指定給DB_ENV->open方法的標誌:

DB_PRIVATE:如果這個標誌被指定,區域將在每進程的堆內存中被創建;也就是說由malloc()返回的內存。
這個標誌最好不要指定當一個以上的內存訪問環境的時候。因爲它很有可能引起數據庫腐爛(corruption)和一些不可預知的行爲,例如,當
server應用程序和bdb公用程序,(例如:db_archive, db_checkpoint or db_stat)都有可能訪問這個環境的時候,B_PRIVATE標誌最好別指
定。

DB_SYSTEM_MEM:如果這個標誌被指定,共享區域將在系統內存中創建而不是在文件中。這是一個可選的機制,爲了在多個進程和一個進程中的
多線程間共享bdb環境。bdb所使用的系統內存潛在地很有用,陪任何特殊的進程度過一生。因此附加的清除將是必要的當一個應用程序出現故
障後,因爲bdb沒有辦法去確認,支撐共享內存區的系統資源是不是還給了系統。
系統內存的使用是根據計算機體系結構而定的。例如,在一個支持 X/Open樣式共享內存的系統上,像UNIX系統,shmget(2) 和相近的
系統V IPC接口被使用。在VxWorks 系統中使用系統內存。在這些情況下,一個初始的段id必須在應用程序中被指定,以確保應用程序不互相覆
蓋對方的數據庫環境。因此,段創建的數量不是無限制的增長。可以參考DB_ENV->set_shm_key方法得到跟多的信息。
在windows平臺上DB_SYSTEM_MEM標誌問題多多,我就不說了.

default:如果沒有內存相關的標誌被指定給DB_ENV->open,被文件系統支撐的內存(覺得應該可以理解爲虛擬內存)將用來存儲這區域(regions)。在unix系統上,bdb庫將將使用POSIX mmap接口。如果mmap不可用,那麼unix shmget接口將可能被使用,如果它可用的話。
任何在文件系統中創建用來支撐區域的文件,將在環境的home目錄下被創建。這些文件命名爲__db.###(例如,_db.001, __db.002等等)。
當區域文件被文件系統來支撐的時候,每個區域對應一個文件被創建。當區域文件被系統內存來支撐的時候,只有一個文件將仍然被創建,因爲這兒必須有一個熟知的名字在文件系統中,以便多進程能定位到環境所使用的系統共享內存。
統計在環境中的共享內存區域可以用db_stat的-e選項來顯示。


Security

下面是當你在寫bdb應用程序的時候需要考慮的安全問題:

數據庫環境許可:
被bdb數據庫環境使用的目錄,應該有它自己的許可設置,以確保那些沒有適當權限的用戶不能訪問環境裏的文件。應用程序,那些添加到用戶
的許可(例如,unix的setuid 或 setgid程序), 應該細心的檢查,不允許違法的使用這些許可,例如訪問在環境中的文件。

環境變量:
設置 DB_USE_ENVIRON 和 DB_USE_ENVIRON_ROOT標誌 和允許在文件命名時使用環境變量都是危險的。在bdb應用程序中用附加的許可(例如,
unix的setuid 或 setgid程序)設置這些標誌,將潛在地允許那些正常情況下沒有權限的用戶讀寫數據庫。

文件許可:
默認地,bdb總是創建所有者和所在組可讀寫的文件(也就是,S_IRUSR, S_IWUSR, S_IRGRP 和 S_IWGRP; 或八進制模式 0660 在歷史性的UNIX
系統上),創建文件的組的所有權,是基於系統和目錄默認的,不被bdb進一步的指定。

臨時支撐(backing)文件:
如果一個沒有被命名的數據庫被創建,而cache太小以至於不能在內存中控制這個數據庫,bdb將創建一個臨時的物理文件使它能把數據庫的cache頁放到磁盤上,當需要的時候。
在這種情況下,環境變量,像TMPDIR可能被用來指定用以定位那個臨時文件。儘管臨時支撐文件被創建被只有所有者可讀寫的。(S_IRUSR 和 S_IWUSR, 或八進制模式 0660 在歷史性的UNIX系統上),一些文件系統可能不能充分的保護被創建在隨機目錄中的臨時文件。爲了絕對安全,應用程序存儲敏感數據在未命名的數據庫中,應該用DB_ENV->set_tmp_dir方法用已知的許可(known permissions)指定一個臨時目錄。

Encryption

bdb可選擇的用Rijndael/AES算法支持加密和解密。這個加密只是文件級的,如果侵入者能夠訪問你係統的內存,那麼這種加密就不能提供保障
了。與我的應用無關我就不多說了。自己看手冊。

Remote filesystems

最好別使用遠程文件系統,像nfs等。因爲區域文件要映射到內存,遠程文件系統不能很好的支持某些語義。數據庫文件,的日誌文件,臨時文
件,還勉強可以放在遠程文件系統上,如果遠程文件系統完全支持標準POSIX文件系統語義的話。總之,不用最好。

Environment FAQ

我使用多進程訪問bdb數據庫環境,這兒有什麼方法可以確保兩個進程不同時執行數據恢復(recovery )操作嗎?或者說,確保其他所有的進程都退出了,可以運行數據恢復了?

其實重點要說明的是,當執行數據恢復的時候要確保沒有別的進程在使用這個環境。
很多應用程序組,寫一個小的監視程序,來恢復數據庫環境,然後執行那些實際上用數據庫環境工作的進程。監視程序然後監視工作的進程,如果任何工作進程發生故障推出或其他原因,監視程序將kill所有仍然存活的其他進程,然後執行恢復任務,然後重新這個循環。


本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/database/20071202/8691_2.html

發佈了12 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章