2017/11/18

[lmdb]mdb_dbi_close()は通常使わない

久しぶりにGoogle HomeやWindows10以外の話だ。
Cのlmdbで、mdb_drop()してエラーが発生したので悩んでいたのだ。


いま、C言語のlmdbを使っている。
「C言語の」とわざわざ書いたのは、どうもpythonなど他の言語にもAPIがあるようだったからだ。
今回はC言語版しか使っていないので、他については分からない。


困っていたのはmdb_drop()だったのだが、そもそもそれ以前にDB保存されているかどうかも危うかった。
ちょっと、まとめておこう。


lmdbの保存から見ていく。

https://gist.github.com/hirokuma/98b5010f4770267ab730efd3422be982

$ sudo apt install liblmdb-dev
$ gcc -o tst lmdb_drop.c -llmdb
$ rm -rf testdb
$ ./tst
$ mdb_dump -a testdb
VERSION=3
format=bytevalue
database=aaa
type=btree
mapsize=1048576
maxreaders=126
db_pagesize=4096
HEADER=END
  6161616161
  313233
DATA=END

databaseが"aaa"、keyが"aaaaa"で、dataが"123"だから、だいたいこんな感じの出力になるのではなかろうか(これはUbuntu 16.04で実行)。


ただ、77行目の「mdb_dbi_close()」のコメントアウトを外すと、DB保存自体されなくなった。
えー、そうなのー!!
順番が、txnの開始→dbi取得だったので、txnのcommitより前にdbiをcloseしてもよいのだろうと思っていたのだ。

確かに、mdb_dbi_close()の説明にも「Normally unnecessary」と書かれているのだ。
通常は不要=やっといても悪いことはない、という判断だったのだが、そうではないのだろう。


では、ここにもう1つdatabaseを追加する。
コメントアウトしている79~92行のコメントを外すのだ。
mdb_dbi_close()は、さっきの話があるので、生かせないのだ。

そうするとですな、dbiが2つ開くことになってしまい、このまま実行するとL82でassertしてしまうのだ。
どうするかというと、L28の引数を1から2に変更するのだ。
つまり、トランザクションを閉じるまでの間は開いていることになるので、その分のmaxdbsは確保しておきなさい、ということだ。


mdb_drop()がうまくいかなかったのも、同じ理由だ。
commit前にL124でmdb_dbi_close()していたので、削除できていなかったのだ。


分かってしまえば大したことはないのだけど、なかなか気付きにくかった。
「Normally unnecessary」というのは本当にそうだったのだけど、Normalって難しいですな。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。