Tokyo Cabinetでキーが重複したレコードを格納する
Tokyo Cabinetの仕様書を見ると、
B+木のデータベースでは、キーが重複する複数のレコードを格納することができます。このデータベースに対しては、ハッシュ表のデータベースと同様に、キーを指定してレコードを格納したり取り出したり削除したりすることができます。レコードはユーザが指示した比較関数に基づいて整列されて格納されます。カーソルを用いて各レコードを昇順または降順で参照することができます。この機構によって、文字列の前方一致検索や数値の範囲検索が可能になります。
とあるのだが、↓みたいにB+木のデータベースにキーが重複したレコードを格納しても格納されるのは「database -> oracle」のみとなる。
/* レコードを格納する */ if(!tcbdbput2(bdb, "database", "mysql") || !tcbdbput2(bdb, "database", "postgresql") || !tcbdbput2(bdb, "database", "oracle")){ ecode = tcbdbecode(bdb); fprintf(stderr, "put error: %s\n", tcbdberrmsg(ecode)); }
narazuya@bokkko% tcbmgr list -pv casket.tcb database oracle narazuya@bokkko%
う〜ん、何故だ?と思ってAPIを調べてたら、
bool tcbdbputdup2(TCBDB *bdb, const char *kstr, const char *vstr); `bdb' specifies the B+ tree database object connected as a writer. `kstr' specifies the string of the key. `vstr' specifies the string of the value. If successful, the return value is true, else, it is false. If a record with the same key exists in the database, the new record is placed after the existing one. The function `tcbdbputdup3' is used in order to store records into a B+ tree database object with allowing duplication of keys.
重複(duplicate)したキーを格納するには、後ろにdupの付いた関数を使わないといけないようだ。
/* レコードを格納する */ if(!tcbdbputdup2(bdb, "database", "mysql") || !tcbdbputdup2(bdb, "database", "postgresql") || !tcbdbputdup2(bdb, "database", "oracle")){ ecode = tcbdbecode(bdb); fprintf(stderr, "put error: %s\n", tcbdberrmsg(ecode)); }
narazuya@bokkko% tcbmgr list -pv casket.tcb database mysql database postgresql database oracle narazuya@bokkko%
ちなみに重複したキーのレコードを削除する場合、tcbdboutもしくはtcbdbout2だと最初の1つだけを削除し、
tcbdbout3だと該当するすべてのレコードを削除する。