这是tokyo cabinet的一个BUG么
最近在研读tokyo cabinet的代码,但是发现一个问题。
目前在跟进的是使用hash table实现的数据库文件,在项目的examples目录下面有一些作者写的demo文件演示如何使用的。我使用这里的tchdbex.c文件跟踪代码的运行情况,不过在里面加入了下面两行代码:
(代码前面加上+号的是我加上的两行代码)
可以看到,我在加入了记录(“foo”, “hop”)之后,对它进行了删除操作,在这之后紧跟着再次插入相同的记录。
tokyo cabinet的hash-table实现中,删除一条记录时会将塌存放到一个free pool类型的数组中,这里面保存了这条删除记录的大小和在文件中的偏移量。
问题在于,在加入记录时,记录的大小是32byte,删除记录时理所当然的也是删除一条大小为32byte的记录了,但是呢,紧跟着再次插入同样的记录时,代码中(tchdb.c):
其实,在上面的代码中,第二次插入记录的时候,查找可用的freepool失败之后继续往下走,最后真正插入到文件中的数据记录大小还是32的。
我给作者发去邮件,咨询这个问题,作者的回答大意是说我描述的这个现象确实存在,不过是有一定的考虑在里面的,后期会进行一些改进。我没有完全的把这部分代码阅读完毕,所以也就不好多说什么了,下面附上邮件内容,做一个记录,也为可能会发现这个问题的朋友提个醒吧。
我使用的版本是1.4.19。
目前在跟进的是使用hash table实现的数据库文件,在项目的examples目录下面有一些作者写的demo文件演示如何使用的。我使用这里的tchdbex.c文件跟踪代码的运行情况,不过在里面加入了下面两行代码:
/*
store records
*/
if ( ! tchdbput2(hdb, " foo " , " hop " ) ||
! tchdbput2(hdb, " bar " , " step " ) ||
! tchdbput2(hdb, " baz " , " jump " )){
ecode = tchdbecode(hdb);
fprintf(stderr, " put error: %s\n " , tchdberrmsg(ecode));
}
+ tchdbout2(hdb, " foo " );
+ tchdbput2(hdb, " foo " , " hop " );
if ( ! tchdbput2(hdb, " foo " , " hop " ) ||
! tchdbput2(hdb, " bar " , " step " ) ||
! tchdbput2(hdb, " baz " , " jump " )){
ecode = tchdbecode(hdb);
fprintf(stderr, " put error: %s\n " , tchdberrmsg(ecode));
}
+ tchdbout2(hdb, " foo " );
+ tchdbput2(hdb, " foo " , " hop " );
(代码前面加上+号的是我加上的两行代码)
可以看到,我在加入了记录(“foo”, “hop”)之后,对它进行了删除操作,在这之后紧跟着再次插入相同的记录。
tokyo cabinet的hash-table实现中,删除一条记录时会将塌存放到一个free pool类型的数组中,这里面保存了这条删除记录的大小和在文件中的偏移量。
问题在于,在加入记录时,记录的大小是32byte,删除记录时理所当然的也是删除一条大小为32byte的记录了,但是呢,紧跟着再次插入同样的记录时,代码中(tchdb.c):
3417
rec.rsiz
=
HDBMAXHSIZ
+
ksiz
+
vsiz;
3418 if ( ! tchdbfbpsearch(hdb, & re
3417行算出这条新插入的记录应该是38byte,于是走入下面的函数tchdbfbpsearch 查找能满足这个大小的freepool,之前返回的freepool是32,于是这个查找失败了,不得不重新分配空间来存放这个新的记录,而不是复用已经返回的空间---尽管前后两次插入的数据大小是一样的。
3418 if ( ! tchdbfbpsearch(hdb, & re
其实,在上面的代码中,第二次插入记录的时候,查找可用的freepool失败之后继续往下走,最后真正插入到文件中的数据记录大小还是32的。
我给作者发去邮件,咨询这个问题,作者的回答大意是说我描述的这个现象确实存在,不过是有一定的考虑在里面的,后期会进行一些改进。我没有完全的把这部分代码阅读完毕,所以也就不好多说什么了,下面附上邮件内容,做一个记录,也为可能会发现这个问题的朋友提个醒吧。
我使用的版本是1.4.19。
chuang
发送至 hirarin
显示详细信息 15 : 10 ( 6 小时前)
Hi, hirarin,recently, I try to read and trace the tokyocabinet source.
when I use the examples / tchdbex.c to trace hash - table, I find a problem.
In the file tchdbex.c, I add two lines:
/* store records */
if ( ! tchdbput2(hdb, " foo " , " hop " ) ||
! tchdbput2(hdb, " bar " , " step " ) ||
! tchdbput2(hdb, " baz " , " jump " )){
ecode = tchdbecode(hdb);
fprintf(stderr, " put error: %s\n " , tchdberrmsg(ecode));
}
+ tchdbout2(hdb, " foo " );
+ tchdbput2(hdb, " foo " , " hop " );
so, you can see that after insert key " foo " , " bar " and " baz " , I try to remove the record with the key " foo " , and then insert record ( " foo " , " hop " ) again.
But, when i use gdb to trace the program, i find that, when i first insert the record ( " foo " , " hop " ), the record size is 32 .
and then, when i remove the record ( " foo " , " hop " ), the record size is 32 , it is ok, then a free block with size 32 is inserted into the free block arrays.
But, when I insert record ( " foo " , " hop " ) once again, in the file tchdb.c: 3417 :
3417 rec.rsiz = HDBMAXHSIZ + ksiz + vsiz;
then the record size is 38
and then the next line it tries to find a free block fix to this size, but there is only free block with size 32 , so it is falied to find a free block.
I mean that, if I remove the record ( " foo " , " hop " ) and then try to insert it again, seems that it should use the free block with size 32 .Otherwise, there will be missing retrieval of the free block.
So, is it a bug ??
BTW: the version is 1.4 . 19
|
Mikio Hirabayashi
发送至 我
显示详细信息 16 : 37 ( 5 小时前)
Hi,
Thanks for the report.
It ' s not a bug but on purpose.
The header size is not calcurated at the line, I estimate it the
maximum size in theory.
However, I hit on an idia thanks to you. I ' ll change the logic to
reduce the file size.
Regards.
发送至 hirarin
显示详细信息 15 : 10 ( 6 小时前)
Hi, hirarin,recently, I try to read and trace the tokyocabinet source.
when I use the examples / tchdbex.c to trace hash - table, I find a problem.
In the file tchdbex.c, I add two lines:
/* store records */
if ( ! tchdbput2(hdb, " foo " , " hop " ) ||
! tchdbput2(hdb, " bar " , " step " ) ||
! tchdbput2(hdb, " baz " , " jump " )){
ecode = tchdbecode(hdb);
fprintf(stderr, " put error: %s\n " , tchdberrmsg(ecode));
}
+ tchdbout2(hdb, " foo " );
+ tchdbput2(hdb, " foo " , " hop " );
so, you can see that after insert key " foo " , " bar " and " baz " , I try to remove the record with the key " foo " , and then insert record ( " foo " , " hop " ) again.
But, when i use gdb to trace the program, i find that, when i first insert the record ( " foo " , " hop " ), the record size is 32 .
and then, when i remove the record ( " foo " , " hop " ), the record size is 32 , it is ok, then a free block with size 32 is inserted into the free block arrays.
But, when I insert record ( " foo " , " hop " ) once again, in the file tchdb.c: 3417 :
3417 rec.rsiz = HDBMAXHSIZ + ksiz + vsiz;
then the record size is 38
and then the next line it tries to find a free block fix to this size, but there is only free block with size 32 , so it is falied to find a free block.
I mean that, if I remove the record ( " foo " , " hop " ) and then try to insert it again, seems that it should use the free block with size 32 .Otherwise, there will be missing retrieval of the free block.
So, is it a bug ??
BTW: the version is 1.4 . 19
|
Mikio Hirabayashi
发送至 我
显示详细信息 16 : 37 ( 5 小时前)
Hi,
Thanks for the report.
It ' s not a bug but on purpose.
The header size is not calcurated at the line, I estimate it the
maximum size in theory.
However, I hit on an idia thanks to you. I ' ll change the logic to
reduce the file size.
Regards.