BerkeleyDB原理及其對應API

BerkeleyDB(簡稱爲BDB)是一種以key-value爲結構的嵌入式數據庫引擎:html

  • 嵌入式:bdb提供了一系列應用程序接口(API),調用這些接口很簡單,應用程序和bdb所提供的庫一塊兒編譯/連接成爲可執行程序;
  • NOSQL:bdb不支持SQL語言,它對數據的管理很簡單,bdb數據庫包含若干條記錄,每條記錄由關鍵字和數據(key-value)兩部分構成。數據能夠是簡單的數據類型,也能夠是複雜的數據類型,例如C語言的結構體,bdb對數據類型不作任何解釋,徹底由程序員自行處理,典型的C語言指針的自由風格;

 

DB的設計思想是簡單、小巧、可靠、高性能。若是說一些主流數據庫系統是大而全的話,那麼DB就可稱爲小而精。DB提供了一系列應用程序接口(API),調用自己很簡單,應用程序和DB所提供的庫在一塊兒編譯成爲可執行程序。這種方式從兩方面極大提升了DB的效率。第一:DB庫和應用程序運行在同一個地址空間,沒有客戶端程序和數據庫服務器之間昂貴的網絡通信開銷,也沒有本地主機進程之間的通信;第二:不須要對SQL代碼解碼,對數據的訪問直截了當。git

DB對須要管理的數據見解很簡單,DB數據庫包含若干條記錄,每個記錄由關鍵字和數據(KEY/VALUE)構成。數據能夠是簡單的數據類型,也能夠是複雜的數據類型,例如C語言中結構。DB對數據類型不作任何解釋, 徹底由程序員自行處理,典型的C語言指針的"自由"風格。若是把記錄當作一個有n個字段的表,那麼第1個字段爲表的主鍵,第2--n個字段對應了其它數據。DB應用程序一般使用多個DB數據庫,從某種意義上看,也就是關係數據庫中的多個表。DB庫很是緊湊,不超過500K,但能夠管理大至256T的數據量。程序員

DB的設計充分體現了UNIX的基於工具的哲學,即若干簡單工具的組合能夠實現強大的功能。DB的每個基礎功能模塊都被設計爲獨立的,也即意味着其使用領域並不侷限於DB自己。例如加鎖子系統能夠用於非DB應用程序的通用操做,內存共享緩衝池子系統能夠用於在內存中基於頁面的文件緩衝。算法

 

BDB能夠分爲幾個子系統:數據庫

  • 存儲管理子系統 (Storage Subsystem)
  • 內存池管理子系統 (Memory Pool Subsystem)
  • 事務子系統 (Transaction Subsystem)
  • 鎖子系統 (Locking Subsystem)
  • 日誌子系統 (Logging Subsystem)

BDB的每個基礎功能模塊都被設計爲獨立的,也即意味着其使用領域並不侷限於BDB自己,例如加鎖子系統能夠用於非BDB應用程序的通用操做,內存共享緩衝池子系統能夠用於在內存中基於頁面的文件緩衝。編程

 

BDB庫的安裝方法:從官網下載、解壓後執行下面的命令緩存

cd build_unix
../dist/configure
make
make install

DB缺省把庫和頭文件安裝在目錄 /usr/local/BerkeleyDB.6.1/ 下,使用下面的命令就可正確編譯程序:服務器

gcc test.c  -I/usr/local/BerkeleyDB.6.1/include/ -L/usr/local/BerkeleyDB.6.1/lib/ -ldb -lpthread

 

 

下面是一個BDB API使用的例子:網絡

複製代碼
#include <db.h> 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

typedef struct customer {
    int  c_id;
    char name[10];
    char address[20];
    int  age;
} CUSTOMER;


/* 數據結構DBT在使用前,應首先初始化,不然編譯可經過但運行時報參數錯誤  */
void init_DBT(DBT * key, DBT * data)
{
    memset(key, 0, sizeof(DBT));
    memset(data, 0, sizeof(DBT));
}

int main(void)
{
    DB_ENV *dbenv;
    DB *dbp;    
    DBT key, data;

    int ret = 0;
    int key_cust_c_id = 1;
    CUSTOMER cust = {1, "chenqi", "beijing", 30}; 


    /* initialize env handler */
    if (ret = db_env_create(&dbenv, 0)) { 
        printf("db_env_create ERROR: %s\n", db_strerror(ret));
        goto failed;
    }   

    u_int32_t flags = DB_CREATE | DB_INIT_MPOOL | DB_INIT_CDB | DB_THREAD;;  

    if (ret = dbenv->open(dbenv, "/data0/bdb_test", flags, 0)) {
        printf("dbenv->open ERROR: %s\n", db_strerror(ret));
        goto failed;
    }   

    /* initialize db handler */
    if (ret = db_create(&dbp, dbenv, 0)) {
        printf("db_create ERROR: %s\n", db_strerror(ret));
        goto failed;
    }   

    flags = DB_CREATE | DB_THREAD;

    if (ret = dbp->open(dbp, NULL, "single.db", NULL, DB_BTREE, flags, 0664)) {
        printf("dbp->open ERROR: %s\n", db_strerror(ret));
        goto failed;
    }


    /* write record */
    /* initialize DBT */
    init_DBT(&key, &data);
    key.data = &key_cust_c_id;
    key.size = sizeof(key_cust_c_id);
    data.data = &cust;
    data.size = sizeof(CUSTOMER);

    if (ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) {
        printf("dbp->put ERROR: %s\n", db_strerror(ret));
        goto failed;
    }

    /* flush to disk */
    dbp->sync(dbp, 0);

    /* get record */
    init_DBT(&key, &data);
    key.data = &key_cust_c_id;
    key.size = sizeof(key_cust_c_id);
    data.flags = DB_DBT_MALLOC;

    if (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
        printf("dbp->get ERROR: %s\n", db_strerror(ret));
        goto failed;
    }

    CUSTOMER *info = data.data;

    printf("id = %d\nname=%s\naddress=%s\nage=%d\n",
            info->c_id,
            info->name,
            info->address,
            info->age);

    /* free */
    free(data.data);

    if(dbp) {
        dbp->close(dbp, 0);
    }

    if (dbenv) {
    dbenv->close(dbenv, 0);
    }

    return 0;


failed:

    if(dbp) {
        dbp->close(dbp, 0);
    }

    if (dbenv) {
        dbenv->close(dbenv, 0);
    }

    return -1;
}
複製代碼

 上面的例子中使用了不少BDB庫中的API,在下面會再具體介紹它們。 數據結構

 


 

 

訪問方法

訪問方法對應了數據在硬盤上的存儲格式和操做方法。在編寫應用程序時,選擇合適的算法可能會在運算速度上提升1個甚至多個數量級。大多數數據庫都選用B+樹算法,DB也不例外,同時還支持HASH算法、Recno算法和Queue算法。接下來,咱們將討論這些算法的特色以及如何根據須要存儲數據的特色進行選擇。

  1. BTree:有序平衡樹結構;
  2. Hash:擴展線性哈希表結構(extended linear hashing);
  3. Queue:由有固定長度的記錄組成的隊列結構,每一個記錄使用一個邏輯序列號做爲鍵值,邏輯紀錄號由算法自己生成,這和關係型數據庫中邏輯主鍵一般定義爲int AUTO型是同一個概念;支持在隊尾快速插入,和從隊首取出(或刪除)記錄;並提供記錄級別的加鎖操做,從而支持對隊列的併發訪問。
  4. Recno:同時支持固定長度的記錄和變長記錄,而且提供支持flat text file的永久存儲和數據在讀時提供一個快速的臨時存儲空間;

 

說明:

BTree和Hash的key和value都支持任意複雜類型,而且也容許存在key重複的記錄;

Queue和Recno的key只能是邏輯序列號,二者基本上都是創建在Btree算法之上,提供存儲有序數據的接口。前者的序列號是不可變的,後者的序列號能夠是可變,也能夠是不變;

可變,指的是當記錄被刪除或者插入時,編號改變;不變,指的是無論數據庫如何操做,編號都不改變。在Queue算法中編號總被不變的。在Recno算法中編號是可變的,即當記錄被刪除或者插入時,數據庫裏的其餘記錄的編號也可能會改變。

另外,Queue的value爲定長結構,而Recno的value能夠爲定長,也能夠爲變長結構;

 

對算法的選擇首先要看關鍵字的類型,若是爲複雜類型,則只能選擇BTree或HASH算法,若是關鍵字爲邏輯記錄號,則應該選擇Recno或Queue算法。

當工做集key有序時,BTree算法比較合適;若是工做集比較大且基本上關鍵字爲隨機分佈時,選擇HASH算法。

Queue算法只能存儲定長的記錄,在高的併發處理狀況下,Queue算法效率較高;若是是其它狀況,則選擇Recno算法,Recno算法把數據存儲爲flat text file。

 

Access Method

Description

Choosing Occasion

BTree

關鍵字有序存儲,而且其結構能隨數據的插入和刪除進行動態調整。爲了代碼的簡單,Berkeley DB沒有實現對關鍵字的前綴碼壓縮。B+樹支持對數據查詢、插入、刪除的常數級速度。關鍵字能夠爲任意的數據結構。

一、 當Key爲複雜類型時。

二、 當Key有序時。

Hash

DB中實際使用的是擴展線性HASH算法(extended linear hashing),能夠根據HASH表的增加進行適當的調整。關鍵字能夠爲任意的數據結構。

一、 當Key爲複雜類型。

二、 當數據較大且key隨機分佈時。

 

Recno

要求每個記錄都有一個邏輯紀錄號,邏輯紀錄號由算法自己生成。至關於關係數據庫中的自動增加字段。Recho創建在B+樹算法之上,提供了一個存儲有序數據的接口。記錄的長度能夠爲定長或不定長。

一、 當key爲邏輯記錄號時。

二、 當非高併發的狀況下。

Queue

和Recno方式接近, 只不過記錄的長度爲定長。數據以定長記錄方式存儲在隊列中,插入操做把記錄插入到隊列的尾部,相比之下插入速度是最快的。

一、當key爲邏輯記錄號時。

二、定長記錄。

三、 高併發的狀況下。

 

 

 

 


 

數據結構

數據庫環境句柄結構DB_ENV:環境在DB中屬於高級特性,本質上看,環境是多個數據庫的包裝器。當一個或多個數據庫在環境中打開後,環境能夠爲這些數據庫提供多種子系統服務,例如多線/進程處理支持、事務處理支持、高性能支持、日誌恢復支持等。

數據庫句柄結構DB:包含了若干描述數據庫屬性的參數,如數據庫訪問方法類型、邏輯頁面大小、數據庫名稱等;同時,DB結構中包含了大量的數據庫處理函數指針,大多數形式爲 (*dosomething)(DB *, arg1, arg2, …),其中最重要的有open、close、put、get等函數。

數據庫記錄結構DBT:DB中的記錄由關鍵字和數據構成,關鍵字和數據都用結構DBT表示。實際上徹底能夠把關鍵字當作特殊的數據。結構中最重要的兩個字段是 void * data和u_int32_t size,分別對應數據自己和數據的長度。

數據庫遊標結構DBC:遊標(cursor)是數據庫應用中常見概念,其本質上就是一個關於特定記錄的遍歷器。注意到DB支持多重記錄(duplicate records),即多條記錄有相同關鍵字,在對多重記錄的處理中,使用遊標是最容易的方式。

DB中核心數據結構在使用前都要初始化,隨後能夠調用結構中的函數(指針)完成各類操做,最後必須關閉數據結構。從設計思想的層面上看,這種設計方法是利用面向過程語言實現面對對象編程的一個典範。

 

DB_ENV    *dbenv;           // 環境句柄
DB      *dbp;             // 數據庫句柄
DBT     key, value;       // 紀錄結構
DBC     *cur;            // 遊標結構

 

 

數據庫每條記錄包含兩個DBT結構,一個是key,一個是value。
複製代碼
typedef struct {
     void *data;          // 數據buf
     u_int32_t size;     // 數據大小
     u_int32_t ulen;     //
     u_int32_t dlen;     // 數據長度
     u_int32_t doff;     // 數據開始處
     u_int32_t flags;     
} DBT;
複製代碼

 

 

 

數據庫環境

BDB環境是對一個或多個數據庫的封裝,環境對應一個目錄,數據庫對應該目錄下面的一個文件。
 
環境支持:
  • 在一個磁盤文件中包含多個數據庫;
  • 多進程和多線程支持;
  • 事務處理;
  • 高可用支持(主從庫複製);
  • 日誌系統(可用於數據庫異常恢復);
 
與環境相關的API:
DB_ENV *dbenv;
db_env_create(&dbenv, 0);                     // 建立數據庫環境句柄
dbenv->open(dbenv, path, flags, 0);          // 打開數據庫環境, path是環境的目錄路徑, flag參數參考下面介紹
dbenv->close(dbenv, 0);                      // 關閉數據庫環境
dbenv->err(dbenv, ret, formart, ...);        // 錯誤調試

 

打開環境時的flags標誌位:
DB_CREATE               // 打開的環境不存在的話就建立它
DB_THREAD               // 支持線程
DB_INIT_MPOOL         // 初始化內存中的cache
DB_INIT_CDB

 

 

BDB 環境的使用例子:

複製代碼
/* 定義一個環境變量,並建立 */
DB_ENV *dbenv;
db_env_create(&dbenv, 0);

/* 在環境打開以前,可調用形式爲dbenv->set_XXX()的若干函數設置環境 */

/* 通知DB使用Rijndael加密算法(參考資料>)對數據進行處理 */
dbenv->set_encrypt(dbenv, "encrypt_string", DB_ENCRYPT_AES);

/* 設置DB的緩存爲5M */
dbenv->set_cachesize(dbenv, 0, 5 * 1024 * 1024, 0);

/* 設置DB查找數據庫文件的目錄 */
dbenv->set_data_dir(dbenv, "/usr/javer/work_db");

/* 設置出錯時的回調函數 */
dbenv->set_errcall(dbenv, callback);

/* 將錯誤信息寫到指定文件 */
dbenv->set_errfile(dbenv, file);

/* 打開數據庫環境,注意後四個標誌分別指示DB啓動日誌、加鎖、緩存、事務處理子系統 */
dbenv->open(dbenv,home,DB_CREATE|DB_INIT_LOG|DB_INIT_LOCK| DB_INIT_MPOOL |DB_INIT_TXN, 0);

/* 在環境打開後,則能夠打開若干個數據庫,全部數據庫的處理都在環境的控制和保護中。
   注意db_create函數的第二個參數是環境變量 */
db_create(&dbp1, dbenv, 0);
dbp1->open(dbp1, ……);
db_create(&dbp2, dbenv, 0);
dbp1->open(dbp2, ……);

/* do something with the database */
/* 最後首先關閉打開的數據庫,再關閉環境 */
dbp2->close(dbp2, 0);
dbp1->close(dbp1, 0);
dbenv->close(dbenv, 0);
複製代碼

 

 

 

數據庫操做

DB數據庫是一組K-V記錄的集合,key和value都是DBT結構存儲的,與數據庫操做有關的API:
複製代碼
DB* dbp; 
db_create(&dbp, dbenv, 0);                                            // 獲取數據庫句柄
dbp->open(dbp, NULL, filename, NULL, DB_BTREE, flags, 0);        
dbp->close(&dbp, 0);                                                  // 在關閉數據庫前,先關閉全部打開的遊標
dbp->sync(dbp, 0)                                                     // 刷新cache,同步到磁盤,close操做會隱含調用該過程
dbp->remove(dbp, filename, NULL, 0)                                 // 移除數據庫,不要移除已打開的數據庫
dbp->rename(dbp, oldname, NULL, newname, 0)                      // 數據庫重命名,不要重命名已打開的數據庫
 
dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);              // DB_NOOVERWRITE不容許重寫已存在的key
dbp->get(dbp, NULL, &key, &data, flags);                             // 若是存在key重複的記錄,只返回第一個,或者使用遊標
dbp->del(dbp, NULL, &key, 0);                                        // 刪除指定key的記錄
dbp->truncate(dbp, NULL, u_int32_t* count, 0);                      // 刪除全部記錄,count中返回被刪除的記錄個數
dbp->get_open_flags(dbp, &open_flags);                             // 獲取打開的flags,僅對已打開的數據庫纔有意義
dbp->set_flags(dbp, flags);                                          // 設置打開的flags
複製代碼

 

 打開數據庫時的flags標誌位
DB_CREATE  //若是打開的數據庫不存在,就建立它;不指定這個標誌,若是數據庫不存在,打開失敗!
DB_EXC    //與DB_CREATE一塊兒使用,若是打開的數據庫已經存在,則打開失敗;不存在,則建立它;
DB_RDONLY  //只讀的方式打開,隨後的任何寫操做都會失敗;
DB_TRUNCATE  //清空對應的數據庫磁盤文件;
DB_DUPSORT   //

  

get方法返回DB_NOTFOUND時表示沒有匹配記錄,其最後一個參數flags:

DB_GET_BOTH   // get方法默認只匹配key,該flag將返回key和data都匹配的第一條記錄
DB_MULTIPLE   // get方法默認只返回匹配的第一條記錄,該flag返回全部匹配記錄

 

使用get方法時,data參數是DBT結構,該DBT的flags參數能夠定義爲:

DB_DBT_USERMEM       // 使用本身的內存存儲檢索的data
DB_DBT_MALLOC        // 使用DB分配的內存,用完後要手動free

DB提供的內存對齊方式可能不符合用戶數據結構的需求,因此儘可能使用咱們本身的內存。

用DB_DBT_USERMEM方式改寫前面的例子:

複製代碼
   /* get record */
    CUSTOMER info;
    init_DBT(&key, &data);

    key.data = &key_cust_c_id;
    key.size = sizeof(key_cust_c_id);

    data.data = &info;
    data.ulen = sizeof(CUSTOMER);
    data.flags = DB_DBT_USERMEM;

    if (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
        printf("dbp->get ERROR: %s\n", db_strerror(ret));
        goto failed;
    }   

    printf("id = %d\nname=%s\naddress=%s\nage=%d\n", 
            info.c_id,
            info.name,
            info.address,
            info.age);
複製代碼

 

 

 

 
錯誤處理
DB接口調用成功一般返回0,失敗返回非0值,此時能夠檢查錯誤碼errno;
由系統調用失敗引發的錯誤errno>0,不然errno<0。
複製代碼
db_strerror(errno)                     // 將錯誤編碼映射成一個字符串
dbp->set_errfile(dbp, FILE*)           // 設置錯誤文件
dbp->set_errcall(dbp, void(*)(const DB_ENV *dbenv, const char* err_pfx, const char* msg))           // 定義錯誤處理的回調函數
dbp->set_errpfx(dbp, format...)       // 加上錯誤消息前綴
dbp->err(dbp, ret, format...)        // 生成錯誤消息,並按優先級發給set_errcall定義的錯誤處理回調函數、set_errfile定義的文件、stderr;
dbp->errx(dbp, format...)            // 與dbp->err相似,但沒有返回值ret這個額外參數
複製代碼

錯誤消息由一個前綴(由set_errpfx定義)、消息自己(由err或errx定義)和一個換行符組成。

 

 

 


 

遊標

若是DB數據庫中存在鍵值相同的多條記錄,使用dbp->get()方法默認只能獲取一條記錄(除非打開DB_MULTIPLE標誌),這個時候有必要使用遊標(cursor),遊標能夠迭代DB數據庫中的記錄。
DBC  *cur;
dbp->cursor(dbp, NULL, &cur, 0); // 初始化遊標對象 cur->close(cur); // 關閉遊標 cur->get(cur, &key, &data, flags); // 迭代記錄,當沒有可迭代的記錄時,返回DB_NOTFOUND cur->put(cur, &key, &data, flags); cur->del(cur, 0); // 刪除遊標指向的記錄

 

cur->get()方法中flags參數的取值:
一、迭代整個數據庫中的紀錄集合:
DB_NEXT    // 從第一條紀錄遍歷到最後一條紀錄;
DB_PREV    // 逆序遍歷,從最後一條紀錄開始;

 

 
二、查找符合條件的記錄集:
複製代碼
DB_SET          // 移動遊標到鍵值等於給定值的第一條紀錄;
DB_SET_RANGE      // 若是數據庫使用BTREE的算法,移動遊標到鍵值大於或等於給定值的紀錄集合;
DB_GET_BOTH      // 移動遊標到鍵值和數據項均等於給定值的第一條記錄;
DB_GET_BOTH_RAGNE   // 移動遊標到鍵值等於給定值,數據項大於或等於給定值的紀錄集合;
 
DB_NEXT_DUP      // 獲取下一個key重複的記錄;
DB_PREV_DUP      // 獲取上一個key重複的記錄;
DB_NEXT_NODUP     // 獲取下一個key不重複的記錄;
DB_PREV_NODUP    // 獲取上一個key不重複的記錄;
複製代碼

 

 
cur->put()方法中flags參數的取值:
DB_NODUPDATA   // 若是插入的key已存在,返回DB_KEYEXIST,若是不存在,則記錄的插入順序由其在數據庫的插入順序決定;
DB_KEYFIRST    // 在key重複的集合裏面放在第一個位置;
DB_KEYLAST    // 在key重複的集合裏面放在最後一個位置;
DB_CURRENT    // replace

 

 

 


 

secondary數據庫

一般,對DB數據庫的檢索都是基於key的,若是想經過value(或value的部分信息)來檢索數據能夠經過secondary database來實現。
若是咱們把存放K-V記錄的數據庫稱爲 primary database,那麼secondary database索引的是其它字段,而對應的value就是primary database的key。從secondary database中讀取記錄時,DB自動返回primary database中對應的value;
在建立secondary database時須要提供一個callback函數,用來建立key,這個key是根據primary database的key或value生成的。這個callback函數返回0時才容許索引到secondary中,咱們能夠在callback中返回DB_DONOTINDEX或其它錯誤碼告訴secondary不要索引該記錄。

創建secondary database以後,若是在primary database中新增或刪除記錄,會觸發對secondary database的更新。
注意:咱們不能直接更新secondary database,任何寫secondary database的操做都會失敗,secondary database的變動須要經過修改primary database實現。但這裏有一個例外,容許在secondary database中刪除記錄。

 
將secondary綁定到primary database的接口:
primary_dbp->associate(primary_dbp, NULL, second_dbp, key_creator, 0);
int key_creator(DB* dbp, const DBT* pkey, const DBT* pdata, DBT* skey);

 

 

 一個例子:

複製代碼
DB *dbp, *sdbp;     /* Primary and secondary DB handles */
u_int32_t flags;    /* Primary database open flags */
int ret;            /* Function return value */

typedef struct vendor {
    char name[MAXFIELD];         /* Vendor name */
    char street[MAXFIELD];        /* Street name and number */
    char city[MAXFIELD];         /* City */
    char state[3];            /* Two-digit US state code */
    char zipcode[6];           /* US zipcode */
    char phone_number[13];       /* Vendor phone number */
    char sales_rep[MAXFIELD];      /* Name of sales representative */
    char sales_rep_phone[MAXFIELD];  /* Sales rep's phone number */
} VENDOR;

/* Primary */
ret = db_create(&dbp, NULL, 0); 
if (ret != 0) {
    /* Error handling goes here */
}

/* Secondary */
ret = db_create(&sdbp, NULL, 0); 
if (ret != 0) {
    /* Error handling goes here */
}

/* Usually we want to support duplicates for secondary databases */
ret = sdbp->set_flags(sdbp, DB_DUPSORT);
if (ret != 0) {
    /* Error handling goes here */
}

/* Database open flags */
flags = DB_CREATE; /* If the database does not exist, create it.*/

/* open the primary database */
ret = dbp->open(dbp, NULL, "my_db.db", NULL, DB_BTREE, flags, 0); 
if (ret != 0) {
    /* Error handling goes here */
}

/* open the secondary database */
ret = sdbp->open(sdbp, NULL, "my_secdb.db", NULL, DB_BTREE, flags, 0); 
if (ret != 0) {
    /* Error handling goes here */
}

/* Callback used for key creation. Not defined in this example. See the next section. */
int get_sales_rep(DB *sdbp,   /* secondary db handle */
        const DBT *pkey,    /* primary db record's key */
        const DBT *pdata,   /* primary db record's data */
        DBT *skey)       /* secondary db record's key */
{
    VENDOR *vendor;
/* First, extract the structure contained in the primary's data */ vendor = pdata->data;
/* Now set the secondary key's data to be the representative's name */ memset(skey, 0, sizeof(DBT)); skey->data = vendor->sales_rep; skey->size = strlen(vendor->sales_rep) + 1;
/* Return 0 to indicate that the record can be created/updated. */ return (0); } /* Now associate the secondary to the primary */ dbp->associate(dbp, NULL, sdbp, get_sales_rep, 0);
複製代碼

 

 

 

 

頁面大小

BDB記錄的key和value都是存放在內存頁(page)裏面,因此頁面大小(page size)對數據庫性能有很大影響。
對BTree庫,page size的理想大小至少是記錄大小的4倍。
 
DB* dbp; 
dbp->set_pagesize()          // 設置page size
dbp->stat()                  // 查看page size

 

 
page size的影響:
一、overflow pages
溢出頁(overflow pages)是用來存放那些單個page沒法存放的kye或value的page。
若是page size設置太低,會產生溢出頁,從而影響數據庫性能。
 
二、locking
page size對多線程(或多進程)的BDB應用也會產生影響,這是由於BDB使用了page級的加鎖(Queue除外)。
一般一個page包含多條記錄,若是某個線程正在訪問一條記錄,則該記錄所在的page會被鎖住,致使同一個page下面的其餘記錄也沒法被其餘線程訪問。
若是page size設置太高,會加大鎖發生的機率,但page size太小,會致使BTree的深大變大,一樣損失性能。
 
三、I/O
DB數據庫的頁面大小要和文件系統的block size一致;
 

 

 

 


 

緩存

DB能夠將那些常常訪問到記錄cache 到內存裏面,從而加快讀寫速度。

dbp->set_cachesize(dbp, gbytes, bytes, ncache);         // 經過數據庫句柄設置cache大小
dbenv->set_cachesize(dbp, gbytes, bytes, ncache);      // 經過環境句柄設置cache大小(全局)

 

from:https://www.cnblogs.com/chenny7/p/4864547.html

相關文章
相關標籤/搜索