QDBMはデータベースを扱うルーチン群のライブラリである。データベースといっても単純なものであり、キーと値のペアからなるレコードを格納したデータファイルである。キーと値は任意の長さを持つ一連のバイトであり、文字列でもバイナリでも扱うことができる。テーブルやデータ型の概念はない。キーはデータベース内で一意であり、キーが重複する複数のレコードを格納することはできない。
このデータベースに対しては、キーと値を指定してレコードを格納したり、キーを指定して対応するレコードを削除したり、キーを指定して対応するレコードを検索することができる。また、データベースに格納してある全てのキーを順不同に1つずつ取り出すこともできる。このような操作は、UNIX標準で定義されているDBMライブラリおよびその互換であるNDBMやGDBMに類するものである。QDBMはDBMのより良い代替として利用することができる。
QDBMはGDBMを参考に次の3点を目標として開発された。処理がより高速であること。データベースファイルがより小さいこと。APIがより単純であること。QDBMの特徴は、まさにそれらを達成していることである。また、DBMが抱える3つの制限事項を回避している。すなわち、プロセス内で複数のデータベースを扱うことができ、キーと値のサイズに制限がなく、データベースファイルがスパースでない。
QDBMはレコードの探索にハッシュアルゴリズムを用いる。バケット配列に十分な要素数があれば、レコードの探索にかかる時間計算量は O(1) である。すなわち、レコードの探索に必要な時間はデータベースの規模に関わらず一定である。追加や削除に関しても同様である。ハッシュ値の衝突はセパレートチェーン法で管理する。チェーンのデータ構造は二分探索木である。バケット配列の要素数が著しく少ない場合でも、探索等の時間計算量は O(log n) に抑えられる。
QDBMはバケット配列を全てRAM上に保持することによって、処理の高速化を図る。バケット配列がRAM上にあれば、ほぼ1パスのファイル操作でレコードに該当するファイル上の領域を参照することができる。ファイルに記録されたバケット配列はreadコールでRAM上に読み込むのではなく、mmapコールでRAMに直接マッピングされる。したがって、データベースに接続する際の準備時間が極めて短く、また、複数のプロセスでメモリマップを共有することができる。
バケット配列の要素数が格納するレコード数の半分ほどであれば、データの性質によって多少前後するが、ハッシュ値の衝突率は50%ほどである(等倍だと40%、2倍だと20%、4倍だと10%、8倍だと3%)。その場合、平均2パス以下のファイル操作でレコードを探索することができる。これを性能指標とするならば、例えば100万個のレコードを格納するためには50万要素のバケット配列が求められる。バケット配列の各要素は4バイトである。すなわち、2MバイトのRAMが利用できれば100万レコードのデータベースが構築できる。
QDBMにはデータベースに接続する方法として、リーダとライタの2種類がある。リーダは読み込み専用であり、ライタは読み書き両用である。データベースにはファイルロックによってプロセス間での排他制御が行われる。ライタが接続している間は、他のプロセスはリーダとしてもライタとしても接続できない。リーダが接続している間は、他のプロセスのリーダは接続できるが、ライタは接続できない。この機構によって、マルチタスク環境での同時接続の整合性が保証される。ただし、マルチスレッドには対応しない。
DBMにはレコードの追加操作に関して挿入モードと置換モードがある。前者では、キーが既存のレコードと重複する際に既存の値を残す。後者では、キーが既存のレコードと重複した際に新しい値に置き換える。QDBMはその2つに加えて連結モードがある。既存の値の末尾に指定された値を連結して格納する操作である。レコードの値を配列として扱う場合、要素を追加するには連結モードが役に立つ。また、DBMではレコードの値を取り出す際にはその全ての領域を処理対象にするしか方法がないが、QDBMでは値の領域の一部のみを選択して取り出すことができる。レコードの値を配列として扱う場合にはこの機能も役に立つ。
データベースにアラインメントを設定すると、各レコードは適当なパディングを空けてファイル中に配置される。既存のキーと重複するレコードに既存の値のサイズよりも大きいサイズの値を書き込もうとした際に、追加分のサイズがパディングに収まれば、そのレコードの領域を別の位置に再確保する必要がない。レコードの位置を移す処理はサイズに応じた計算量がかかるが、パディングをレコードの大きさに応じたサイズでとることによって、レコードの規模に対する更新処理の性能が一定に保たれる。
QDBMのAPIには基本APIと拡張APIの2種類がある。前者ではファイルを単位としてデータベースを扱い、後者ではディレクトリを単位としてデータベースを扱う。データベースの全てのデータをひとつのファイルに格納しようとすると、ファイルサイズがファイルシステムの制限を越える場合がある。拡張APIではそれに対処すべく、ディレクトリの中の複数のファイルに分割してデータを格納する。基本APIと拡張APIは互いに酷似した書式を備えるので、一方のAPIを使って書かれたアプリケーションを他方のAPIを用いて書き直すことはたやすい。
QDBMをインストールするには gcc と make が必要である。
QDBMの配布用アーカイブファイルを展開したら、生成されたディレクトリに入ってインストール作業を行う。まず、以下のコマンドを実行して、ビルド環境の設定を行う。
./configure
プログラムをビルドする。
make
プログラムの自己診断テストを行う。
make check
プログラムをインストールする。作業は root ユーザで行う。
make install
一連の作業が終ると、ヘッダファイル depot.h と curia.h が /usr/local/include に、ライブラリ libqdbm.a と libqdbm.so が /usr/local/lib に、コマンド dpm と dptest と dptsv と crm と crtest が /usr/local/bin にインストールされる。
QDBMをアンインストールするには、./configure をした後の状態で以下のコマンドを実行する。作業は root ユーザで行う。
make uninstall
DepotはQDBMの基本APIである。Depotを使うためには、depot.h をインクルードすべきである。通常、ソースファイルの冒頭付近で以下の記述を行う。
Depotでデータベースを扱う際には、DEPOT型へのポインタをハンドルとして用いる。これは、stdio.h の各種ルーチンがファイル入出力にFILE型へのポインタを用いているのに似ている。ハンドルは、dpopen で開き、dpclose で閉じる。ハンドルのメンバを直接参照することは推奨されない。データベースに致命的なエラーが起きた場合は、以後そのハンドルに対する dpclose を除く全ての操作は何もせずにエラーを返す。
外部変数 dpdbgfd にはデバッグ情報を出力するファイルディスクリプタを指定する。初期値は -1 であり、値が負数ならば出力を行わない。
外部変数 dpecode には直前のエラーコードが記録される。初期値は DP_ENOERR である。DPECODE型の詳細については depot.h を参照されたい。
エラーコードに対応するメッセージ文字列を得るには、関数 dperrmsg を用いる。
ecode はエラーコードを指定する。戻り値はエラーメッセージの文字列である。戻り値の領域は書き込み禁止領域である。
データベースのハンドルを作成するには、関数 dpopen を用いる。バケット配列の要素数はデータベースを作成する時に決められ、最適化以外の手段で変更することはできない。バケット配列の要素数は、格納するレコード数の半分から4倍程度にするのがよい。ライタ(読み書き両用モード)でデータベースファイルを開く際にはそのファイルに対して排他ロックがかけられ、リーダ(読み込み専用モード)で開く際には共有ロックがかけられる。その際には該当のロックがかけられるまでブロックする。
name はデータベースファイルの名前を指定する。omode は接続モードを指定し、DP_OREADER ならリーダ、DP_OWRITER ならライタとなる。omode が DP_OWRITER の場合、DP_OCREAT または DP_OTRUNC とのビット論理和にすることができる。DP_OCREAT はファイルが無い場合に新規作成することを指示し、DP_OTRUNC はファイルが存在しても作り直すことを指示する。bnum はバケット配列の要素数の目安を指定するが、0 以下ならデフォルト値が使われる。戻り値は正常ならデータベースハンドルであり、エラーなら NULL である。
一旦接続したデータベースハンドルは、処理が完了したら関数 dpclose に渡してデータベースとの接続を閉じる必要がある。データベースの更新内容は、接続を閉じた時点で初めてファイルと同期される。ライタでデータベースを開いた場合、適切に閉じないとデータベースが破壊される。
depot はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。閉じたハンドルの領域は解放されるので、以後は利用できなくなる。
レコードを追加するには、関数 dpput を用いる。
depot はライタで接続したデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。vbuf は値のデータ領域のポインタを指定する。vsiz は値のデータ領域のサイズをバイト数で指定するか、-1 なら vbuf の文字列長となる。dmode は DP_DOVER か DP_DKEEP か DP_DCAT で、キーが既存レコードと重複した際の制御を指定する。DP_DOVER は既存のレコードの値を上書きし、DP_DKEEP は既存のレコードを残してエラーを返し、DP_DCAT は指定された値を既存の値の末尾に加える。戻り値は正常なら真であり、エラーなら偽である。
レコードを削除するには、関数 dpout を用いる。
depot はライタで接続したデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。戻り値は正常なら真であり、エラーなら偽である。該当のレコードがない場合も偽を返す。
レコードを検索するには、関数 dpget を用いる。この関数の戻り値は malloc で確保された領域であり、不要になったら free で解放するべきである。
depot はデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。start は値の領域から抽出する最初のバイトのオフセットを指定する。max は値の領域から抽出するサイズをバイト数で指定するか、負数なら無制限となる。sp が NULL でなければ、その参照先に抽出した領域のバイト数を格納する。戻り値は正常なら値を格納したアロケートした領域へのポインタ、エラーなら NULL である。該当のレコードがない場合も NULL を返す。取り出そうとした値のサイズが start より小さかった場合には該当とみなさない。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。
レコードの値のサイズを取得するには、関数 dpvsiz を用いる。レコードの有無も調べられる。dpget と違って実データを読み込まないので効率がよい。
depot はデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。戻り値は該当レコードの値のバイト数であり、該当がなかったり、エラーの場合は -1 である。
データベースに格納された全てのレコードを参照するためのイテレータを初期化するには、関数 dpiterinit を用いる。
depot はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。
イテレータを初期化してから関数 dpiternext を呼び出すことで、順序は制御できないが、全てのレコードを1回ずつ参照することができる。この関数の戻り値は malloc で確保された領域であり、不要になったら free で解放するべきである。
depot はデータベースハンドルを指定する。sp が NULL でなければ、その参照先に抽出した領域のバイト数を格納する。戻り値は正常ならキーを格納したアロケートした領域へのポインタ、エラーなら NULL である。イテレータが最後まできて該当のレコードがない場合も NULL を返す。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。
データベースのアラインメントを設定には、関数 dpsetalign を用いる。アラインメントを設定しておくと、レコードの上書きを頻繁にする場合の処理効率が良くなる。アラインメントの基本サイズは、一連の更新操作をした後の状態での標準的な値のサイズを指定するのがよい。アラインメントのユニットサイズは、基本サイズの4倍から16倍程度にするのがよい。
depot はライタで接続したデータベースハンドルを指定する。asiz はアラインメントの基本サイズを指定する。aunit はアラインメントのユニットサイズを指定する。戻り値は正常なら真であり、エラーなら偽である。レコードの値を格納する領域のサイズは、アラインメントの倍数で確保される。アラインメントは値のサイズがユニットサイズに達するごとに基本サイズを倍加して算出される。アラインメントの設定はデータベースに保存されないので、データベースを開く度に指定すること。
データベースを更新した内容をファイルとデバイスに同期させるには、関数 dpsync を用いる。データベースを閉じないうちに別プロセスにデータベースファイルを利用させる場合に役立つ。
depot はライタで接続したデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。
レコードを削除したり、置換モードや連結モードで書き込みを繰り返す場合は、データベース内に不要な領域が蓄積する。不要領域を削除してデータベースを最適化するには、関数 dpoptimize を用いる。
depot はライタで接続したデータベースハンドルを指定する。bnum はバケット配列の新しい容量を指定するが、0 以下ならレコード数に最適な値が指定される。戻り値は正常なら真であり、エラーなら偽である。最適化の過程では一時ファイルを作成して元のファイルと置き換える。したがって、元のファイルに複数のリンクがある場合や、シンボリックリンクを使っている場合には注意が必要である。
データベースの名前を得るには、関数 dpname を用いる。
depot はデータベースハンドルを指定する。戻り値は正常なら値を格納したアロケートした領域へのポインタ、エラーなら NULL である。
データベースのファイルサイズを得るには、関数 dpfsiz を用いる。
depot はデータベースハンドルを指定する。戻り値は正常ならデータベースファイルのサイズ、エラーなら -1 である。
データベースのバケット配列の要素数を得るには、関数 dpbnum を用いる。
depot はデータベースハンドルを指定する。戻り値は正常ならデータベースのバケットの要素数、エラーなら -1 である。
データベースのバケット配列の利用要素数を得るには、関数 dpbusenum を用いる。
depot はデータベースハンドルを指定する。戻り値は正常ならバケット配列の利用要素数、エラーなら -1 である。
データベースのレコード数を得るには、関数 dprnum を用いる。
depot はデータベースハンドルを指定する。戻り値は正常ならデータベースのレコード数、エラーなら -1 である。
データベースの内部で用いるハッシュ関数として、dpinnerhash がある。アプリケーションがバケット配列の状態を予測する際に役立つ。
kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。戻り値はキーから31ビット長のハッシュ値を算出した値である。
データベースの内部で用いるハッシュ関数と独立したハッシュ関数として、dpouterhash がある。アプリケーションがデータベースの更に上でハッシュアルゴリズムを利用する際に役に立つ。
kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。戻り値はキーから31ビット長のハッシュ値を算出した値である。
ある数以上の素数を得るには、関数 dpprimenum を用いる。バケット配列のサイズを決める場合に役立つ。
num は適当な正の数を指定する。戻り値は、指定した数と同じかより大きくかつなるべく小さい素数である。
Depotを利用したプログラムをビルドするには、ライブラリ libqdbm.a または libqdbm.so をリンク対象に加える必要がある。例えば、hoge.c から hoge を作るには、以下のようにビルドを行う。
gcc -I/usr/local/include -L/usr/local/lib -o hoge hoge.c -lqdbm
Depotに対応するコマンドラインインタフェースは以下のものである。
dpm はDepotやそのアプリケーションのデバッグに役立つツールである。データベースを更新したり、状態を調べる機能を持つ。シェルスクリプトでデータベースアプリケーションを作るのにも利用できる。以下の書式で用いる。name はファイル名、key はレコードのキー、val はレコードの値を指定する。
dpm は処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。
dptest はDepotの機能テストや性能テストに用いるツールである。dptest によって生成されたデータベースファイルを dpm によって解析したり、time コマンドによって dptest の実行時間を計るとよい。以下の書式で用いる。name はファイル名、rnum はレコード数、bnum はバケット配列の要素数を指定する。
dptest は処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。
dptsv はタブ区切りでキーと値を表現した行からなるTSVファイルとDepotのデータベースを相互変換する。
TSVファイルを読み込んでデータベースを作成する場合は、以下の書式を用いる。name は作成するデータベース名を指定する。-bnum オプションの num はバケット配列の要素数を指定する。TSVのデータは標準入力から読み込む。キーが重複するレコードは後者を優先する。
データベースの全てのレコードをTSVファイルとして出力する場合は、以下の書式を用いる。name は作成するデータベース名を指定する。TSVのデータは標準出力される。
dptsv は処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。
CuriaはQDBMの拡張APIであり、複数のデータベースファイルをディレクトリで一括して扱う機能を提供する。データベースを複数のファイルに分割することで、ファイルシステムによるファイルサイズの制限を回避することができる。また、複数のデバイスにファイルを分散させることで、スケーラビリティが向上する。
Depotではファイル名を指定してデータベースを構築するが、Curiaではディレクトリ名を指定してデータベースを構築する。指定したディレクトリの下には、depot という名前のデータベースファイルが生成される。これはディレクトリの属性を保持するもので、レコードの実データは格納されない。それとは別に、データベースを分割した個数だけ、4桁の十進数値の名前を持つサブディレクトリが生成され、各々のサブディレクトリの中には depot という名前でデータベースファイルが生成される。レコードの実データはそれらに格納される。例えば、hoge という名前のデータベースを作成し、分割数を3にする場合、hoge/depot 、hoge/0001/depot 、hoge/0002/depot 、hoge/0003/depot が生成される。データベースを作成する際にすでにディレクトリが存在していてもエラーとはならない。したがって、予めサブディレクトリを生成しておいて、各々に異なるデバイスのファイルシステムをマウントしておけば、データベースファイルを複数のデバイスに分割して格納することができる。NFS等を利用すれば複数のファイルサーバにデータベースファイルを分散させることもできる。
Curiaを使うためには、depot.h と curia.h をインクルードすべきである。通常、ソースファイルの冒頭付近で以下の記述を行う。
Curiaでデータベースを扱う際には、CURIA型へのポインタをハンドルとして用いる。ハンドルは、cropen で開き、crclose で閉じる。ハンドルのメンバを直接参照することは推奨されない。
CuriaでもDepotと同じく外部変数 dpecode に直前のエラーコードが記録される。エラーコードに対応するメッセージ文字列を得るには、関数 dperrmsg を用いる。
データベースのハンドルを作成するには、関数 cropen を用いる。バケット配列の要素数はデータベースを作成する時に決められ、最適化以外の手段で変更することはできない。データベースファイルの分割数はデータベースを作成する時に指定したものから変更することはできない。バケット配列の要素数は、格納するレコード数の半分から4倍程度にするのがよい。データベースファイルの分割数の最大値は 256 個である。ライタ(読み書き両用モード)でデータベースファイルを開く際にはそのファイルに対して排他ロックがかけられ、リーダ(読み込み専用モード)で開く際には共有ロックがかけられる。その際には該当のロックがかけられるまでブロックする。
name はデータベースディレクトリの名前を指定する。omode は接続モードを指定し、CR_OREADER ならリーダ、CR_OWRITER ならライタとなる。omode が CR_OWRITER の場合、CR_OCREAT または CR_OTRUNC とのビット論理和にすることができる。CR_OCREAT はファイルが無い場合に新規作成することを指示し、CR_OTRUNC はファイルが存在しても作り直すことを指示する。bnum はバケット配列の要素数の目安を指定するが、0 以下ならデフォルト値が使われる。dnum は要素データベースの数を指定するが、0 以下ならデフォルト値が使われる。戻り値は正常ならデータベースハンドルであり、エラーなら NULL である。
一旦接続したデータベースハンドルは、処理が完了したら関数 crclose に渡してデータベースとの接続を閉じる必要がある。データベースの更新内容は、接続を閉じた時点で初めてファイルと同期される。ライタでデータベースを開いた場合、適切に閉じないとデータベースが破壊される。
curia はデータベースハンドルを指定する。戻り値は正常なら真であり、エラーなら偽である。閉じたハンドルの領域は解放されるので、以後は利用することができなくなる。
Curiaにはその他に以下の関数がある。これらの振舞いはDepotの対応する関数と同様なので、そちらを参照されたい。Depotの各関数の名前の接頭辞 dp を cr に読み変えれば対応がとれる。ただし、dperrmsg と dpinnerhash と dpouterhash と dpprimenum に対応する関数はCuriaにはない。
Curiaにはラージオブジェクトを扱う機能がある。通常のレコードのデータはデータベースファイルに格納されるが、ラージオブジェクトのレコードのデータは個別のファイルに格納される。ラージオブジェクトのファイルはハッシュ値を元にディレクトリに分けて格納されるので、通常のレコードには劣るが、それなりの速度で参照できる。サイズが大きく参照頻度が低いデータは、ラージオブジェクトとしてデータベースファイルから分離すべきである。そうすれば、通常のレコードに対する処理速度が向上する。ラージオブジェクトのディレクトリ階層はデータベースファイルが格納されるサブディレクトリの中の lob という名前のディレクトリの中に作られる。通常のデータベースとラージオブジェクトのデータベースはキー空間が異なり、互いに干渉することはない。関数 crfsiz 、crbnum 、crbusenum 、crrnum の値にはラージオブジェクトのレコードは反映されない。
ラージオブジェクト用データベースにレコードを追加するには、関数 crputlob を用いる。
curia はライタで接続したデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。vbuf は値のデータ領域のポインタを指定する。vsiz は値のデータ領域のサイズをバイト数で指定するか、-1 なら vbuf の文字列長となる。dmode は CR_DOVER か CR_DKEEP か CR_DCAT で、キーが既存レコードと重複した際の制御を指定する。CR_DOVER は既存のレコードの値を上書きし、CR_DKEEP は既存のレコードを残してエラーを返し、CR_DCAT は指定された値を既存の値の末尾に加える。戻り値は正常なら真であり、エラーなら偽である。通常のデータベースとラージオブジェクト用のデータベースはキー空間が異なり、ラージオブジェクトの追加操作によって通常のレコードに上書きや追加が起こることはない。
ラージオブジェクト用データベースからレコードを削除するには、関数 croutlob を用いる。
curia はライタで接続したデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。戻り値は正常なら真であり、エラーなら偽である。該当のレコードがない場合も偽を返す。通常のデータベースとラージオブジェクト用のデータベースはキー空間が異なり、ラージオブジェクトの削除操作によって通常のレコードの削除が起こることはない。
ラージオブジェクト用データベースからレコードの値を抽出するには、関数 crgetlob を用いる。
curia はデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。start は値の領域から抽出する最初のバイトのオフセットを指定する。max は値の領域から抽出するサイズをバイト数で指定するか、負数なら無制限となる。sp が NULL でなければ、その参照先に抽出した領域のバイト数を格納する。戻り値は正常なら値を格納したアロケートした領域へのポインタ、エラーなら NULL である。該当のレコードがない場合も NULL を返す。取り出そうとした値のサイズが start より小さかった場合には該当とみなさない。戻り値の領域は、実際には1バイト多く確保して終端文字が置かれるので、文字列として利用できる。通常のデータベースとラージオブジェクト用のデータベースはキー空間が異なり、ラージオブジェクトの検索操作によって通常のレコードが該当することはない。
ラージオブジェクト用データベースにあるレコードの値のサイズを取得するには、関数 crvsizlob を用いる。
curia はデータベースハンドルを指定する。kbuf はキーのデータ領域のポインタを指定する。ksiz はキーのデータ領域のサイズをバイト数で指定するか、負数なら kbuf の文字列長となる。戻り値は該当レコードの値のバイト数であり、該当がなかったり、エラーの場合は -1 である。通常のデータベースとラージオブジェクト用のデータベースはキー空間が異なり、ラージオブジェクトの検索操作によって通常のレコードが該当することはない。
ラージオブジェクト用データベースのレコード数を得るには、関数 crrnumlob を用いる。
curia はデータベースハンドルを指定する。戻り値は正常ならレコード数、エラーなら -1 である。
Curiaを利用したプログラムをビルドする方法は、Depotの場合と全く同じである。
Curiaに対応するコマンドラインインタフェースは以下のものである。
crm はCuriaやそのアプリケーションのデバッグに役立つツールである。データベースを更新したり、状態を調べる機能を持つ。シェルスクリプトでデータベースアプリケーションを作るのにも利用できる。以下の書式で用いる。name はディレクトリ名、key はレコードのキー、val はレコードの値を指定する。
crm は処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。
crtest はCuriaの機能テストや性能テストに用いるツールである。crtest によって生成されたデータベースディレクトリを crm によって解析したり、time コマンドによって crtest の実行時間を計るとよい。以下の書式で用いる。name はディレクトリ名、rnum はレコード数、bnum はバケット配列の要素数を指定する。
crtest は処理が正常に終了すれば 0 を返し、エラーがあればそれ以外の値を返して終了する。
Depotが管理するデータベースファイルの内容は、ヘッダ部、バケット部、レコード部の3つに大別される。
ヘッダ部はファイルの先頭から 48 バイトの固定長でとられ、以下の情報が記録される。
バケット部はヘッダ部の直後にバケット配列の要素数に応じた大きさでとられ、チェーンの先頭要素のオフセットが各要素に記録される。
レコード部はバケット部の直後からファイルの末尾までを占め、各レコードの以下の情報を持つ要素が記録される。
データベースファイルはスパースではないので、通常のファイルと同様に複製等の操作を行うことができる。Depotはバイトオーダの調整をしないでファイルの読み書きを行っているので、バイトオーダの異なる環境にデータベースファイルをコピーしてもそのままでは利用できない。
Segmentation Fault等によるクラッシュ、予期せぬデータの消失等の不整合、メモリリーク、その他諸々のバグに関して、既知のもので未修正のものはない。
Depotのデータベースは書き込みエラーに対して脆弱である。ロールバックやバックアップの機能はない。外的エラー要因への対処はアプリケーションに任される。例えば、ディスクが一杯になったり、シグナル等を受け取って処理を中断せざるを得ない時の対処がそれにあたる。
バグを発見したら、是非とも作者にフィードバックしてほしい。その際、QDBMのバージョンと、利用環境のOSとコンパイラのバージョンも教えてほしい。作者のメールアドレスは mikio@24h.co.jp である。
QDBMは平林幹雄が作成し、著作権を保持するものである。QDBMはGNU GENERAL PUBLIC LICENSE Version 2に基づくフリーソフトウェアとして無償で配布される。QDBMは誰でも自由に使用し、改編し、頒布することができる。一方で、QDBMは完全に無保証であり、その使用および不使用に伴ういかなる損害に対しても作者は責任を負わない。