久々にLMDBだ。
といっても、記事にするのが久々なだけで、毎日使っている。
にも関わらず、まだ理解できていないことが多い。
今回は、mdb_cursor_get()でMDB_NEXTを指定した場合についてだ。
cursorを使う場合、だいたいこんな感じになるだろう。
01: while ((retval = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 02: const char *p_key = (const char *)key.mv_data; 03: const char *p_data = (const char *)data.mv_data; 04: if (p_key[4] == '5') { 05: mdb_cursor_del(cursor, 0); 06: } 07: printf("key=%s, data=%s\n", p_key, p_data); 08: }
サンプルもこんな感じで、while()でMDB_NEXTを使って全部取得するようになっていたと思う。
で、上のコードではmdb_cursor_del()を使ってみた。
取得したデータの一部が「5」だったら、それを消したい、というわけだ。
やってみると、ちゃんと対象のデータだけが削除された。
ならいいじゃないか、と思いそうだが、気になったのはMDB_NEXTだ。
私は今まで「取得した後に次へ移動する」という意味だと思っていたのだ。
LMDBのドキュメントには"Position at next data item"と書かれているので、次のデータ位置にポジションを移動する、と解釈したのだ。
しかし実際は、「5」のデータを取得できた後でmdb_cursor_del()すると「5」のデータが消えたので、そういうわけではないのだ。
だから、「次へ移動して取得」という意味になる。
じゃあ、cursorをオープンした直後はどうなんだ?
カーソルの位置は先頭にあるだろうから、2番目のデータから取得されそうではないか。
しかし、そんなことはないのはわかっている。
ならば、オープンした直後はどうなっているのだ?
01: if ((retval = mdb_cursor_get(cursor, &key, &data, MDB_GET_CURRENT)) == 0) { 02: const char *p_key = (const char *)key.mv_data; 03: const char *p_data = (const char *)data.mv_data; 04: printf("KEY=%s, DATA=%s\n", p_key, p_data); 05: } else { 06: fprintf(stderr, "ERR(%u): %s\n", __LINE__, mdb_strerror(retval)); 07: }
これをオープンした直後に実行したのだが、エラーになった。
Invalid argumentだそうだ。
mdb_cursor_get(MDB_NEXT)でwhile()ループを抜けた後に実行してみると、最後に取得したデータが取れた。
つまり、mdb_cursor_get()は、opの動作をした後にカーソル位置のデータを取得するのだ。
opの動作ができない場合はエラーになるし、cursorのオープン直後はまだカーソル位置が先頭にもなっていないからMDB_GET_CURRENTはエラーになるということか。
どうにも気になっていたのに、確認しないまま使っていたのよねぇ。。。
不安だったので、削除するときはmdb_del()の方を使っていたのだ。
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。