<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,17 @@
+2009-03-11  Mikio Hirabayashi  &lt;mikio@users.sourceforge.net&gt;
+
+	* tcutil.c (tctopsort): new function.
+
+	* tchdb.c (tchdbfbpinsert, tchdbfbpsearch, tchdbfbpsplice): performance was improved.
+
+	* tchdb.c (tchdbwriterec): concurrency was improved.
+
+	* tctdb.c (tctdbqrysearchimpl): a bug related to the skip parameter was fixed.
+
+	* tctdb.c (tctdbputimpl, tctdbidxout, tctdbqrysearchimpl): performance was improved.
+
+	- Release: 1.4.11
+
 2009-03-02  Mikio Hirabayashi  &lt;mikio@users.sourceforge.net&gt;
 
 	* tcutil.c (tcmdbputproc, tcndbputfunc): removing mechanism was added.</diff>
      <filename>ChangeLog</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for tokyocabinet 1.4.10.
+# Generated by GNU Autoconf 2.61 for tokyocabinet 1.4.11.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@@ -572,8 +572,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='tokyocabinet'
 PACKAGE_TARNAME='tokyocabinet'
-PACKAGE_VERSION='1.4.10'
-PACKAGE_STRING='tokyocabinet 1.4.10'
+PACKAGE_VERSION='1.4.11'
+PACKAGE_STRING='tokyocabinet 1.4.11'
 PACKAGE_BUGREPORT=''
 
 # Factoring default headers for most tests.
@@ -1192,7 +1192,7 @@ if test &quot;$ac_init_help&quot; = &quot;long&quot;; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat &lt;&lt;_ACEOF
-\`configure' configures tokyocabinet 1.4.10 to adapt to many kinds of systems.
+\`configure' configures tokyocabinet 1.4.11 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1253,7 +1253,7 @@ fi
 
 if test -n &quot;$ac_init_help&quot;; then
   case $ac_init_help in
-     short | recursive ) echo &quot;Configuration of tokyocabinet 1.4.10:&quot;;;
+     short | recursive ) echo &quot;Configuration of tokyocabinet 1.4.11:&quot;;;
    esac
   cat &lt;&lt;\_ACEOF
 
@@ -1354,7 +1354,7 @@ fi
 test -n &quot;$ac_init_help&quot; &amp;&amp; exit $ac_status
 if $ac_init_version; then
   cat &lt;&lt;\_ACEOF
-tokyocabinet configure 1.4.10
+tokyocabinet configure 1.4.11
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1368,7 +1368,7 @@ cat &gt;config.log &lt;&lt;_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by tokyocabinet $as_me 1.4.10, which was
+It was created by tokyocabinet $as_me 1.4.11, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -1724,7 +1724,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 # Package information
 MYLIBVER=8
-MYLIBREV=1
+MYLIBREV=2
 MYFORMATVER=&quot;1.0&quot;
 
 # Targets
@@ -6351,7 +6351,7 @@ exec 6&gt;&amp;1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log=&quot;
-This file was extended by tokyocabinet $as_me 1.4.10, which was
+This file was extended by tokyocabinet $as_me 1.4.11, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6394,7 +6394,7 @@ Report bugs to &lt;bug-autoconf@gnu.org&gt;.&quot;
 _ACEOF
 cat &gt;&gt;$CONFIG_STATUS &lt;&lt;_ACEOF
 ac_cs_version=&quot;\\
-tokyocabinet config.status 1.4.10
+tokyocabinet config.status 1.4.11
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\&quot;`echo &quot;$ac_configure_args&quot; | sed 's/^ //; s/[\\&quot;&quot;\`\$]/\\\\&amp;/g'`\\&quot;
 </diff>
      <filename>configure</filename>
    </modified>
    <modified>
      <diff>@@ -7,11 +7,11 @@
 #================================================================
 
 # Package name
-AC_INIT(tokyocabinet, 1.4.10)
+AC_INIT(tokyocabinet, 1.4.11)
 
 # Package information
 MYLIBVER=8
-MYLIBREV=1
+MYLIBREV=2
 MYFORMATVER=&quot;1.0&quot;
 
 # Targets</diff>
      <filename>configure.in</filename>
    </modified>
    <modified>
      <diff>@@ -47,15 +47,28 @@
       switch((now.getMonth() + now.getDate() + now.getMinutes()) % 12){
       default: text = &quot;super hyper ultra database manager&quot;; break;
       case 1: text = &quot;much quicker database manager&quot;; break;
-      case 3: text = &quot;the uitimate database manager&quot;; break;
+      case 3: text = &quot;the ultimate database manager&quot;; break;
       case 5: text = &quot;the supreme database manager&quot;; break;
-      case 7: text = &quot;the lightning database manager&quot;; break;
+      case 7: text = &quot;the lightening database manager&quot;; break;
       case 9: text = &quot;the mighty unbeatable invincible database manager&quot;; break;
       case 11: text = &quot;the dinosaur wing of database managers&quot;; break;
       }
       elem.firstChild.nodeValue = label + &quot;: &quot; + text;
     }
   }
+  elem = document.getElementById(&quot;logo&quot;);
+  if(elem){
+    var rnd = Math.floor(Math.random() * 5);
+    if(rnd == 0){
+      elem.src = &quot;logo-g.png&quot;;
+      elem.removeAttribute(&quot;height&quot;);
+      elem.removeAttribute(&quot;width&quot;);
+    } else if(rnd == 1){
+      elem.src = &quot;logo-y.png&quot;;
+      elem.removeAttribute(&quot;height&quot;);
+      elem.removeAttribute(&quot;width&quot;);
+    }
+  }
 }
 &lt;/script&gt;
 &lt;/head&gt;
@@ -68,7 +81,7 @@
 &lt;div class=&quot;note&quot;&gt;Last Update: Fri, 13 Feb 2009 15:37:50 +0900&lt;/div&gt;
 &lt;div class=&quot;navi&quot;&gt;[&lt;span class=&quot;void&quot;&gt;English&lt;/span&gt;/&lt;a href=&quot;index.ja.html&quot; hreflang=&quot;ja&quot;&gt;Japanese&lt;/a&gt;]&lt;/div&gt;
 
-&lt;div class=&quot;logo&quot;&gt;&lt;img src=&quot;logo.png&quot; alt=&quot;Tokyo Cabinet&quot; width=&quot;300&quot; height=&quot;110&quot; /&gt;&lt;/div&gt;
+&lt;div class=&quot;logo&quot;&gt;&lt;img src=&quot;logo.png&quot; id=&quot;logo&quot; alt=&quot;Tokyo Cabinet&quot; width=&quot;300&quot; height=&quot;110&quot; /&gt;&lt;/div&gt;
 
 &lt;hr /&gt;
 
@@ -126,7 +139,7 @@
 &lt;p&gt;The following are the source packages of Tokyo Cabinet.  As for binary packages, see the site of each distributor.&lt;/p&gt;
 
 &lt;ul&gt;
-&lt;li&gt;&lt;a href=&quot;tokyocabinet-1.4.9.tar.gz&quot;&gt;Latest Source Package (version 1.4.9)&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href=&quot;tokyocabinet-1.4.11.tar.gz&quot;&gt;Latest Source Package (version 1.4.11)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;pastpkg/&quot;&gt;Past Versions&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
 </diff>
      <filename>doc/index.html</filename>
    </modified>
    <modified>
      <diff>@@ -97,6 +97,19 @@
       elem.firstChild.nodeValue = label + &quot;: &quot; + text;
     }
   }
+  elem = document.getElementById(&quot;logo&quot;);
+  if(elem){
+    var rnd = Math.floor(Math.random() * 5);
+    if(rnd == 0){
+      elem.src = &quot;logo-g.png&quot;;
+      elem.removeAttribute(&quot;height&quot;);
+      elem.removeAttribute(&quot;width&quot;);
+    } else if(rnd == 1){
+      elem.src = &quot;logo-y.png&quot;;
+      elem.removeAttribute(&quot;height&quot;);
+      elem.removeAttribute(&quot;width&quot;);
+    }
+  }
 }
 &lt;/script&gt;
 &lt;/head&gt;
@@ -109,7 +122,7 @@
 &lt;div class=&quot;note&quot;&gt;Last Update: Fri, 13 Feb 2009 15:37:50 +0900&lt;/div&gt;
 &lt;div class=&quot;navi&quot;&gt;[&lt;a href=&quot;index.html&quot; hreflang=&quot;en&quot;&gt;English&lt;/a&gt;/&lt;span class=&quot;void&quot;&gt;Japanese&lt;/span&gt;]&lt;/div&gt;
 
-&lt;div class=&quot;logo&quot;&gt;&lt;img src=&quot;logo-ja.png&quot; alt=&quot;Tokyo Cabinet&quot; width=&quot;300&quot; height=&quot;110&quot; /&gt;&lt;/div&gt;
+&lt;div class=&quot;logo&quot;&gt;&lt;img src=&quot;logo-ja.png&quot; id=&quot;logo&quot; alt=&quot;Tokyo Cabinet&quot; width=&quot;300&quot; height=&quot;110&quot; /&gt;&lt;/div&gt;
 
 &lt;hr /&gt;
 
@@ -167,7 +180,7 @@
 &lt;p&gt;&#20197;&#19979;&#12398;&#12477;&#12540;&#12473;&#12497;&#12483;&#12465;&#12540;&#12472;&#12434;&#12480;&#12454;&#12531;&#12525;&#12540;&#12489;&#12375;&#12390;&#12367;&#12384;&#12373;&#12356;&#12290;&#12496;&#12452;&#12490;&#12522;&#12497;&#12483;&#12465;&#12540;&#12472;&#12395;&#12388;&#12356;&#12390;&#12399;&#12289;&#21508;&#12487;&#12451;&#12473;&#12488;&#12522;&#12499;&#12517;&#12540;&#12479;&#12398;&#12469;&#12452;&#12488;&#12434;&#12372;&#35239;&#12367;&#12384;&#12373;&#12356;&#12290;&lt;/p&gt;
 
 &lt;ul&gt;
-&lt;li&gt;&lt;a href=&quot;tokyocabinet-1.4.9.tar.gz&quot;&gt;&#26368;&#26032;&#12398;&#12477;&#12540;&#12473;&#12497;&#12483;&#12465;&#12540;&#12472;&#65288;&#12496;&#12540;&#12472;&#12519;&#12531;1.4.9&#65289;&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href=&quot;tokyocabinet-1.4.11.tar.gz&quot;&gt;&#26368;&#26032;&#12398;&#12477;&#12540;&#12473;&#12497;&#12483;&#12465;&#12540;&#12472;&#65288;&#12496;&#12540;&#12472;&#12519;&#12531;1.4.11&#65289;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;pastpkg/&quot;&gt;&#36942;&#21435;&#12398;&#12496;&#12540;&#12472;&#12519;&#12531;&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
 </diff>
      <filename>doc/index.ja.html</filename>
    </modified>
    <modified>
      <diff>@@ -2206,6 +2206,17 @@
 &lt;dd&gt;`&lt;var&gt;buf&lt;/var&gt;' specifies the pointer to the region into which the result string is written.  The size of the buffer should be equal to or more than 48 bytes.&lt;/dd&gt;
 &lt;/dl&gt;
 
+&lt;p&gt;The function `tctopsort' is used in order to sort top records of an array.&lt;/p&gt;
+
+&lt;dl class=&quot;api&quot;&gt;
+&lt;dt&gt;&lt;code&gt;void tctopsort(void *&lt;var&gt;base&lt;/var&gt;, size_t &lt;var&gt;nmemb&lt;/var&gt;, size_t &lt;var&gt;size&lt;/var&gt;, size_t &lt;var&gt;top&lt;/var&gt;, int(*&lt;var&gt;compar&lt;/var&gt;)(const void *, const void *));&lt;/code&gt;&lt;/dt&gt;
+&lt;dd&gt;`&lt;var&gt;base&lt;/var&gt;' spacifies the pointer to an array.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;nmemb&lt;/var&gt;' specifies the number of elements of the array.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;size&lt;/var&gt;' specifies the size of each element.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;top&lt;/var&gt;' specifies the number of top records.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;compar&lt;/var&gt;' specifies the pointer to comparing function.  The two arguments specify the pointers of elements.  The comparing function should returns positive if the former is big, negative if the latter is big, 0 if both are equal.&lt;/dd&gt;
+&lt;/dl&gt;
+
 &lt;p&gt;The function `tcchidxnew' is used in order to create a consistent hashing object.&lt;/p&gt;
 
 &lt;dl class=&quot;api&quot;&gt;
@@ -5235,7 +5246,7 @@ int main(int argc, char **argv){
 &lt;dt&gt;&lt;code&gt;int tctdbecode(TCTDB *&lt;var&gt;tdb&lt;/var&gt;);&lt;/code&gt;&lt;/dt&gt;
 &lt;dd&gt;`&lt;var&gt;tdb&lt;/var&gt;' specifies the table database object.&lt;/dd&gt;
 &lt;dd&gt;The return value is the last happened error code.&lt;/dd&gt;
-&lt;dd&gt;The following error code is defined: `TCESUCCESS' for success, `TCETHREAD' for threading error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for miscellaneous error.&lt;/dd&gt;
+&lt;dd&gt;The following error codes are defined: `TCESUCCESS' for success, `TCETHREAD' for threading error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for miscellaneous error.&lt;/dd&gt;
 &lt;/dl&gt;
 
 &lt;p&gt;The function `tctdbsetmutex' is used in order to set mutual exclusion control of a table database object for threading.&lt;/p&gt;</diff>
      <filename>doc/spex-en.html</filename>
    </modified>
    <modified>
      <diff>@@ -2209,6 +2209,17 @@
 &lt;dd&gt;`&lt;var&gt;buf&lt;/var&gt;' specifies the pointer to the region into which the result string is written.  The size of the buffer should be equal to or more than 48 bytes.&lt;/dd&gt;
 &lt;/dl&gt;
 
+&lt;p&gt;The function `tctopsort' is used in order to sort top records of an array.&lt;/p&gt;
+
+&lt;dl class=&quot;api&quot;&gt;
+&lt;dt&gt;&lt;code&gt;void tctopsort(void *&lt;var&gt;base&lt;/var&gt;, size_t &lt;var&gt;nmemb&lt;/var&gt;, size_t &lt;var&gt;size&lt;/var&gt;, size_t &lt;var&gt;top&lt;/var&gt;, int(*&lt;var&gt;compar&lt;/var&gt;)(const void *, const void *));&lt;/code&gt;&lt;/dt&gt;
+&lt;dd&gt;`&lt;var&gt;base&lt;/var&gt;' spacifies the pointer to an array.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;nmemb&lt;/var&gt;' specifies the number of elements of the array.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;size&lt;/var&gt;' specifies the size of each element.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;top&lt;/var&gt;' specifies the number of top records.&lt;/dd&gt;
+&lt;dd&gt;`&lt;var&gt;compar&lt;/var&gt;' specifies the pointer to comparing function.  The two arguments specify the pointers of elements.  The comparing function should returns positive if the former is big, negative if the latter is big, 0 if both are equal.&lt;/dd&gt;
+&lt;/dl&gt;
+
 &lt;p&gt;The function `tcchidxnew' is used in order to create a consistent hashing object.&lt;/p&gt;
 
 &lt;dl class=&quot;api&quot;&gt;
@@ -5238,7 +5249,7 @@ int main(int argc, char **argv){
 &lt;dt&gt;&lt;code&gt;int tctdbecode(TCTDB *&lt;var&gt;tdb&lt;/var&gt;);&lt;/code&gt;&lt;/dt&gt;
 &lt;dd&gt;`&lt;var&gt;tdb&lt;/var&gt;' specifies the table database object.&lt;/dd&gt;
 &lt;dd&gt;The return value is the last happened error code.&lt;/dd&gt;
-&lt;dd&gt;The following error code is defined: `TCESUCCESS' for success, `TCETHREAD' for threading error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for miscellaneous error.&lt;/dd&gt;
+&lt;dd&gt;The following error codes are defined: `TCESUCCESS' for success, `TCETHREAD' for threading error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for miscellaneous error.&lt;/dd&gt;
 &lt;/dl&gt;
 
 &lt;p&gt;The function `tctdbsetmutex' is used in order to set mutual exclusion control of a table database object for threading.&lt;/p&gt;</diff>
      <filename>doc/spex-ja.html</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>doc/tokyoproducts.pdf</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>doc/tokyoproducts.ppt</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ use constant {
 my @commands = (
                 &quot;./tchtest write casket 1000000 1000000&quot;,
                 &quot;./tchtest read casket&quot;,
-                &quot;./tchtest rcat casket 100000&quot;,
+                &quot;./tchtest rcat casket 1000000&quot;,
                 &quot;./tcbtest write casket 1000000&quot;,
                 &quot;./tcbtest read casket&quot;,
                 &quot;./tcbtest rcat -lc 256 -nc 128 casket 100000&quot;,</diff>
      <filename>lab/stopwatch</filename>
    </modified>
    <modified>
      <diff>@@ -76,7 +76,7 @@ The function `tctdbecode' is used in order to get the last happened error code o
 The return value is the last happened error code.
 .RE
 .RS
-The following error code is defined: `TCESUCCESS' for success, `TCETHREAD' for threading error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for miscellaneous error.
+The following error codes are defined: `TCESUCCESS' for success, `TCETHREAD' for threading error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for miscellaneous error.
 .RE
 .RE
 .PP</diff>
      <filename>man/tctdb.3</filename>
    </modified>
    <modified>
      <diff>@@ -3543,6 +3543,28 @@ The function `tcmd5hash' is used in order to get the MD5 hash value of a record.
 .RE
 .RE
 .PP
+The function `tctopsort' is used in order to sort top records of an array.
+.PP
+.RS
+.br
+\fBvoid tctopsort(void *\fIbase\fB, size_t \fInmemb\fB, size_t \fIsize\fB, size_t \fItop\fB, int(*\fIcompar\fB)(const void *, const void *));\fR
+.RS
+`\fIbase\fR' spacifies the pointer to an array.
+.RE
+.RS
+`\fInmemb\fR' specifies the number of elements of the array.
+.RE
+.RS
+`\fIsize\fR' specifies the size of each element.
+.RE
+.RS
+`\fItop\fR' specifies the number of top records.
+.RE
+.RS
+`\fIcompar\fR' specifies the pointer to comparing function.  The two arguments specify the pointers of elements.  The comparing function should returns positive if the former is big, negative if the latter is big, 0 if both are equal.
+.RE
+.RE
+.PP
 The function `tcchidxnew' is used in order to create a consistent hashing object.
 .PP
 .RS</diff>
      <filename>man/tcutil.3</filename>
    </modified>
    <modified>
      <diff>@@ -44,9 +44,10 @@
 #define HDBXFSIZINC    32768             // increment of extra file size
 #define HDBMINRUNIT    48                // minimum record reading unit
 #define HDBMAXHSIZ     32                // maximum record header size
+#define HDBFBPALWRAT   2                 // allowance ratio of the free block pool
 #define HDBFBPBSIZ     64                // base region size of the free block pool
 #define HDBFBPESIZ     4                 // size of each region of the free block pool
-#define HDBFBPMGFREQ   256               // frequency to merge the free block pool
+#define HDBFBPMGFREQ   4096              // frequency to merge the free block pool
 #define HDBDRPUNIT     65536             // unit size of the delayed record pool
 #define HDBDRPLAT      2048              // latitude size of the delayed record pool
 #define HDBCACHEOUT    128               // number of records in a process of cacheout
@@ -2039,7 +2040,7 @@ static void tchdbsetbucket(TCHDB *hdb, uint64_t bidx, uint64_t off){
    The return value is true if successful, else, it is false. */
 static bool tchdbsavefbp(TCHDB *hdb){
   assert(hdb);
-  if(hdb-&gt;fbpnum &gt; (hdb-&gt;fbpmax &gt;&gt; 1)){
+  if(hdb-&gt;fbpnum &gt; hdb-&gt;fbpmax){
     tchdbfbpmerge(hdb);
   } else if(hdb-&gt;fbpnum &gt; 1){
     tcfbpsortbyoff(hdb-&gt;fbpool, hdb-&gt;fbpnum);
@@ -2089,7 +2090,7 @@ static bool tchdbloadfbp(TCHDB *hdb){
   }
   const char *rp = buf;
   HDBFB *cur = hdb-&gt;fbpool;
-  HDBFB *end = cur + hdb-&gt;fbpmax;
+  HDBFB *end = cur + hdb-&gt;fbpmax * HDBFBPALWRAT;
   uint64_t base = 0;
   while(cur &lt; end &amp;&amp; *rp != '\0'){
     int step;
@@ -2106,6 +2107,7 @@ static bool tchdbloadfbp(TCHDB *hdb){
   }
   hdb-&gt;fbpnum = cur - (HDBFB *)hdb-&gt;fbpool;
   TCFREE(buf);
+  tcfbpsortbyrsiz(hdb-&gt;fbpool, hdb-&gt;fbpnum);
   return true;
 }
 
@@ -2199,7 +2201,6 @@ static void tcfbpsortbyrsiz(HDBFB *fbpool, int fbpnum){
 static void tchdbfbpmerge(TCHDB *hdb){
   assert(hdb);
   TCDODEBUG(hdb-&gt;cnt_mergefbp++);
-  int32_t onum = hdb-&gt;fbpnum;
   tcfbpsortbyoff(hdb-&gt;fbpool, hdb-&gt;fbpnum);
   HDBFB *wp = hdb-&gt;fbpool;;
   HDBFB *cur = wp;
@@ -2218,7 +2219,7 @@ static void tchdbfbpmerge(TCHDB *hdb){
   }
   if(end-&gt;off &gt; 0) *(wp++) = *end;
   hdb-&gt;fbpnum = wp - (HDBFB *)hdb-&gt;fbpool;
-  hdb-&gt;fbpmis = (hdb-&gt;fbpnum &lt; onum) ? 0 : hdb-&gt;fbpnum * -2;
+  hdb-&gt;fbpmis = hdb-&gt;fbpnum * -1;
 }
 
 
@@ -2231,18 +2232,41 @@ static void tchdbfbpinsert(TCHDB *hdb, uint64_t off, uint32_t rsiz){
   TCDODEBUG(hdb-&gt;cnt_insertfbp++);
   if(hdb-&gt;fpow &lt; 1) return;
   HDBFB *pv = hdb-&gt;fbpool;
-  if(hdb-&gt;fbpnum &gt;= hdb-&gt;fbpmax){
+  if(hdb-&gt;fbpnum &gt;= hdb-&gt;fbpmax * HDBFBPALWRAT){
     tchdbfbpmerge(hdb);
     tcfbpsortbyrsiz(hdb-&gt;fbpool, hdb-&gt;fbpnum);
-    if(hdb-&gt;fbpnum &gt;= hdb-&gt;fbpmax){
+    int diff = hdb-&gt;fbpnum - hdb-&gt;fbpmax;
+    if(diff &gt; 0){
       TCDODEBUG(hdb-&gt;cnt_reducefbp++);
-      int32_t dnum = (hdb-&gt;fbpmax &gt;&gt; 2) + 1;
-      memmove(pv, pv + dnum, (hdb-&gt;fbpnum - dnum) * sizeof(*pv));
-      hdb-&gt;fbpnum -= dnum;
+      memmove(pv, pv + diff, (hdb-&gt;fbpnum - diff) * sizeof(*pv));
+      hdb-&gt;fbpnum -= diff;
     }
     hdb-&gt;fbpmis = 0;
   }
-  pv = pv + hdb-&gt;fbpnum;
+  int num = hdb-&gt;fbpnum;
+  int left = 0;
+  int right = num;
+  int i = (left + right) / 2;
+  int cand = -1;
+  while(right &gt;= left &amp;&amp; i &lt; num){
+    int rv = (int)rsiz - (int)pv[i].rsiz;
+    if(rv == 0){
+      cand = i;
+      break;
+    } else if(rv &lt;= 0){
+      cand = i;
+      right = i - 1;
+    } else {
+      left = i + 1;
+    }
+    i = (left + right) / 2;
+  }
+  if(cand &gt;= 0){
+    pv += cand;
+    memmove(pv + 1, pv, sizeof(*pv) * (num - cand));
+  } else {
+    pv += num;
+  }
   pv-&gt;off = off;
   pv-&gt;rsiz = rsiz;
   hdb-&gt;fbpnum++;
@@ -2263,30 +2287,43 @@ static bool tchdbfbpsearch(TCHDB *hdb, TCHREC *rec){
   }
   uint32_t rsiz = rec-&gt;rsiz;
   HDBFB *pv = hdb-&gt;fbpool;
-  HDBFB *ep = pv + hdb-&gt;fbpnum;
-  while(pv &lt; ep){
-    if(pv-&gt;rsiz &gt;= rsiz){
-      if(pv-&gt;rsiz &gt; rsiz * 2){
-        uint32_t psiz = tchdbpadsize(hdb, pv-&gt;off + rsiz);
-        uint64_t noff = pv-&gt;off + rsiz + psiz;
-        if(pv-&gt;rsiz &gt;= (noff - pv-&gt;off) * 2){
-          TCDODEBUG(hdb-&gt;cnt_dividefbp++);
-          rec-&gt;off = pv-&gt;off;
-          rec-&gt;rsiz = noff - pv-&gt;off;
-          pv-&gt;off = noff;
-          pv-&gt;rsiz -= rec-&gt;rsiz;
-          return tchdbwritefb(hdb, pv-&gt;off, pv-&gt;rsiz);
-        }
+  int num = hdb-&gt;fbpnum;
+  int left = 0;
+  int right = num;
+  int i = (left + right) / 2;
+  int cand = -1;
+  while(right &gt;= left &amp;&amp; i &lt; num){
+    int rv = (int)rsiz - (int)pv[i].rsiz;
+    if(rv == 0){
+      cand = i;
+      break;
+    } else if(rv &lt;= 0){
+      cand = i;
+      right = i - 1;
+    } else {
+      left = i + 1;
+    }
+    i = (left + right) / 2;
+  }
+  if(cand &gt;= 0){
+    pv += cand;
+    if(pv-&gt;rsiz &gt; rsiz * 2){
+      uint32_t psiz = tchdbpadsize(hdb, pv-&gt;off + rsiz);
+      uint64_t noff = pv-&gt;off + rsiz + psiz;
+      if(pv-&gt;rsiz &gt;= (noff - pv-&gt;off) * 2){
+        TCDODEBUG(hdb-&gt;cnt_dividefbp++);
+        rec-&gt;off = pv-&gt;off;
+        rec-&gt;rsiz = noff - pv-&gt;off;
+        pv-&gt;off = noff;
+        pv-&gt;rsiz -= rec-&gt;rsiz;
+        return tchdbwritefb(hdb, pv-&gt;off, pv-&gt;rsiz);
       }
-      rec-&gt;off = pv-&gt;off;
-      rec-&gt;rsiz = pv-&gt;rsiz;
-      ep--;
-      pv-&gt;off = ep-&gt;off;
-      pv-&gt;rsiz = ep-&gt;rsiz;
-      hdb-&gt;fbpnum--;
-      return true;
     }
-    pv++;
+    rec-&gt;off = pv-&gt;off;
+    rec-&gt;rsiz = pv-&gt;rsiz;
+    memmove(pv, pv + 1, sizeof(*pv) * (num - cand - 1));
+    hdb-&gt;fbpnum--;
+    return true;
   }
   rec-&gt;off = hdb-&gt;fsiz;
   rec-&gt;rsiz = 0;
@@ -2306,24 +2343,62 @@ static bool tchdbfbpsearch(TCHDB *hdb, TCHREC *rec){
    The return value is whether splicing succeeded or not. */
 static bool tchdbfbpsplice(TCHDB *hdb, TCHREC *rec, uint32_t nsiz){
   assert(hdb &amp;&amp; rec &amp;&amp; nsiz &gt; 0);
-  if(hdb-&gt;fbpnum &lt; 1) return false;
+  if(hdb-&gt;mmtx){
+    if(hdb-&gt;fbpnum &lt; 1) return false;
+    uint64_t off = rec-&gt;off + rec-&gt;rsiz;
+    uint32_t rsiz = rec-&gt;rsiz;
+    uint8_t magic;
+    if(tchdbseekreadtry(hdb, off, &amp;magic, sizeof(magic)) &amp;&amp; magic != HDBMAGICFB) return false;
+    HDBFB *pv = hdb-&gt;fbpool;
+    HDBFB *ep = pv + hdb-&gt;fbpnum;
+    while(pv &lt; ep){
+      if(pv-&gt;off == off &amp;&amp; rsiz + pv-&gt;rsiz &gt;= nsiz){
+        if(hdb-&gt;iter == pv-&gt;off) hdb-&gt;iter += pv-&gt;rsiz;
+        rec-&gt;rsiz += pv-&gt;rsiz;
+        ep--;
+        pv-&gt;off = ep-&gt;off;
+        pv-&gt;rsiz = ep-&gt;rsiz;
+        hdb-&gt;fbpnum--;
+        return true;
+      }
+      pv++;
+    }
+    return false;
+  }
   uint64_t off = rec-&gt;off + rec-&gt;rsiz;
-  uint32_t rsiz = rec-&gt;rsiz;
-  HDBFB *pv = hdb-&gt;fbpool;
-  HDBFB *ep = pv + hdb-&gt;fbpnum;
-  while(pv &lt; ep){
-    if(pv-&gt;off == off &amp;&amp; rsiz + pv-&gt;rsiz &gt;= nsiz){
-      if(hdb-&gt;iter == pv-&gt;off) hdb-&gt;iter += pv-&gt;rsiz;
-      rec-&gt;rsiz += pv-&gt;rsiz;
-      ep--;
-      pv-&gt;off = ep-&gt;off;
-      pv-&gt;rsiz = ep-&gt;rsiz;
-      hdb-&gt;fbpnum--;
-      return true;
+  TCHREC nrec;
+  char nbuf[HDBIOBUFSIZ];
+  while(off &lt; hdb-&gt;fsiz){
+    nrec.off = off;
+    if(!tchdbreadrec(hdb, &amp;nrec, nbuf)) return false;
+    if(nrec.magic != HDBMAGICFB) break;
+    if(hdb-&gt;iter == off) hdb-&gt;iter += nrec.rsiz;
+    off += nrec.rsiz;
+  }
+  uint32_t jsiz = off - rec-&gt;off;
+  if(jsiz &lt; nsiz) return false;
+  rec-&gt;rsiz = jsiz;
+  uint64_t base = rec-&gt;off;
+  HDBFB *wp = hdb-&gt;fbpool;;
+  HDBFB *cur = wp;
+  HDBFB *end = wp + hdb-&gt;fbpnum;
+  while(cur &lt; end){
+    if(cur-&gt;off &lt; base || cur-&gt;off &gt; off) *(wp++) = *cur;
+    cur++;
+  }
+  hdb-&gt;fbpnum = wp - (HDBFB *)hdb-&gt;fbpool;
+  if(jsiz &gt; nsiz * 2){
+    uint32_t psiz = tchdbpadsize(hdb, rec-&gt;off + nsiz);
+    uint64_t noff = rec-&gt;off + nsiz + psiz;
+    if(jsiz &gt;= (noff - rec-&gt;off) * 2){
+      TCDODEBUG(hdb-&gt;cnt_dividefbp++);
+      nsiz = off - noff;
+      if(!tchdbwritefb(hdb, noff, nsiz)) return false;
+      rec-&gt;rsiz = noff - rec-&gt;off;
+      tchdbfbpinsert(hdb, noff, nsiz);
     }
-    pv++;
   }
-  return false;
+  return true;
 }
 
 
@@ -2404,16 +2479,27 @@ static bool tchdbwriterec(TCHDB *hdb, TCHREC *rec, uint64_t bidx, off_t entoff){
     finc = rec-&gt;rsiz;
   } else if(rsiz &gt; rec-&gt;rsiz){
     if(rbuf != stack) TCFREE(rbuf);
+    if(!HDBLOCKDB(hdb)) return false;
     if(tchdbfbpsplice(hdb, rec, rsiz)){
       TCDODEBUG(hdb-&gt;cnt_splicefbp++);
-      return tchdbwriterec(hdb, rec, bidx, entoff);
+      bool rv = tchdbwriterec(hdb, rec, bidx, entoff);
+      HDBUNLOCKDB(hdb);
+      return rv;
     }
     TCDODEBUG(hdb-&gt;cnt_moverec++);
-    if(!tchdbwritefb(hdb, rec-&gt;off, rec-&gt;rsiz)) return false;
+    if(!tchdbwritefb(hdb, rec-&gt;off, rec-&gt;rsiz)){
+      HDBUNLOCKDB(hdb);
+      return false;
+    }
     tchdbfbpinsert(hdb, rec-&gt;off, rec-&gt;rsiz);
     rec-&gt;rsiz = rsiz;
-    if(!tchdbfbpsearch(hdb, rec)) return false;
-    return tchdbwriterec(hdb, rec, bidx, entoff);
+    if(!tchdbfbpsearch(hdb, rec)){
+      HDBUNLOCKDB(hdb);
+      return false;
+    }
+    bool rv = tchdbwriterec(hdb, rec, bidx, entoff);
+    HDBUNLOCKDB(hdb);
+    return rv;
   } else {
     TCDODEBUG(hdb-&gt;cnt_reuserec++);
     uint32_t psiz = rec-&gt;rsiz - rsiz;
@@ -2424,8 +2510,16 @@ static bool tchdbwriterec(TCHDB *hdb, TCHREC *rec, uint64_t bidx, off_t entoff){
       uint32_t nsiz = rec-&gt;rsiz - rsiz - psiz;
       rec-&gt;rsiz = noff - rec-&gt;off;
       rec-&gt;psiz = psiz;
-      if(!tchdbwritefb(hdb, noff, nsiz)) return false;
+      if(!tchdbwritefb(hdb, noff, nsiz)){
+        if(rbuf != stack) TCFREE(rbuf);
+        return false;
+      }
+      if(!HDBLOCKDB(hdb)){
+        if(rbuf != stack) TCFREE(rbuf);
+        return false;
+      }
       tchdbfbpinsert(hdb, noff, nsiz);
+      HDBUNLOCKDB(hdb);
     }
     rec-&gt;psiz = psiz;
   }
@@ -3056,7 +3150,7 @@ static bool tchdbopenimpl(TCHDB *hdb, const char *path, int omode){
   }
   hdb-&gt;fbpmax = 1 &lt;&lt; hdb-&gt;fpow;;
   if(omode &amp; HDBOWRITER){
-    TCMALLOC(hdb-&gt;fbpool, hdb-&gt;fbpmax * sizeof(HDBFB));
+    TCMALLOC(hdb-&gt;fbpool, hdb-&gt;fbpmax * HDBFBPALWRAT * sizeof(HDBFB));
   } else {
     hdb-&gt;fbpool = NULL;
   }
@@ -3208,7 +3302,7 @@ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx,
         entoff = rec.off + (sizeof(uint8_t) + sizeof(uint8_t)) +
           (hdb-&gt;ba64 ? sizeof(uint64_t) : sizeof(uint32_t));
       } else {
-        bool rv, lock;
+        bool rv;
         int nvsiz;
         char *nvbuf;
         HDBPDPROCOP *procptr;
@@ -3227,7 +3321,6 @@ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx,
             return false;
           }
           nvsiz = rec.vsiz + vsiz;
-          lock = vsiz + TCCALCVNUMSIZE(nvsiz) - TCCALCVNUMSIZE(rec.vsiz) &gt; rec.psiz;
           if(rec.bbuf){
             TCREALLOC(rec.bbuf, rec.bbuf, rec.ksiz + nvsiz);
             memcpy(rec.bbuf + rec.ksiz + rec.vsiz, vbuf, vsiz);
@@ -3241,16 +3334,6 @@ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx,
             rec.vbuf = rec.bbuf;
             rec.vsiz = nvsiz;
           }
-          if(lock){
-            if(!HDBLOCKDB(hdb)){
-              TCFREE(rec.bbuf);
-              return false;
-            }
-            rv = tchdbwriterec(hdb, &amp;rec, bidx, entoff);
-            HDBUNLOCKDB(hdb);
-            TCFREE(rec.bbuf);
-            return rv;
-          }
           rv = tchdbwriterec(hdb, &amp;rec, bidx, entoff);
           TCFREE(rec.bbuf);
           return rv;
@@ -3311,22 +3394,10 @@ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx,
           if(nvbuf == (void *)-1){
             return tchdbremoverec(hdb, &amp;rec, rbuf, bidx, entoff);
           } else if(nvbuf){
-            lock = nvsiz + TCCALCVNUMSIZE(nvsiz) - TCCALCVNUMSIZE(rec.vsiz) &gt;
-              rec.vsiz + rec.psiz;
             rec.kbuf = kbuf;
             rec.ksiz = ksiz;
             rec.vbuf = nvbuf;
             rec.vsiz = nvsiz;
-            if(lock){
-              if(!HDBLOCKDB(hdb)){
-                TCFREE(nvbuf);
-                return false;
-              }
-              rv = tchdbwriterec(hdb, &amp;rec, bidx, entoff);
-              HDBUNLOCKDB(hdb);
-              TCFREE(nvbuf);
-              return rv;
-            }
             rv = tchdbwriterec(hdb, &amp;rec, bidx, entoff);
             TCFREE(nvbuf);
             return rv;
@@ -3337,17 +3408,10 @@ static bool tchdbputimpl(TCHDB *hdb, const char *kbuf, int ksiz, uint64_t bidx,
           break;
         }
         TCFREE(rec.bbuf);
-        lock = vsiz + TCCALCVNUMSIZE(vsiz) - TCCALCVNUMSIZE(rec.vsiz) &gt; rec.vsiz + rec.psiz;
         rec.ksiz = ksiz;
         rec.vsiz = vsiz;
         rec.kbuf = kbuf;
         rec.vbuf = vbuf;
-        if(lock){
-          if(!HDBLOCKDB(hdb)) return false;
-          rv = tchdbwriterec(hdb, &amp;rec, bidx, entoff);
-          HDBUNLOCKDB(hdb);
-          return rv;
-        }
         return tchdbwriterec(hdb, &amp;rec, bidx, entoff);
       }
     }</diff>
      <filename>tchdb.c</filename>
    </modified>
    <modified>
      <diff>@@ -1399,23 +1399,41 @@ static bool tctdbputimpl(TCTDB *tdb, const void *pkbuf, int pksiz, TCMAP *cols,
       return false;
     }
     TCMAP *ocols = tcmapload(obuf, osiz);
-    if(!tctdbidxout(tdb, pkbuf, pksiz, ocols)) err = true;
     if(dmode == TDBPDCAT){
+      TCMAP *ncols = tcmapnew2(tcmaprnum(cols) + 1);
       tcmapiterinit(cols);
       const char *kbuf;
       int ksiz;
       while((kbuf = tcmapiternext(cols, &amp;ksiz)) != NULL){
         int vsiz;
         const char *vbuf = tcmapiterval(kbuf, &amp;vsiz);
-        tcmapput(ocols, kbuf, ksiz, vbuf, vsiz);
+        if(tcmapputkeep(ocols, kbuf, ksiz, vbuf, vsiz)) tcmapput(ncols, kbuf, ksiz, vbuf, vsiz);
       }
-      if(!tctdbidxput(tdb, pkbuf, pksiz, ocols)) err = true;
+      if(!tctdbidxput(tdb, pkbuf, pksiz, ncols)) err = true;
+      tcmapdel(ncols);
       int csiz;
       char *cbuf = tcmapdump(ocols, &amp;csiz);
       if(!tchdbput(tdb-&gt;hdb, pkbuf, pksiz, cbuf, csiz)) err = true;
       TCFREE(cbuf);
     } else {
-      if(!tctdbidxput(tdb, pkbuf, pksiz, cols)) err = true;
+      TCMAP *ncols = tcmapnew2(tcmaprnum(cols) + 1);
+      tcmapiterinit(cols);
+      const char *kbuf;
+      int ksiz;
+      while((kbuf = tcmapiternext(cols, &amp;ksiz)) != NULL){
+        int vsiz;
+        const char *vbuf = tcmapiterval(kbuf, &amp;vsiz);
+        int osiz;
+        const char *obuf = tcmapget(ocols, kbuf, ksiz, &amp;osiz);
+        if(obuf &amp;&amp; osiz == vsiz &amp;&amp; !memcmp(obuf, vbuf, osiz)){
+          tcmapout(ocols, kbuf, ksiz);
+        } else {
+          tcmapput(ncols, kbuf, ksiz, vbuf, vsiz);
+        }
+      }
+      if(!tctdbidxout(tdb, pkbuf, pksiz, ocols)) err = true;
+      if(!tctdbidxput(tdb, pkbuf, pksiz, ncols)) err = true;
+      tcmapdel(ncols);
       int csiz;
       char *cbuf = tcmapdump(cols, &amp;csiz);
       if(!tchdbput(tdb-&gt;hdb, pkbuf, pksiz, cbuf, csiz)) err = true;
@@ -2680,24 +2698,28 @@ static TCLIST *tctdbqrysearchimpl(TDBQRY *qry){
         key-&gt;vbuf = vbuf;
         key-&gt;vsiz = vsiz;
       }
+      int (*compar)(const TDBSORTKEY *a, const TDBSORTKEY *b) = NULL;
       switch(otype){
       case TDBQOSTRASC:
-        qsort(keys, rnum, sizeof(*keys),
-              (int(*)(const void *, const void *))tdbcmpsortkeystrasc);
+        compar = tdbcmpsortkeystrasc;
         break;
       case TDBQOSTRDESC:
-        qsort(keys, rnum, sizeof(*keys),
-              (int(*)(const void *, const void *))tdbcmpsortkeystrdesc);
+        compar = tdbcmpsortkeystrdesc;
         break;
       case TDBQONUMASC:
-        qsort(keys, rnum, sizeof(*keys),
-              (int(*)(const void *, const void *))tdbcmpsortkeynumasc);
+        compar = tdbcmpsortkeynumasc;
         break;
       case TDBQONUMDESC:
-        qsort(keys, rnum, sizeof(*keys),
-              (int(*)(const void *, const void *))tdbcmpsortkeynumdesc);
+        compar = tdbcmpsortkeynumdesc;
         break;
       }
+      if(compar){
+        if(max &lt;= rnum / 16){
+          tctopsort(keys, rnum, sizeof(*keys), max, (int (*)(const void *, const void *))compar);
+        } else {
+          qsort(keys, rnum, sizeof(*keys), (int (*)(const void *, const void *))compar);
+        }
+      }
       TCLIST *nres = tclistnew2(rnum);
       for(int i = 0; i &lt; rnum; i++){
         TDBSORTKEY *key = keys + i;
@@ -2719,6 +2741,7 @@ static TCLIST *tctdbqrysearchimpl(TDBQRY *qry){
       int rsiz;
       TCFREE(tclistshift(res, &amp;rsiz));
     }
+    max -= qry-&gt;skip;
   }
   if(TCLISTNUM(res) &gt; max){
     int left = TCLISTNUM(res) - max;
@@ -3215,34 +3238,32 @@ static bool tctdbidxout(TCTDB *tdb, const void *pkbuf, int pksiz, TCMAP *cols){
     for(int i = 0; i &lt; inum; i++){
       TDBIDX *idx = idxs + i;
       if(strcmp(idx-&gt;name, kbuf)) continue;
-      TCLIST *ovals;
+      BDBCUR *cur;
       switch(idx-&gt;type){
       case TDBITLEXICAL:
       case TDBITDECIMAL:
-        if((ovals = tcbdbget4(idx-&gt;db, vbuf, vsiz)) != NULL){
-          int on = TCLISTNUM(ovals);
-          for(int j = 0; j &lt; on; j++){
-            const char *obuf;
-            int osiz;
-            TCLISTVAL(obuf, ovals, j, osiz);
-            if(osiz == pksiz &amp;&amp; !memcmp(obuf, pkbuf, osiz)){
-              TCFREE(tclistremove(ovals, j, &amp;osiz));
+        cur = tcbdbcurnew(idx-&gt;db);
+        if(tcbdbcurjump(cur, vbuf, vsiz)){
+          int oksiz;
+          const char *okbuf;
+          while((okbuf = tcbdbcurkey3(cur, &amp;oksiz)) != NULL){
+            if(oksiz != vsiz || memcmp(okbuf, vbuf, oksiz)) break;
+            int ovsiz;
+            const char *ovbuf = tcbdbcurval3(cur, &amp;ovsiz);
+            if(ovsiz == pksiz &amp;&amp; !memcmp(ovbuf, pkbuf, ovsiz)){
+              if(!tcbdbcurout(cur)){
+                tctdbsetecode(tdb, tcbdbecode(idx-&gt;db), __FILE__, __LINE__, __func__);
+                err = true;
+              }
               break;
             }
+            tcbdbcurnext(cur);
           }
-          if(!tcbdbout3(idx-&gt;db, vbuf, vsiz)){
-            tctdbsetecode(tdb, tcbdbecode(idx-&gt;db), __FILE__, __LINE__, __func__);
-            err = true;
-          }
-          if(!tcbdbputdup3(idx-&gt;db, vbuf, vsiz, ovals)){
-            tctdbsetecode(tdb, tcbdbecode(idx-&gt;db), __FILE__, __LINE__, __func__);
-            err = true;
-          }
-          tclistdel(ovals);
         } else {
           tctdbsetecode(tdb, tcbdbecode(idx-&gt;db), __FILE__, __LINE__, __func__);
           err = true;
         }
+        tcbdbcurdel(cur);
         break;
       }
     }</diff>
      <filename>tctdb.c</filename>
    </modified>
    <modified>
      <diff>@@ -33,6 +33,7 @@ static void iputchar(int c);
 static void *pdprocfunc(const void *vbuf, int vsiz, int *sp, void *op);
 static bool iterfunc(const void *kbuf, int ksiz, const void *vbuf, int vsiz, void *op);
 static int myrand(int range);
+static int intcompar(const void *ap, const void *bp);
 static int runxstr(int argc, char **argv);
 static int runlist(int argc, char **argv);
 static int runmap(int argc, char **argv);
@@ -152,6 +153,12 @@ static int myrand(int range){
 }
 
 
+/* compare two integers */
+static int intcompar(const void *ap, const void *bp){
+  return *(int *)ap - *(int *)bp;
+}
+
+
 /* parse arguments of xstr command */
 static int runxstr(int argc, char **argv){
   char *rstr = NULL;
@@ -885,6 +892,23 @@ static int procmisc(int rnum){
         tcmd5hash(kbuf, ksiz, buf);
       }
       tcfree(buf);
+      anum = myrand(30) + 1;
+      int tary[anum], qary[anum];
+      for(int j = 0; j &lt; anum; j++){
+        int val = myrand(anum * 2 + 1);
+        tary[j] = val;
+        qary[j] = val;
+      }
+      int tnum = myrand(anum);
+      tctopsort(tary, anum, sizeof(*tary), tnum, intcompar);
+      qsort(qary, anum, sizeof(*qary), intcompar);
+      for(int j = 0; j &lt; tnum; j++){
+        if(tary[j] != qary[j]) err = true;
+      }
+      qsort(tary, anum, sizeof(*tary), intcompar);
+      for(int j = 0; j &lt; anum; j++){
+        if(tary[j] != qary[j]) err = true;
+      }
       TCCHIDX *chidx = tcchidxnew(5);
       for(int i = 0; i &lt; 10; i++){
         char kbuf[RECBUFSIZ];</diff>
      <filename>tcutest.c</filename>
    </modified>
    <modified>
      <diff>@@ -5083,6 +5083,68 @@ void tcmd5hash(const void *ptr, int size, char *buf){
 }
 
 
+/* Sort top records of an array. */
+void tctopsort(void *base, size_t nmemb, size_t size, size_t top,
+               int(*compar)(const void *, const void *)){
+  assert(base &amp;&amp; size &gt; 0 &amp;&amp; compar);
+  if(nmemb &lt; 1) return;
+  if(top &gt; nmemb) top = nmemb;
+  char *bp = base;
+  char *ep = bp + nmemb * size;
+  char *rp = bp + size;
+  int num = 1;
+  char swap[size];
+  while(rp &lt; ep){
+    if(num &lt; top){
+      int cidx = num;
+      while(cidx &gt; 0){
+        int pidx = (cidx - 1) / 2;
+        if(compar(bp + cidx * size, bp + pidx * size) &lt;= 0) break;
+        memcpy(swap, bp + cidx * size, size);
+        memcpy(bp + cidx * size, bp + pidx * size, size);
+        memcpy(bp + pidx * size, swap, size);
+        cidx = pidx;
+      }
+      num++;
+    } else if(compar(rp, bp) &lt; 0){
+      memcpy(swap, bp, size);
+      memcpy(bp, rp, size);
+      memcpy(rp, swap, size);
+      int pidx = 0;
+      int bot = num / 2;
+      while(pidx &lt; bot){
+        int cidx = pidx * 2 + 1;
+        if(cidx &lt; num - 1 &amp;&amp; compar(bp + cidx * size, bp + (cidx + 1) * size) &lt; 0) cidx++;
+        if(compar(bp + pidx * size, bp + cidx * size) &gt; 0) break;
+        memcpy(swap, bp + pidx * size, size);
+        memcpy(bp + pidx * size, bp + cidx * size, size);
+        memcpy(bp + cidx * size, swap, size);
+        pidx = cidx;
+      }
+    }
+    rp += size;
+  }
+  num = top - 1;
+  while(num &gt; 0){
+    memcpy(swap, bp, size);
+    memcpy(bp, bp + num * size, size);
+    memcpy(bp + num * size, swap, size);
+    int pidx = 0;
+    int bot = num / 2;
+    while(pidx &lt; bot){
+      int cidx = pidx * 2 + 1;
+      if(cidx &lt; num - 1 &amp;&amp; compar(bp + cidx * size, bp + (cidx + 1) * size) &lt; 0) cidx++;
+      if(compar(bp + pidx * size, bp + cidx * size) &gt; 0) break;
+      memcpy(swap, bp + pidx * size, size);
+      memcpy(bp + pidx * size, bp + cidx * size, size);
+      memcpy(bp + cidx * size, swap, size);
+      pidx = cidx;
+    }
+    num--;
+  }
+}
+
+
 /* Create a consistent hashing object. */
 TCCHIDX *tcchidxnew(int range){
   assert(range &gt; 0);</diff>
      <filename>tcutil.c</filename>
    </modified>
    <modified>
      <diff>@@ -2420,6 +2420,18 @@ char *tcregexreplace(const char *str, const char *regex, const char *alt);
 void tcmd5hash(const void *ptr, int size, char *buf);
 
 
+/* Sort top records of an array.
+   `base' spacifies the pointer to an array.
+   `nmemb' specifies the number of elements of the array.
+   `size' specifies the size of each element.
+   `top' specifies the number of top records.
+   `compar' specifies the pointer to comparing function.  The two arguments specify the pointers
+   of elements.  The comparing function should returns positive if the former is big, negative
+   if the latter is big, 0 if both are equal. */
+void tctopsort(void *base, size_t nmemb, size_t size, size_t top,
+               int(*compar)(const void *, const void *));
+
+
 /* Create a consistent hashing object.
    `range' specifies the number of nodes.  It should be more than 0.  The range of hash values is
    from 0 to less than the specified number.
@@ -3278,8 +3290,8 @@ typedef struct {                         /* type of structure for a bit stream o
 
 #include &lt;stdio.h&gt;
 
-#define _TC_VERSION    &quot;1.4.10&quot;
-#define _TC_LIBVER     801
+#define _TC_VERSION    &quot;1.4.11&quot;
+#define _TC_LIBVER     802
 #define _TC_FORMATVER  &quot;1.0&quot;
 
 enum {                                   /* enumeration for error codes */</diff>
      <filename>tcutil.h</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a203b0e05a815d8da472fa774fae46fdce93fe9d</id>
    </parent>
  </parents>
  <author>
    <name>Bob Ippolito</name>
    <email>bob@redivi.com</email>
  </author>
  <url>http://github.com/etrepum/tokyo-cabinet/commit/43aeab6c8c84e72658158fdffdee784760b93da0</url>
  <id>43aeab6c8c84e72658158fdffdee784760b93da0</id>
  <committed-date>2009-03-23T15:01:48-07:00</committed-date>
  <authored-date>2009-03-23T15:01:48-07:00</authored-date>
  <message>sync with tokyocabinet-1.4.11.tar.gz</message>
  <tree>9b76d00ae8655e4f8456806f8ead776e15dc3d52</tree>
  <committer>
    <name>Bob Ippolito</name>
    <email>bob@redivi.com</email>
  </committer>
</commit>
