LCOV - code coverage report
Current view: top level - backends/brass - brass_table.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 759 919 82.6 %
Date: 2011-08-21 Functions: 54 54 100.0 %
Branches: 386 532 72.6 %

           Branch data     Line data    Source code
       1                 :            : /* brass_table.cc: Btree implementation
       2                 :            :  *
       3                 :            :  * Copyright 1999,2000,2001 BrightStation PLC
       4                 :            :  * Copyright 2002 Ananova Ltd
       5                 :            :  * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Olly Betts
       6                 :            :  * Copyright 2008 Lemur Consulting Ltd
       7                 :            :  *
       8                 :            :  * This program is free software; you can redistribute it and/or
       9                 :            :  * modify it under the terms of the GNU General Public License as
      10                 :            :  * published by the Free Software Foundation; either version 2 of the
      11                 :            :  * License, or (at your option) any later version.
      12                 :            :  *
      13                 :            :  * This program is distributed in the hope that it will be useful,
      14                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16                 :            :  * GNU General Public License for more details.
      17                 :            :  *
      18                 :            :  * You should have received a copy of the GNU General Public License
      19                 :            :  * along with this program; if not, write to the Free Software
      20                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      21                 :            :  * USA
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <config.h>
      25                 :            : 
      26                 :            : #include "brass_table.h"
      27                 :            : 
      28                 :            : #include <xapian/error.h>
      29                 :            : 
      30                 :            : #include "safeerrno.h"
      31                 :            : #ifdef __WIN32__
      32                 :            : # include "msvc_posix_wrapper.h"
      33                 :            : #endif
      34                 :            : 
      35                 :            : #include "omassert.h"
      36                 :            : #include "str.h"
      37                 :            : #include "stringutils.h" // For STRINGIZE().
      38                 :            : 
      39                 :            : // Define to use "dangerous" mode - in this mode we write modified btree
      40                 :            : // blocks back in place.  This is somewhat faster (especially once we're
      41                 :            : // I/O bound) but the database can't be safely searched during indexing
      42                 :            : // and if indexing is terminated uncleanly, the database may be corrupt.
      43                 :            : //
      44                 :            : // Despite the risks, it's useful for speeding up a full rebuild.
      45                 :            : //
      46                 :            : // FIXME: make this mode run-time selectable, and record that it is currently
      47                 :            : // in use somewhere on disk, so readers can check and refuse to open the
      48                 :            : // database.
      49                 :            : //
      50                 :            : // #define DANGEROUS
      51                 :            : 
      52                 :            : #include <sys/types.h>
      53                 :            : 
      54                 :            : // Trying to include the correct headers with the correct defines set to
      55                 :            : // get pread() and pwrite() prototyped on every platform without breaking any
      56                 :            : // other platform is a real can of worms.  So instead we probe for what
      57                 :            : // prototypes (if any) are required in configure and put them into
      58                 :            : // PREAD_PROTOTYPE and PWRITE_PROTOTYPE.
      59                 :            : #if defined HAVE_PREAD && defined PREAD_PROTOTYPE
      60                 :            : PREAD_PROTOTYPE
      61                 :            : #endif
      62                 :            : #if defined HAVE_PWRITE && defined PWRITE_PROTOTYPE
      63                 :            : PWRITE_PROTOTYPE
      64                 :            : #endif
      65                 :            : 
      66                 :            : #include <cstdio>    /* for rename */
      67                 :            : #include <cstring>   /* for memmove */
      68                 :            : #include <climits>   /* for CHAR_BIT */
      69                 :            : 
      70                 :            : #include "brass_btreebase.h"
      71                 :            : #include "brass_cursor.h"
      72                 :            : 
      73                 :            : #include "debuglog.h"
      74                 :            : #include "io_utils.h"
      75                 :            : #include "omassert.h"
      76                 :            : #include "pack.h"
      77                 :            : #include "unaligned.h"
      78                 :            : #include "utils.h"
      79                 :            : 
      80                 :            : #include <algorithm>  // for std::min()
      81                 :            : #include <string>
      82                 :            : 
      83                 :            : using namespace Brass;
      84                 :            : using namespace std;
      85                 :            : 
      86                 :            : // Only try to compress tags longer than this many bytes.
      87                 :            : const size_t COMPRESS_MIN = 4;
      88                 :            : 
      89                 :            : //#define BTREE_DEBUG_FULL 1
      90                 :            : #undef BTREE_DEBUG_FULL
      91                 :            : 
      92                 :            : #ifdef BTREE_DEBUG_FULL
      93                 :            : /*------debugging aids from here--------*/
      94                 :            : 
      95                 :            : static void print_key(const byte * p, int c, int j);
      96                 :            : static void print_tag(const byte * p, int c, int j);
      97                 :            : 
      98                 :            : /*
      99                 :            : static void report_cursor(int N, Btree * B, Brass::Cursor * C)
     100                 :            : {
     101                 :            :     int i;
     102                 :            :     printf("%d)\n", N);
     103                 :            :     for (i = 0; i <= B->level; i++)
     104                 :            :         printf("p=%d, c=%d, n=[%d], rewrite=%d\n",
     105                 :            :                 C[i].p, C[i].c, C[i].n, C[i].rewrite);
     106                 :            : }
     107                 :            : */
     108                 :            : 
     109                 :            : /*------to here--------*/
     110                 :            : #endif /* BTREE_DEBUG_FULL */
     111                 :            : 
     112                 :      11233 : static inline byte *zeroed_new(size_t size)
     113                 :            : {
     114                 :      11233 :     byte *temp = new byte[size];
     115                 :            :     // No need to check if temp is NULL, new throws std::bad_alloc if
     116                 :            :     // allocation fails.
     117                 :            :     Assert(temp);
     118                 :      11233 :     memset(temp, 0, size);
     119                 :      11233 :     return temp;
     120                 :            : }
     121                 :            : 
     122                 :            : /* A B-tree comprises (a) a base file, containing essential information (Block
     123                 :            :    size, number of the B-tree root block etc), (b) a bitmap, the Nth bit of the
     124                 :            :    bitmap being set if the Nth block of the B-tree file is in use, and (c) a
     125                 :            :    file DB containing the B-tree proper. The DB file is divided into a sequence
     126                 :            :    of equal sized blocks, numbered 0, 1, 2 ... some of which are free, some in
     127                 :            :    use. Those in use are arranged in a tree.
     128                 :            : 
     129                 :            :    Each block, b, has a structure like this:
     130                 :            : 
     131                 :            :      R L M T D o1 o2 o3 ... oN <gap> [item] .. [item] .. [item] ...
     132                 :            :      <---------- D ----------> <-M->
     133                 :            : 
     134                 :            :    And then,
     135                 :            : 
     136                 :            :    R = REVISION(b)  is the revision number the B-tree had when the block was
     137                 :            :                     written into the DB file.
     138                 :            :    L = GET_LEVEL(b) is the level of the block, which is the number of levels
     139                 :            :                     towards the root of the B-tree structure. So leaf blocks
     140                 :            :                     have level 0 and the one root block has the highest level
     141                 :            :                     equal to the number of levels in the B-tree.
     142                 :            :    M = MAX_FREE(b)  is the size of the gap between the end of the directory and
     143                 :            :                     the first item of data. (It is not necessarily the maximum
     144                 :            :                     size among the bits of space that are free, but I can't
     145                 :            :                     think of a better name.)
     146                 :            :    T = TOTAL_FREE(b)is the total amount of free space left in b.
     147                 :            :    D = DIR_END(b)   gives the offset to the end of the directory.
     148                 :            : 
     149                 :            :    o1, o2 ... oN are a directory of offsets to the N items held in the block.
     150                 :            :    The items are key-tag pairs, and as they occur in the directory are ordered
     151                 :            :    by the keys.
     152                 :            : 
     153                 :            :    An item has this form:
     154                 :            : 
     155                 :            :            I K key x C tag
     156                 :            :              <--K-->
     157                 :            :            <------I------>
     158                 :            : 
     159                 :            :    A long tag presented through the API is split up into C tags small enough to
     160                 :            :    be accommodated in the blocks of the B-tree. The key is extended to include
     161                 :            :    a counter, x, which runs from 1 to C. The key is preceded by a length, K,
     162                 :            :    and the whole item with a length, I, as depicted above.
     163                 :            : 
     164                 :            :    Here are the corresponding definitions:
     165                 :            : 
     166                 :            : */
     167                 :            : 
     168                 :            : /** Flip to sequential addition block-splitting after this number of observed
     169                 :            :  *  sequential additions (in negated form). */
     170                 :            : #define SEQ_START_POINT (-10)
     171                 :            : 
     172                 :            : /* There are two bit maps in bit_map0 and bit_map. The nth bit of bitmap is 0
     173                 :            :    if the nth block is free, otherwise 1. bit_map0 is the initial state of
     174                 :            :    bitmap at the start of the current transaction.
     175                 :            : 
     176                 :            :    Note use of the limits.h values:
     177                 :            :    UCHAR_MAX = 255, an unsigned with all bits set, and
     178                 :            :    CHAR_BIT = 8, the number of bits per byte
     179                 :            : 
     180                 :            :    BYTE_PAIR_RANGE below is the smallest +ve number that can't be held in two
     181                 :            :    bytes -- 64K effectively.
     182                 :            : */
     183                 :            : 
     184                 :            : #define BYTE_PAIR_RANGE (1 << 2 * CHAR_BIT)
     185                 :            : 
     186                 :            : /// read_block(n, p) reads block n of the DB file to address p.
     187                 :            : void
     188                 :    6641155 : BrassTable::read_block(uint4 n, byte * p) const
     189                 :            : {
     190                 :            :     // Log the value of p, not the contents of the block it points to...
     191                 :            :     LOGCALL_VOID(DB, "BrassTable::read_block", n | (void*)p);
     192                 :            :     /* Use the base bit_map_size not the bitmap's size, because
     193                 :            :      * the latter is uninitialised in readonly mode.
     194                 :            :      */
     195                 :            :     Assert(n / CHAR_BIT < base.get_bit_map_size());
     196                 :            : 
     197                 :            : #ifdef HAVE_PREAD
     198                 :    6641155 :     off_t offset = off_t(block_size) * n;
     199                 :    6641155 :     int m = block_size;
     200                 :          0 :     while (true) {
     201                 :            :         ssize_t bytes_read = pread(handle, reinterpret_cast<char *>(p), m,
     202                 :    6641155 :                                    offset);
     203                 :            :         // normal case - read succeeded, so return.
     204         [ +  - ]:    6641155 :         if (bytes_read == m) return;
     205         [ #  # ]:          0 :         if (bytes_read == -1) {
     206         [ #  # ]:          0 :             if (errno == EINTR) continue;
     207                 :          0 :             string message = "Error reading block " + str(n) + ": ";
     208                 :          0 :             message += strerror(errno);
     209                 :          0 :             throw Xapian::DatabaseError(message);
     210         [ #  # ]:          0 :         } else if (bytes_read == 0) {
     211                 :          0 :             string message = "Error reading block " + str(n) + ": got end of file";
     212                 :          0 :             throw Xapian::DatabaseError(message);
     213         [ #  # ]:          0 :         } else if (bytes_read < m) {
     214                 :            :             /* Read part of the block, which is not an error.  We should
     215                 :            :              * continue reading the rest of the block.
     216                 :            :              */
     217                 :          0 :             m -= int(bytes_read);
     218                 :          0 :             p += bytes_read;
     219                 :          0 :             offset += bytes_read;
     220                 :            :         }
     221                 :            :     }
     222                 :            : #else
     223                 :            :     if (lseek(handle, off_t(block_size) * n, SEEK_SET) == -1) {
     224                 :            :         string message = "Error seeking to block: ";
     225                 :            :         message += strerror(errno);
     226                 :            :         throw Xapian::DatabaseError(message);
     227                 :            :     }
     228                 :            : 
     229                 :            :     io_read(handle, reinterpret_cast<char *>(p), block_size, block_size);
     230                 :            : #endif
     231                 :            : }
     232                 :            : 
     233                 :            : /** write_block(n, p) writes block n in the DB file from address p.
     234                 :            :  *  When writing we check to see if the DB file has already been
     235                 :            :  *  modified. If not (so this is the first write) the old base is
     236                 :            :  *  deleted. This prevents the possibility of it being opened
     237                 :            :  *  subsequently as an invalid base.
     238                 :            :  */
     239                 :            : void
     240                 :     321693 : BrassTable::write_block(uint4 n, const byte * p) const
     241                 :            : {
     242                 :            :     LOGCALL_VOID(DB, "BrassTable::write_block", n | p);
     243                 :            :     Assert(writable);
     244                 :            :     /* Check that n is in range. */
     245                 :            :     Assert(n / CHAR_BIT < base.get_bit_map_size());
     246                 :            : 
     247                 :            :     /* don't write to non-free */;
     248                 :            :     AssertParanoid(base.block_free_at_start(n));
     249                 :            : 
     250                 :            :     /* write revision is okay */
     251                 :            :     AssertEqParanoid(REVISION(p), latest_revision_number + 1);
     252                 :            : 
     253         [ +  + ]:     321693 :     if (both_bases) {
     254                 :            :         // Delete the old base before modifying the database.
     255                 :            :         //
     256                 :            :         // If the file is on NFS, then io_unlink() may return false even if
     257                 :            :         // the file was removed, so on balance throwing an exception in this
     258                 :            :         // case is unhelpful, since we wanted the file gone anyway!  The
     259                 :            :         // likely explanation is that somebody moved, deleted, or changed a
     260                 :            :         // symlink to the database directory.
     261                 :        586 :         (void)io_unlink(name + "base" + other_base_letter());
     262                 :        586 :         both_bases = false;
     263                 :        586 :         latest_revision_number = revision_number;
     264                 :            :     }
     265                 :            : 
     266                 :            : #ifdef HAVE_PWRITE
     267                 :     321693 :     off_t offset = off_t(block_size) * n;
     268                 :     321693 :     int m = block_size;
     269                 :          0 :     while (true) {
     270                 :     321693 :         ssize_t bytes_written = pwrite(handle, p, m, offset);
     271         [ +  - ]:     321693 :         if (bytes_written == m) {
     272                 :            :             // normal case - write succeeded, so return.
     273                 :            :             return;
     274         [ #  # ]:          0 :         } else if (bytes_written == -1) {
     275         [ #  # ]:          0 :             if (errno == EINTR) continue;
     276                 :          0 :             string message = "Error writing block: ";
     277                 :          0 :             message += strerror(errno);
     278                 :          0 :             throw Xapian::DatabaseError(message);
     279         [ #  # ]:          0 :         } else if (bytes_written == 0) {
     280                 :          0 :             string message = "Error writing block: wrote no data";
     281                 :          0 :             throw Xapian::DatabaseError(message);
     282         [ #  # ]:          0 :         } else if (bytes_written < m) {
     283                 :            :             /* Wrote part of the block, which is not an error.  We should
     284                 :            :              * continue writing the rest of the block.
     285                 :            :              */
     286                 :          0 :             m -= bytes_written;
     287                 :          0 :             p += bytes_written;
     288                 :          0 :             offset += bytes_written;
     289                 :            :         }
     290                 :            :     }
     291                 :            : #else
     292                 :            :     if (lseek(handle, (off_t)block_size * n, SEEK_SET) == -1) {
     293                 :            :         string message = "Error seeking to block: ";
     294                 :            :         message += strerror(errno);
     295                 :            :         throw Xapian::DatabaseError(message);
     296                 :            :     }
     297                 :            : 
     298                 :            :     io_write(handle, reinterpret_cast<const char *>(p), block_size);
     299                 :            : #endif
     300                 :            : }
     301                 :            : 
     302                 :            : 
     303                 :            : /* A note on cursors:
     304                 :            : 
     305                 :            :    Each B-tree level has a corresponding array element C[j] in a
     306                 :            :    cursor, C. C[0] is the leaf (or data) level, and C[B->level] is the
     307                 :            :    root block level. Within a level j,
     308                 :            : 
     309                 :            :        C[j].p  addresses the block
     310                 :            :        C[j].c  is the offset into the directory entry in the block
     311                 :            :        C[j].n  is the number of the block at C[j].p
     312                 :            : 
     313                 :            :    A look up in the B-tree causes navigation of the blocks starting
     314                 :            :    from the root. In each block, p, we find an offset, c, to an item
     315                 :            :    which gives the number, n, of the block for the next level. This
     316                 :            :    leads to an array of values p,c,n which are held inside the cursor.
     317                 :            : 
     318                 :            :    Any Btree object B has a built-in cursor, at B->C. But other cursors may
     319                 :            :    be created.  If BC is a created cursor, BC->C is the cursor in the
     320                 :            :    sense given above, and BC->B is the handle for the B-tree again.
     321                 :            : */
     322                 :            : 
     323                 :            : 
     324                 :            : void
     325                 :          5 : BrassTable::set_overwritten() const
     326                 :            : {
     327                 :            :     LOGCALL_VOID(DB, "BrassTable::set_overwritten", NO_ARGS);
     328                 :            :     // If we're writable, there shouldn't be another writer who could cause
     329                 :            :     // overwritten to be flagged, so that's a DatabaseCorruptError.
     330         [ -  + ]:          5 :     if (writable)
     331                 :          0 :         throw Xapian::DatabaseCorruptError("Db block overwritten - are there multiple writers?");
     332                 :          5 :     throw Xapian::DatabaseModifiedError("The revision being read has been discarded - you should call Xapian::Database::reopen() and retry the operation");
     333                 :            : }
     334                 :            : 
     335                 :            : /* block_to_cursor(C, j, n) puts block n into position C[j] of cursor
     336                 :            :    C, writing the block currently at C[j] back to disk if necessary.
     337                 :            :    Note that
     338                 :            : 
     339                 :            :        C[j].rewrite
     340                 :            : 
     341                 :            :    is true iff C[j].n is different from block n in file DB. If it is
     342                 :            :    false no rewriting is necessary.
     343                 :            : */
     344                 :            : 
     345                 :            : void
     346                 :    9520865 : BrassTable::block_to_cursor(Brass::Cursor * C_, int j, uint4 n) const
     347                 :            : {
     348                 :            :     LOGCALL_VOID(DB, "BrassTable::block_to_cursor", (void*)C_ | j | n);
     349         [ +  + ]:    9520865 :     if (n == C_[j].n) return;
     350                 :    6822148 :     byte * p = C_[j].p;
     351                 :            :     Assert(p);
     352                 :            : 
     353                 :            :     // FIXME: only needs to be done in write mode
     354         [ +  + ]:    6822148 :     if (C_[j].rewrite) {
     355                 :            :         Assert(writable);
     356                 :            :         Assert(C == C_);
     357                 :     303081 :         write_block(C_[j].n, p);
     358                 :     303081 :         C_[j].rewrite = false;
     359                 :            :     }
     360                 :            : 
     361                 :            :     // Check if the block is in the built-in cursor (potentially in
     362                 :            :     // modified form).
     363 [ +  + ][ +  + ]:    7018081 :     if (writable && n == C[j].n) {
     364         [ +  - ]:     195933 :         if (p != C[j].p)
     365                 :     195933 :             memcpy(p, C[j].p, block_size);
     366                 :            :     } else {
     367                 :    6626215 :         read_block(n, p);
     368                 :            :     }
     369                 :            : 
     370                 :    6822148 :     C_[j].n = n;
     371         [ +  + ]:    6822148 :     if (j < level) {
     372                 :            :         /* unsigned comparison */
     373         [ +  + ]:    6814092 :         if (rare(REVISION(p) > REVISION(C_[j + 1].p))) {
     374                 :          5 :             set_overwritten();
     375                 :            :             return;
     376                 :            :         }
     377                 :            :     }
     378                 :            : 
     379         [ -  + ]:    6822143 :     if (rare(j != GET_LEVEL(p))) {
     380                 :          0 :         string msg = "Expected block ";
     381                 :          0 :         msg += str(j);
     382                 :          0 :         msg += ", not ";
     383                 :          0 :         msg += str(GET_LEVEL(p));
     384                 :    9520860 :         throw Xapian::DatabaseCorruptError(msg);
     385                 :            :     }
     386                 :            : }
     387                 :            : 
     388                 :            : /** Btree::alter(); is called when the B-tree is to be altered.
     389                 :            : 
     390                 :            :    It causes new blocks to be forced for the current set of blocks in
     391                 :            :    the cursor.
     392                 :            : 
     393                 :            :    The point is that if a block at level 0 is to be altered it may get
     394                 :            :    a new number. Then the pointer to this block from level 1 will need
     395                 :            :    changing. So the block at level 1 needs altering and may get a new
     396                 :            :    block number. Then the pointer to this block from level 2 will need
     397                 :            :    changing ... and so on back to the root.
     398                 :            : 
     399                 :            :    The clever bit here is spotting the cases when we can make an early
     400                 :            :    exit from this process. If C[j].rewrite is true, C[j+k].rewrite
     401                 :            :    will be true for k = 1,2 ... We have been through all this before,
     402                 :            :    and there is no need to do it again. If C[j].n was free at the
     403                 :            :    start of the transaction, we can copy it back to the same place
     404                 :            :    without violating the integrity of the B-tree. We don't then need a
     405                 :            :    new n and can return. The corresponding C[j].rewrite may be true or
     406                 :            :    false in that case.
     407                 :            : */
     408                 :            : 
     409                 :            : void
     410                 :    1401740 : BrassTable::alter()
     411                 :            : {
     412                 :            :     LOGCALL_VOID(DB, "BrassTable::alter", NO_ARGS);
     413                 :            :     Assert(writable);
     414                 :            : #ifdef DANGEROUS
     415                 :            :     C[0].rewrite = true;
     416                 :            : #else
     417                 :    1401740 :     int j = 0;
     418                 :    1401740 :     byte * p = C[j].p;
     419                 :    1402634 :     while (true) {
     420         [ +  + ]:    1402634 :         if (C[j].rewrite) return; /* all new, so return */
     421                 :     303912 :         C[j].rewrite = true;
     422                 :            : 
     423                 :     303912 :         uint4 n = C[j].n;
     424         [ +  + ]:     303912 :         if (base.block_free_at_start(n)) {
     425                 :            :             Assert(REVISION(p) == latest_revision_number + 1);
     426                 :     302425 :             return;
     427                 :            :         }
     428                 :            :         Assert(REVISION(p) < latest_revision_number + 1);
     429                 :       1487 :         base.free_block(n);
     430                 :       1487 :         n = base.next_free_block();
     431                 :       1487 :         C[j].n = n;
     432                 :       1487 :         SET_REVISION(p, latest_revision_number + 1);
     433                 :            : 
     434         [ +  + ]:       1487 :         if (j == level) return;
     435                 :        894 :         j++;
     436                 :        894 :         p = C[j].p;
     437                 :        894 :         Item_wr(p, C[j].c).set_block_given_by(n);
     438                 :            :     }
     439                 :            : #endif
     440                 :            : }
     441                 :            : 
     442                 :            : /** find_in_block(p, key, leaf, c) searches for the key in the block at p.
     443                 :            : 
     444                 :            :    leaf is true for a data block, and false for an index block (when the
     445                 :            :    first key is dummy and never needs to be tested). What we get is the
     446                 :            :    directory entry to the last key <= the key being searched for.
     447                 :            : 
     448                 :            :    The lookup is by binary chop, with i and j set to the left and
     449                 :            :    right ends of the search area. In sequential addition, c will often
     450                 :            :    be the answer, so we test the keys round c and move i and j towards
     451                 :            :    c if possible.
     452                 :            : */
     453                 :            : 
     454                 :            : int
     455                 :   11611641 : BrassTable::find_in_block(const byte * p, Key key, bool leaf, int c)
     456                 :            : {
     457                 :            :     LOGCALL_STATIC(DB, int, "BrassTable::find_in_block", (void*)p | (const void *)key.get_address() | leaf | c);
     458                 :   11611641 :     int i = DIR_START;
     459         [ +  + ]:   11611641 :     if (leaf) i -= D2;
     460                 :   11611641 :     int j = DIR_END(p);
     461                 :            : 
     462         [ +  + ]:   11611641 :     if (c != -1) {
     463 [ +  + ][ +  + ]:    5870586 :         if (c < j && i < c && Item(p, c).key() <= key)
         [ +  + ][ +  + ]
     464                 :    5172917 :             i = c;
     465                 :    5870586 :         c += D2;
     466 [ +  + ][ +  + ]:    5870586 :         if (c < j && i < c && key < Item(p, c).key())
         [ +  + ][ +  + ]
     467                 :    1618359 :             j = c;
     468                 :            :     }
     469                 :            : 
     470         [ +  + ]:   41654167 :     while (j - i > D2) {
     471                 :   30042526 :         int k = i + ((j - i)/(D2 * 2))*D2; /* mid way */
     472         [ +  + ]:   30042526 :         if (key < Item(p, k).key()) j = k; else i = k;
     473                 :            :     }
     474                 :   11611641 :     RETURN(i);
     475                 :            : }
     476                 :            : 
     477                 :            : /** find(C_) searches for the key of B->kt in the B-tree.
     478                 :            : 
     479                 :            :    Result is true if found, false otherwise.  When false, the B_tree
     480                 :            :    cursor is positioned at the last key in the B-tree <= the search
     481                 :            :    key.  Goes to first (null) item in B-tree when key length == 0.
     482                 :            : */
     483                 :            : 
     484                 :            : bool
     485                 :    4541018 : BrassTable::find(Brass::Cursor * C_) const
     486                 :            : {
     487                 :            :     LOGCALL(DB, bool, "BrassTable::find", (void*)C_);
     488                 :            :     // Note: the parameter is needed when we're called by BrassCursor
     489                 :            :     const byte * p;
     490                 :            :     int c;
     491                 :    4541018 :     Key key = kt.key();
     492         [ +  + ]:   11594916 :     for (int j = level; j > 0; --j) {
     493                 :    7053903 :         p = C_[j].p;
     494                 :    7053903 :         c = find_in_block(p, key, false, C_[j].c);
     495                 :            : #ifdef BTREE_DEBUG_FULL
     496                 :            :         printf("Block in BrassTable:find - code position 1");
     497                 :            :         report_block_full(j, C_[j].n, p);
     498                 :            : #endif /* BTREE_DEBUG_FULL */
     499                 :    7053903 :         C_[j].c = c;
     500                 :    7053903 :         block_to_cursor(C_, j - 1, Item(p, c).block_given_by());
     501                 :            :     }
     502                 :    4541013 :     p = C_[0].p;
     503                 :    4541013 :     c = find_in_block(p, key, true, C_[0].c);
     504                 :            : #ifdef BTREE_DEBUG_FULL
     505                 :            :     printf("Block in BrassTable:find - code position 2");
     506                 :            :     report_block_full(0, C_[0].n, p);
     507                 :            : #endif /* BTREE_DEBUG_FULL */
     508                 :    4541013 :     C_[0].c = c;
     509         [ +  + ]:    4541013 :     if (c < DIR_START) RETURN(false);
     510                 :    4541013 :     RETURN(Item(p, c).key() == key);
     511                 :            : }
     512                 :            : 
     513                 :            : /** compact(p) compact the block at p by shuffling all the items up to the end.
     514                 :            : 
     515                 :            :    MAX_FREE(p) is then maximized, and is equal to TOTAL_FREE(p).
     516                 :            : */
     517                 :            : 
     518                 :            : void
     519                 :      34605 : BrassTable::compact(byte * p)
     520                 :            : {
     521                 :            :     LOGCALL_VOID(DB, "BrassTable::compact", (void*)p);
     522                 :            :     Assert(writable);
     523                 :      34605 :     int e = block_size;
     524                 :      34605 :     byte * b = buffer;
     525                 :      34605 :     int dir_end = DIR_END(p);
     526         [ +  + ]:    1734765 :     for (int c = DIR_START; c < dir_end; c += D2) {
     527                 :    1700160 :         Item item(p, c);
     528                 :    1700160 :         int l = item.size();
     529                 :    1700160 :         e -= l;
     530                 :    1700160 :         memmove(b + e, item.get_address(), l);
     531                 :    1700160 :         setD(p, c, e);  /* reform in b */
     532                 :            :     }
     533                 :      34605 :     memmove(p + e, b + e, block_size - e);  /* copy back */
     534                 :      34605 :     e -= dir_end;
     535                 :      34605 :     SET_TOTAL_FREE(p, e);
     536                 :      34605 :     SET_MAX_FREE(p, e);
     537                 :      34605 : }
     538                 :            : 
     539                 :            : /** Btree needs to gain a new level to insert more items: so split root block
     540                 :            :  *  and construct a new one.
     541                 :            :  */
     542                 :            : void
     543                 :        206 : BrassTable::split_root(uint4 split_n)
     544                 :            : {
     545                 :            :     LOGCALL_VOID(DB, "BrassTable::split_root", split_n);
     546                 :            :     /* gain a level */
     547                 :        206 :     ++level;
     548                 :            : 
     549                 :            :     /* check level overflow - this isn't something that should ever happen
     550                 :            :      * but deserves more than an Assert()... */
     551         [ -  + ]:        206 :     if (level == BTREE_CURSOR_LEVELS) {
     552                 :          0 :         throw Xapian::DatabaseCorruptError("Btree has grown impossibly large ("STRINGIZE(BTREE_CURSOR_LEVELS)" levels)");
     553                 :            :     }
     554                 :            : 
     555                 :        206 :     byte * q = zeroed_new(block_size);
     556                 :        206 :     C[level].p = q;
     557                 :        206 :     C[level].c = DIR_START;
     558                 :        206 :     C[level].n = base.next_free_block();
     559                 :        206 :     C[level].rewrite = true;
     560                 :        206 :     SET_REVISION(q, latest_revision_number + 1);
     561                 :        206 :     SET_LEVEL(q, level);
     562                 :        206 :     SET_DIR_END(q, DIR_START);
     563                 :        206 :     compact(q);   /* to reset TOTAL_FREE, MAX_FREE */
     564                 :            : 
     565                 :            :     /* form a null key in b with a pointer to the old root */
     566                 :            :     byte b[10]; /* 7 is exact */
     567                 :        206 :     Item_wr item(b);
     568                 :        206 :     item.form_null_key(split_n);
     569                 :        206 :     add_item(item, level);
     570                 :        206 : }
     571                 :            : 
     572                 :            : /** enter_key(j, prevkey, newkey) is called after a block split.
     573                 :            : 
     574                 :            :    It enters in the block at level C[j] a separating key for the block
     575                 :            :    at level C[j - 1]. The key itself is newkey. prevkey is the
     576                 :            :    preceding key, and at level 1 newkey can be trimmed down to the
     577                 :            :    first point of difference to prevkey for entry in C[j].
     578                 :            : 
     579                 :            :    This code looks longer than it really is. If j exceeds the number
     580                 :            :    of B-tree levels the root block has split and we have to construct
     581                 :            :    a new one, but this is a rare event.
     582                 :            : 
     583                 :            :    The key is constructed in b, with block number C[j - 1].n as tag,
     584                 :            :    and this is added in with add_item. add_item may itself cause a
     585                 :            :    block split, with a further call to enter_key. Hence the recursion.
     586                 :            : */
     587                 :            : void
     588                 :      16725 : BrassTable::enter_key(int j, Key prevkey, Key newkey)
     589                 :            : {
     590                 :            :     LOGCALL_VOID(DB, "BrassTable::enter_key", j | Literal("prevkey") | Literal("newkey"));
     591                 :            :     Assert(writable);
     592                 :            :     Assert(prevkey < newkey);
     593                 :            :     AssertRel(j,>=,1);
     594                 :            : 
     595                 :      16725 :     uint4 blocknumber = C[j - 1].n;
     596                 :            : 
     597                 :            :     // FIXME update to use Key
     598                 :            :     // Keys are truncated here: but don't truncate the count at the end away.
     599                 :      16725 :     const int newkey_len = newkey.length();
     600                 :            :     AssertRel(newkey_len,>,0);
     601                 :            :     int i;
     602                 :            : 
     603         [ +  + ]:      16725 :     if (j == 1) {
     604                 :            :         // Truncate the key to the minimal key which differs from prevkey,
     605                 :            :         // the preceding key in the block.
     606                 :      16601 :         i = 0;
     607                 :      16601 :         const int min_len = min(newkey_len, prevkey.length());
     608 [ +  + ][ +  + ]:      89084 :         while (i < min_len && prevkey[i] == newkey[i]) {
                 [ +  + ]
     609                 :      72483 :             i++;
     610                 :            :         }
     611                 :            : 
     612                 :            :         // Want one byte of difference.
     613         [ +  + ]:      16601 :         if (i < newkey_len) i++;
     614                 :            :     } else {
     615                 :            :         /* Can't truncate between branch levels, since the separated keys
     616                 :            :          * are in at the leaf level, and truncating again will change the
     617                 :            :          * branch point.
     618                 :            :          */
     619                 :        124 :         i = newkey_len;
     620                 :            :     }
     621                 :            : 
     622                 :            :     byte b[UCHAR_MAX + 6];
     623                 :      16725 :     Item_wr item(b);
     624                 :            :     Assert(i <= 256 - I2 - C2);
     625                 :            :     Assert(i <= (int)sizeof(b) - I2 - C2 - 4);
     626                 :      16725 :     item.set_key_and_block(newkey, i, blocknumber);
     627                 :            : 
     628                 :            :     // When j > 1 we can make the first key of block p null.  This is probably
     629                 :            :     // worthwhile as it trades a small amount of CPU and RAM use for a small
     630                 :            :     // saving in disk use.  Other redundant keys will still creep in though.
     631         [ +  + ]:      16725 :     if (j > 1) {
     632                 :        124 :         byte * p = C[j - 1].p;
     633                 :        124 :         uint4 n = getint4(newkey.get_address(), newkey_len + K1 + C2);
     634                 :        124 :         int new_total_free = TOTAL_FREE(p) + newkey_len + C2;
     635                 :            :         // FIXME: incredibly icky going from key to item like this...
     636                 :        124 :         Item_wr(const_cast<byte*>(newkey.get_address()) - I2).form_null_key(n);
     637                 :        124 :         SET_TOTAL_FREE(p, new_total_free);
     638                 :            :     }
     639                 :            : 
     640                 :      16725 :     C[j].c = find_in_block(C[j].p, item.key(), false, 0) + D2;
     641                 :      16725 :     C[j].rewrite = true; /* a subtle point: this *is* required. */
     642                 :      16725 :     add_item(item, j);
     643                 :      16725 : }
     644                 :            : 
     645                 :            : /** mid_point(p) finds the directory entry in c that determines the
     646                 :            :    approximate mid point of the data in the block at p.
     647                 :            :  */
     648                 :            : 
     649                 :            : int
     650                 :       7823 : BrassTable::mid_point(byte * p)
     651                 :            : {
     652                 :            :     LOGCALL(DB, int, "BrassTable::mid_point", (void*)p);
     653                 :       7823 :     int n = 0;
     654                 :       7823 :     int dir_end = DIR_END(p);
     655                 :       7823 :     int size = block_size - TOTAL_FREE(p) - dir_end;
     656         [ +  - ]:     346567 :     for (int c = DIR_START; c < dir_end; c += D2) {
     657                 :     346567 :         int l = Item(p, c).size();
     658                 :     346567 :         n += 2 * l;
     659         [ +  + ]:     346567 :         if (n >= size) {
     660         [ +  + ]:       7823 :             if (l < n - size) RETURN(c);
     661                 :       4319 :             RETURN(c + D2);
     662                 :            :         }
     663                 :            :     }
     664                 :            : 
     665                 :            :     /* falling out of mid_point */
     666                 :            :     Assert(false);
     667                 :       7823 :     RETURN(0); /* Stop compiler complaining about end of method. */
     668                 :            : }
     669                 :            : 
     670                 :            : /** add_item_to_block(p, kt_, c) adds item kt_ to the block at p.
     671                 :            : 
     672                 :            :    c is the offset in the directory that needs to be expanded to accommodate
     673                 :            :    the new entry for the item.  We know before this is called that there is
     674                 :            :    enough contiguous room for the item in the block, so it's just a matter of
     675                 :            :    shuffling up any directory entries after where we're inserting and copying
     676                 :            :    in the item.
     677                 :            : */
     678                 :            : 
     679                 :            : void
     680                 :    1334868 : BrassTable::add_item_to_block(byte * p, Item_wr kt_, int c)
     681                 :            : {
     682                 :            :     LOGCALL_VOID(DB, "BrassTable::add_item_to_block", (void*)p | Literal("kt_") | c);
     683                 :            :     Assert(writable);
     684                 :    1334868 :     int dir_end = DIR_END(p);
     685                 :    1334868 :     int kt_len = kt_.size();
     686                 :    1334868 :     int needed = kt_len + D2;
     687                 :    1334868 :     int new_total = TOTAL_FREE(p) - needed;
     688                 :    1334868 :     int new_max = MAX_FREE(p) - needed;
     689                 :            : 
     690                 :            :     Assert(new_total >= 0);
     691                 :            : 
     692                 :            :     AssertRel(MAX_FREE(p),>=,needed);
     693                 :            : 
     694                 :            :     Assert(dir_end >= c);
     695                 :            : 
     696                 :    1334868 :     memmove(p + c + D2, p + c, dir_end - c);
     697                 :    1334868 :     dir_end += D2;
     698                 :    1334868 :     SET_DIR_END(p, dir_end);
     699                 :            : 
     700                 :    1334868 :     int o = dir_end + new_max;
     701                 :    1334868 :     setD(p, c, o);
     702                 :    1334868 :     memmove(p + o, kt_.get_address(), kt_len);
     703                 :            : 
     704                 :    1334868 :     SET_MAX_FREE(p, new_max);
     705                 :            : 
     706                 :    1334868 :     SET_TOTAL_FREE(p, new_total);
     707                 :    1334868 : }
     708                 :            : 
     709                 :            : /** BrassTable::add_item(kt_, j) adds item kt_ to the block at cursor level C[j].
     710                 :            :  *
     711                 :            :  *  If there is not enough room the block splits and the item is then
     712                 :            :  *  added to the appropriate half.
     713                 :            :  */
     714                 :            : void
     715                 :    1334868 : BrassTable::add_item(Item_wr kt_, int j)
     716                 :            : {
     717                 :            :     LOGCALL_VOID(DB, "BrassTable::add_item", Literal("kt_") | j);
     718                 :            :     Assert(writable);
     719                 :    1334868 :     byte * p = C[j].p;
     720                 :    1334868 :     int c = C[j].c;
     721                 :            :     uint4 n;
     722                 :            : 
     723                 :    1334868 :     int needed = kt_.size() + D2;
     724         [ +  + ]:    1334868 :     if (TOTAL_FREE(p) < needed) {
     725                 :            :         int m;
     726                 :            :         // Prepare to split p. After splitting, the block is in two halves, the
     727                 :            :         // lower half is split_p, the upper half p again. add_to_upper_half
     728                 :            :         // becomes true when the item gets added to p, false when it gets added
     729                 :            :         // to split_p.
     730                 :            : 
     731         [ +  + ]:      16725 :         if (seq_count < 0) {
     732                 :            :             // If we're not in sequential mode, we split at the mid point
     733                 :            :             // of the node.
     734                 :       7823 :             m = mid_point(p);
     735                 :            :         } else {
     736                 :            :             // During sequential addition, split at the insert point
     737                 :       8902 :             m = c;
     738                 :            :         }
     739                 :            : 
     740                 :      16725 :         uint4 split_n = C[j].n;
     741                 :      16725 :         C[j].n = base.next_free_block();
     742                 :            : 
     743                 :      16725 :         memcpy(split_p, p, block_size);  // replicate the whole block in split_p
     744                 :      16725 :         SET_DIR_END(split_p, m);
     745                 :      16725 :         compact(split_p);      /* to reset TOTAL_FREE, MAX_FREE */
     746                 :            : 
     747                 :            :         {
     748                 :      16725 :             int residue = DIR_END(p) - m;
     749                 :      16725 :             int new_dir_end = DIR_START + residue;
     750                 :      16725 :             memmove(p + DIR_START, p + m, residue);
     751                 :      16725 :             SET_DIR_END(p, new_dir_end);
     752                 :            :         }
     753                 :            : 
     754                 :      16725 :         compact(p);      /* to reset TOTAL_FREE, MAX_FREE */
     755                 :            : 
     756                 :            :         bool add_to_upper_half;
     757         [ +  + ]:      16725 :         if (seq_count < 0) {
     758                 :       7823 :             add_to_upper_half = (c >= m);
     759                 :            :         } else {
     760                 :            :             // And add item to lower half if split_p has room, otherwise upper
     761                 :            :             // half
     762                 :       8902 :             add_to_upper_half = (TOTAL_FREE(split_p) < needed);
     763                 :            :         }
     764                 :            : 
     765         [ +  + ]:      16725 :         if (add_to_upper_half) {
     766                 :      15175 :             c -= (m - DIR_START);
     767                 :            :             Assert(seq_count < 0 || c <= DIR_START + D2);
     768                 :            :             Assert(c >= DIR_START);
     769                 :            :             Assert(c <= DIR_END(p));
     770                 :      15175 :             add_item_to_block(p, kt_, c);
     771                 :      15175 :             n = C[j].n;
     772                 :            :         } else {
     773                 :            :             Assert(c >= DIR_START);
     774                 :            :             Assert(c <= DIR_END(split_p));
     775                 :       1550 :             add_item_to_block(split_p, kt_, c);
     776                 :       1550 :             n = split_n;
     777                 :            :         }
     778                 :      16725 :         write_block(split_n, split_p);
     779                 :            : 
     780                 :            :         // Check if we're splitting the root block.
     781         [ +  + ]:      16725 :         if (j == level) split_root(split_n);
     782                 :            : 
     783                 :            :         /* Enter a separating key at level j + 1 between */
     784                 :            :         /* the last key of block split_p, and the first key of block p */
     785                 :            :         enter_key(j + 1,
     786                 :            :                   Item(split_p, DIR_END(split_p) - D2).key(),
     787                 :      16725 :                   Item(p, DIR_START).key());
     788                 :            :     } else {
     789                 :            :         AssertRel(TOTAL_FREE(p),>=,needed);
     790                 :            : 
     791         [ +  + ]:    1318143 :         if (MAX_FREE(p) < needed) {
     792                 :        949 :             compact(p);
     793                 :            :             AssertRel(MAX_FREE(p),>=,needed);
     794                 :            :         }
     795                 :            : 
     796                 :    1318143 :         add_item_to_block(p, kt_, c);
     797                 :    1318143 :         n = C[j].n;
     798                 :            :     }
     799         [ +  + ]:    1334868 :     if (j == 0) {
     800                 :    1317937 :         changed_n = n;
     801                 :    1317937 :         changed_c = c;
     802                 :            :     }
     803                 :    1334868 : }
     804                 :            : 
     805                 :            : /** BrassTable::delete_item(j, repeatedly) is (almost) the converse of add_item.
     806                 :            :  *
     807                 :            :  * If repeatedly is true, the process repeats at the next level when a
     808                 :            :  * block has been completely emptied, freeing the block and taking out
     809                 :            :  * the pointer to it.  Emptied root blocks are also removed, which
     810                 :            :  * reduces the number of levels in the B-tree.
     811                 :            :  */
     812                 :            : void
     813                 :      43330 : BrassTable::delete_item(int j, bool repeatedly)
     814                 :            : {
     815                 :            :     LOGCALL_VOID(DB, "BrassTable::delete_item", j | repeatedly);
     816                 :            :     Assert(writable);
     817                 :      43330 :     byte * p = C[j].p;
     818                 :      43330 :     int c = C[j].c;
     819                 :      43330 :     int kt_len = Item(p, c).size(); /* size of the item to be deleted */
     820                 :      43330 :     int dir_end = DIR_END(p) - D2;   /* directory length will go down by 2 bytes */
     821                 :            : 
     822                 :      43330 :     memmove(p + c, p + c + D2, dir_end - c);
     823                 :      43330 :     SET_DIR_END(p, dir_end);
     824                 :      43330 :     SET_MAX_FREE(p, MAX_FREE(p) + D2);
     825                 :      43330 :     SET_TOTAL_FREE(p, TOTAL_FREE(p) + kt_len + D2);
     826                 :            : 
     827         [ +  + ]:      43330 :     if (!repeatedly) return;
     828         [ +  + ]:      42116 :     if (j < level) {
     829         [ +  + ]:      41215 :         if (dir_end == DIR_START) {
     830                 :        410 :             base.free_block(C[j].n);
     831                 :        410 :             C[j].rewrite = false;
     832                 :        410 :             C[j].n = BLK_UNUSED;
     833                 :        410 :             C[j + 1].rewrite = true;  /* *is* necessary */
     834                 :        410 :             delete_item(j + 1, true);
     835                 :            :         }
     836                 :            :     } else {
     837                 :            :         Assert(j == level);
     838 [ +  + ][ +  + ]:      43345 :         while (dir_end == DIR_START + D2 && level > 0) {
                 [ +  + ]
     839                 :            :             /* single item in the root block, so lose a level */
     840                 :         15 :             uint4 new_root = Item(p, DIR_START).block_given_by();
     841         [ +  - ]:         15 :             delete [] p;
     842                 :         15 :             C[level].p = 0;
     843                 :         15 :             base.free_block(C[level].n);
     844                 :         15 :             C[level].rewrite = false;
     845                 :         15 :             C[level].n = BLK_UNUSED;
     846                 :         15 :             level--;
     847                 :            : 
     848                 :         15 :             block_to_cursor(C, level, new_root);
     849                 :            : 
     850                 :         15 :             p = C[level].p;
     851                 :         15 :             dir_end = DIR_END(p); /* prepare for the loop */
     852                 :            :         }
     853                 :            :     }
     854                 :            : }
     855                 :            : 
     856                 :            : /* debugging aid:
     857                 :            : static addcount = 0;
     858                 :            : */
     859                 :            : 
     860                 :            : /** add_kt(found) adds the item (key-tag pair) at B->kt into the
     861                 :            :    B-tree, using cursor C.
     862                 :            : 
     863                 :            :    found == find() is handed over as a parameter from Btree::add.
     864                 :            :    Btree::alter() prepares for the alteration to the B-tree. Then
     865                 :            :    there are a number of cases to consider:
     866                 :            : 
     867                 :            :      If an item with the same key is in the B-tree (found is true),
     868                 :            :      the new kt replaces it.
     869                 :            : 
     870                 :            :      If then kt is smaller, or the same size as, the item it replaces,
     871                 :            :      kt is put in the same place as the item it replaces, and the
     872                 :            :      TOTAL_FREE measure is reduced.
     873                 :            : 
     874                 :            :      If kt is larger than the item it replaces it is put in the
     875                 :            :      MAX_FREE space if there is room, and the directory entry and
     876                 :            :      space counts are adjusted accordingly.
     877                 :            : 
     878                 :            :      - But if there is not room we do it the long way: the old item is
     879                 :            :      deleted with delete_item and kt is added in with add_item.
     880                 :            : 
     881                 :            :      If the key of kt is not in the B-tree (found is false), the new
     882                 :            :      kt is added in with add_item.
     883                 :            : */
     884                 :            : 
     885                 :            : int
     886                 :    1360034 : BrassTable::add_kt(bool found)
     887                 :            : {
     888                 :            :     LOGCALL(DB, int, "BrassTable::add_kt", found);
     889                 :            :     Assert(writable);
     890                 :    1360034 :     int components = 0;
     891                 :            : 
     892                 :            :     /*
     893                 :            :     {
     894                 :            :         printf("%d) %s ", addcount++, (found ? "replacing" : "adding"));
     895                 :            :         print_bytes(kt[I2] - K1 - C2, kt + I2 + K1); putchar('\n');
     896                 :            :     }
     897                 :            :     */
     898                 :    1360034 :     alter();
     899                 :            : 
     900         [ +  + ]:    1360034 :     if (found) { /* replacement */
     901                 :      43311 :         seq_count = SEQ_START_POINT;
     902                 :      43311 :         sequential = false;
     903                 :            : 
     904                 :      43311 :         byte * p = C[0].p;
     905                 :      43311 :         int c = C[0].c;
     906                 :      43311 :         Item item(p, c);
     907                 :      43311 :         int kt_size = kt.size();
     908                 :      43311 :         int needed = kt_size - item.size();
     909                 :            : 
     910                 :      43311 :         components = item.components_of();
     911                 :            : 
     912         [ +  + ]:      43311 :         if (needed <= 0) {
     913                 :            :             /* simple replacement */
     914                 :            :             memmove(const_cast<byte *>(item.get_address()),
     915                 :      35612 :                     kt.get_address(), kt_size);
     916                 :      35612 :             SET_TOTAL_FREE(p, TOTAL_FREE(p) - needed);
     917                 :            :         } else {
     918                 :            :             /* new item into the block's freespace */
     919                 :       7699 :             int new_max = MAX_FREE(p) - kt_size;
     920         [ +  + ]:       7699 :             if (new_max >= 0) {
     921                 :       6485 :                 int o = DIR_END(p) + new_max;
     922                 :       6485 :                 memmove(p + o, kt.get_address(), kt_size);
     923                 :       6485 :                 setD(p, c, o);
     924                 :       6485 :                 SET_MAX_FREE(p, new_max);
     925                 :       6485 :                 SET_TOTAL_FREE(p, TOTAL_FREE(p) - needed);
     926                 :            :             } else {
     927                 :            :                 /* do it the long way */
     928                 :       1214 :                 delete_item(0, false);
     929                 :       1214 :                 add_item(kt, 0);
     930                 :            :             }
     931                 :            :         }
     932                 :            :     } else {
     933                 :            :         /* addition */
     934 [ +  + ][ +  + ]:    2265675 :         if (changed_n == C[0].n && changed_c == C[0].c) {
     935         [ +  + ]:     948952 :             if (seq_count < 0) seq_count++;
     936                 :            :         } else {
     937                 :     367771 :             seq_count = SEQ_START_POINT;
     938                 :     367771 :             sequential = false;
     939                 :            :         }
     940                 :    1316723 :         C[0].c += D2;
     941                 :    1316723 :         add_item(kt, 0);
     942                 :            :     }
     943                 :    1360034 :     RETURN(components);
     944                 :            : }
     945                 :            : 
     946                 :            : /* delete_kt() corresponds to add_kt(found), but there are only
     947                 :            :    two cases: if the key is not found nothing is done, and if it is
     948                 :            :    found the corresponding item is deleted with delete_item.
     949                 :            : */
     950                 :            : 
     951                 :            : int
     952                 :      41846 : BrassTable::delete_kt()
     953                 :            : {
     954                 :            :     LOGCALL(DB, int, "BrassTable::delete_kt", NO_ARGS);
     955                 :            :     Assert(writable);
     956                 :            : 
     957                 :      41846 :     bool found = find(C);
     958                 :            : 
     959                 :      41846 :     int components = 0;
     960                 :      41846 :     seq_count = SEQ_START_POINT;
     961                 :      41846 :     sequential = false;
     962                 :            : 
     963                 :            :     /*
     964                 :            :     {
     965                 :            :         printf("%d) %s ", addcount++, (found ? "deleting " : "ignoring "));
     966                 :            :         print_bytes(B->kt[I2] - K1 - C2, B->kt + I2 + K1); putchar('\n');
     967                 :            :     }
     968                 :            :     */
     969         [ +  + ]:      41846 :     if (found) {
     970                 :      41706 :         components = Item(C[0].p, C[0].c).components_of();
     971                 :      41706 :         alter();
     972                 :      41706 :         delete_item(0, true);
     973                 :            :     }
     974                 :      41846 :     RETURN(components);
     975                 :            : }
     976                 :            : 
     977                 :            : /* BrassTable::form_key(key) treats address kt as an item holder and fills in
     978                 :            : the key part:
     979                 :            : 
     980                 :            :            (I) K key c (C tag)
     981                 :            : 
     982                 :            : The bracketed parts are left blank. The key is filled in with key_len bytes and
     983                 :            : K set accordingly. c is set to 1.
     984                 :            : */
     985                 :            : 
     986                 :    4532321 : void BrassTable::form_key(const string & key) const
     987                 :            : {
     988                 :            :     LOGCALL_VOID(DB, "BrassTable::form_key", key);
     989                 :    4532321 :     kt.form_key(key);
     990                 :    4532313 : }
     991                 :            : 
     992                 :            : /* BrassTable::add(key, tag) adds the key/tag item to the
     993                 :            :    B-tree, replacing any existing item with the same key.
     994                 :            : 
     995                 :            :    For a long tag, we end up having to add m components, of the form
     996                 :            : 
     997                 :            :        key 1 m tag1
     998                 :            :        key 2 m tag2
     999                 :            :        ...
    1000                 :            :        key m m tagm
    1001                 :            : 
    1002                 :            :    and tag1+tag2+...+tagm are equal to tag. These in their turn may be replacing
    1003                 :            :    n components of the form
    1004                 :            : 
    1005                 :            :        key 1 n TAG1
    1006                 :            :        key 2 n TAG2
    1007                 :            :        ...
    1008                 :            :        key n n TAGn
    1009                 :            : 
    1010                 :            :    and n may be greater than, equal to, or less than m. These cases are dealt
    1011                 :            :    with in the code below. If m < n for example, we end up with a series of
    1012                 :            :    deletions.
    1013                 :            : */
    1014                 :            : 
    1015                 :            : void
    1016                 :    1351704 : BrassTable::add(const string &key, string tag, bool already_compressed)
    1017                 :            : {
    1018                 :            :     LOGCALL_VOID(DB, "BrassTable::add", key | tag | already_compressed);
    1019                 :            :     Assert(writable);
    1020                 :            : 
    1021         [ +  + ]:    1351704 :     if (handle < 0) create_and_open(block_size);
    1022                 :            : 
    1023                 :    1351704 :     form_key(key);
    1024                 :            : 
    1025                 :    1351696 :     bool compressed = false;
    1026         [ +  + ]:    1351696 :     if (already_compressed) {
    1027                 :        157 :         compressed = true;
    1028 [ +  + ][ +  + ]:    1351539 :     } else if (compress_strategy != DONT_COMPRESS && tag.size() > COMPRESS_MIN) {
                 [ +  + ]
    1029                 :            :         CompileTimeAssert(DONT_COMPRESS != Z_DEFAULT_STRATEGY);
    1030                 :            :         CompileTimeAssert(DONT_COMPRESS != Z_FILTERED);
    1031                 :            :         CompileTimeAssert(DONT_COMPRESS != Z_HUFFMAN_ONLY);
    1032                 :            : #ifdef Z_RLE
    1033                 :            :         CompileTimeAssert(DONT_COMPRESS != Z_RLE);
    1034                 :            : #endif
    1035                 :            : 
    1036                 :      58202 :         lazy_alloc_deflate_zstream();
    1037                 :            : 
    1038                 :      58202 :         deflate_zstream->next_in = (Bytef *)const_cast<char *>(tag.data());
    1039                 :      58202 :         deflate_zstream->avail_in = (uInt)tag.size();
    1040                 :            : 
    1041                 :            :         // If compressed size is >= tag.size(), we don't want to compress.
    1042                 :      58202 :         unsigned long blk_len = tag.size() - 1;
    1043                 :      58202 :         unsigned char * blk = new unsigned char[blk_len];
    1044                 :      58202 :         deflate_zstream->next_out = blk;
    1045                 :      58202 :         deflate_zstream->avail_out = (uInt)blk_len;
    1046                 :            : 
    1047                 :      58202 :         int err = deflate(deflate_zstream, Z_FINISH);
    1048         [ +  + ]:      58202 :         if (err == Z_STREAM_END) {
    1049                 :            :             // If deflate succeeded, then the output was at least one byte
    1050                 :            :             // smaller than the input.
    1051                 :      14632 :             tag.assign(reinterpret_cast<const char *>(blk), deflate_zstream->total_out);
    1052                 :      14632 :             compressed = true;
    1053                 :            :         } else {
    1054                 :            :             // Deflate failed - presumably the data wasn't compressible.
    1055                 :            :         }
    1056                 :            : 
    1057         [ +  - ]:      58202 :         delete [] blk;
    1058                 :            :     }
    1059                 :            : 
    1060                 :            :     // sort of matching kt.append_chunk(), but setting the chunk
    1061                 :    1351696 :     const size_t cd = kt.key().length() + K1 + I2 + C2 + C2;  // offset to the tag data
    1062                 :    1351696 :     const size_t L = max_item_size - cd; // largest amount of tag data for any chunk
    1063                 :    1351696 :     size_t first_L = L;                  // - amount for tag1
    1064                 :    1351696 :     bool found = find(C);
    1065         [ +  + ]:    1351696 :     if (!found) {
    1066                 :    1308706 :         byte * p = C[0].p;
    1067                 :    1308706 :         size_t n = TOTAL_FREE(p) % (max_item_size + D2);
    1068         [ +  + ]:    1308706 :         if (n > D2 + cd) {
    1069                 :    1271038 :             n -= (D2 + cd);
    1070                 :            :             // if n >= last then fully filling this block won't produce
    1071                 :            :             // an extra item, so we might as well do this even if
    1072                 :            :             // full_compaction isn't active.
    1073                 :            :             //
    1074                 :            :             // In the full_compaction case, it turns out we shouldn't always
    1075                 :            :             // try to fill every last byte.  Doing so can actually increase the
    1076                 :            :             // total space required (I believe this effect is due to longer
    1077                 :            :             // dividing keys being required in the index blocks).  Empirically,
    1078                 :            :             // n >= key.size() + K appears a good criterion for K ~= 34.  This
    1079                 :            :             // seems to save about 0.2% in total database size over always
    1080                 :            :             // splitting the tag.  It'll also give be slightly faster retrieval
    1081                 :            :             // as we can avoid reading an extra block occasionally.
    1082                 :    1271038 :             size_t last = tag.length() % L;
    1083   [ +  +  +  + ]:    1271038 :             if (n >= last || (full_compaction && n >= key.size() + 34))
         [ +  + ][ +  + ]
    1084                 :    1263911 :                 first_L = n;
    1085                 :            :         }
    1086                 :            :     }
    1087                 :            : 
    1088                 :            :     // a null tag must be added in of course
    1089         [ +  + ]:    1351696 :     int m = tag.empty() ? 1 : (tag.length() - first_L + L - 1) / L + 1;
    1090                 :            :                                       // there are m items to add
    1091                 :            :     /* FIXME: sort out this error higher up and turn this into
    1092                 :            :      * an assert.
    1093                 :            :      */
    1094         [ -  + ]:    1351696 :     if (m >= BYTE_PAIR_RANGE)
    1095                 :          0 :         throw Xapian::UnimplementedError("Can't handle insanely large tags");
    1096                 :            : 
    1097                 :    1351696 :     int n = 0; // initialise to shut off warning
    1098                 :            :                                       // - and there will be n to delete
    1099                 :    1351696 :     int o = 0;                        // Offset into the tag
    1100                 :    1351696 :     size_t residue = tag.length();    // Bytes of the tag remaining to add in
    1101                 :    1351696 :     int replacement = false;          // Has there been a replacement ?
    1102                 :            :     int i;
    1103                 :    1351696 :     kt.set_components_of(m);
    1104         [ +  + ]:    2711730 :     for (i = 1; i <= m; i++) {
    1105 [ +  + ][ +  + ]:    1360034 :         size_t l = (i == m ? residue : (i == 1 ? first_L : L));
    1106                 :            :         Assert(cd + l <= block_size);
    1107                 :            :         Assert(string::size_type(o + l) <= tag.length());
    1108                 :    1360034 :         kt.set_tag(cd, tag.data() + o, l, compressed);
    1109                 :    1360034 :         kt.set_component_of(i);
    1110                 :            : 
    1111                 :    1360034 :         o += l;
    1112                 :    1360034 :         residue -= l;
    1113                 :            : 
    1114         [ +  + ]:    1360034 :         if (i > 1) found = find(C);
    1115                 :    1360034 :         n = add_kt(found);
    1116         [ +  + ]:    1360034 :         if (n > 0) replacement = true;
    1117                 :            :     }
    1118                 :            :     /* o == tag.length() here, and n may be zero */
    1119         [ -  + ]:    1351696 :     for (i = m + 1; i <= n; i++) {
    1120                 :          0 :         kt.set_component_of(i);
    1121                 :          0 :         delete_kt();
    1122                 :            :     }
    1123         [ +  + ]:    1351696 :     if (!replacement) ++item_count;
    1124                 :    1351696 :     Btree_modified = true;
    1125         [ +  + ]:    1351696 :     if (cursor_created_since_last_modification) {
    1126                 :     188107 :         cursor_created_since_last_modification = false;
    1127                 :     188107 :         ++cursor_version;
    1128                 :            :     }
    1129                 :    1351696 : }
    1130                 :            : 
    1131                 :            : /* BrassTable::del(key) returns false if the key is not in the B-tree,
    1132                 :            :    otherwise deletes it and returns true.
    1133                 :            : 
    1134                 :            :    Again, this is parallel to BrassTable::add, but simpler in form.
    1135                 :            : */
    1136                 :            : 
    1137                 :            : bool
    1138                 :      45922 : BrassTable::del(const string &key)
    1139                 :            : {
    1140                 :            :     LOGCALL(DB, bool, "BrassTable::del", key);
    1141                 :            :     Assert(writable);
    1142                 :            : 
    1143         [ +  + ]:      45922 :     if (handle < 0) {
    1144         [ -  + ]:       4443 :         if (handle == -2) {
    1145                 :          0 :             BrassTable::throw_database_closed();
    1146                 :            :         }
    1147                 :       4443 :         RETURN(false);
    1148                 :            :     }
    1149                 :            : 
    1150                 :            :     // We can't delete a key which we is too long for us to store.
    1151         [ -  + ]:      41479 :     if (key.size() > BRASS_BTREE_MAX_KEY_LEN) RETURN(false);
    1152                 :            : 
    1153         [ -  + ]:      41479 :     if (key.empty()) RETURN(false);
    1154                 :      41479 :     form_key(key);
    1155                 :            : 
    1156                 :      41479 :     int n = delete_kt();  /* there are n items to delete */
    1157         [ +  + ]:      41479 :     if (n <= 0) RETURN(false);
    1158                 :            : 
    1159         [ +  + ]:      41706 :     for (int i = 2; i <= n; i++) {
    1160                 :        367 :         kt.set_component_of(i);
    1161                 :        367 :         delete_kt();
    1162                 :            :     }
    1163                 :            : 
    1164                 :      41339 :     item_count--;
    1165                 :      41339 :     Btree_modified = true;
    1166         [ +  + ]:      41339 :     if (cursor_created_since_last_modification) {
    1167                 :        192 :         cursor_created_since_last_modification = false;
    1168                 :        192 :         ++cursor_version;
    1169                 :            :     }
    1170                 :      45922 :     RETURN(true);
    1171                 :            : }
    1172                 :            : 
    1173                 :            : bool
    1174                 :    1088424 : BrassTable::get_exact_entry(const string &key, string & tag) const
    1175                 :            : {
    1176                 :            :     LOGCALL(DB, bool, "BrassTable::get_exact_entry", key | tag);
    1177                 :            :     Assert(!key.empty());
    1178                 :            : 
    1179         [ +  + ]:    1088424 :     if (handle < 0) {
    1180         [ -  + ]:      50956 :         if (handle == -2) {
    1181                 :          0 :             BrassTable::throw_database_closed();
    1182                 :            :         }
    1183                 :      50956 :         RETURN(false);
    1184                 :            :     }
    1185                 :            : 
    1186                 :            :     // An oversized key can't exist, so attempting to search for it should fail.
    1187         [ +  + ]:    1037468 :     if (key.size() > BRASS_BTREE_MAX_KEY_LEN) RETURN(false);
    1188                 :            : 
    1189                 :    1037436 :     form_key(key);
    1190         [ +  + ]:    1037436 :     if (!find(C)) RETURN(false);
    1191                 :            : 
    1192                 :     748915 :     (void)read_tag(C, &tag, false);
    1193                 :    1088422 :     RETURN(true);
    1194                 :            : }
    1195                 :            : 
    1196                 :            : bool
    1197                 :       1060 : BrassTable::key_exists(const string &key) const
    1198                 :            : {
    1199                 :            :     LOGCALL(DB, bool, "BrassTable::key_exists", key);
    1200                 :            :     Assert(!key.empty());
    1201                 :            : 
    1202                 :            :     // An oversized key can't exist, so attempting to search for it should fail.
    1203         [ -  + ]:       1060 :     if (key.size() > BRASS_BTREE_MAX_KEY_LEN) RETURN(false);
    1204                 :            : 
    1205                 :       1060 :     form_key(key);
    1206                 :       1060 :     RETURN(find(C));
    1207                 :            : }
    1208                 :            : 
    1209                 :            : bool
    1210                 :    2681462 : BrassTable::read_tag(Brass::Cursor * C_, string *tag, bool keep_compressed) const
    1211                 :            : {
    1212                 :            :     LOGCALL(DB, bool, "BrassTable::read_tag", Literal("C_") | tag | keep_compressed);
    1213                 :    2681462 :     Item item(C_[0].p, C_[0].c);
    1214                 :            : 
    1215                 :            :     /* n components to join */
    1216                 :    2681462 :     int n = item.components_of();
    1217                 :            : 
    1218                 :    2681462 :     tag->resize(0);
    1219                 :            :     // max_item_size also includes K1 + I2 + C2 + C2 bytes overhead and the key
    1220                 :            :     // (which is at least 1 byte long).
    1221         [ +  + ]:    2681462 :     if (n > 1) tag->reserve((max_item_size - (1 + K1 + I2 + C2 + C2)) * n);
    1222                 :            : 
    1223                 :    2681462 :     item.append_chunk(tag);
    1224                 :    2681462 :     bool compressed = item.get_compressed();
    1225                 :            : 
    1226         [ +  + ]:    6948760 :     for (int i = 2; i <= n; i++) {
    1227         [ -  + ]:    4267298 :         if (!next(C_, 0)) {
    1228                 :          0 :             throw Xapian::DatabaseCorruptError("Unexpected end of table when reading continuation of tag");
    1229                 :            :         }
    1230                 :    4267298 :         (void)Item(C_[0].p, C_[0].c).append_chunk(tag);
    1231                 :            :     }
    1232                 :            :     // At this point the cursor is on the last item - calling next will move
    1233                 :            :     // it to the next key (BrassCursor::get_tag() relies on this).
    1234 [ +  + ][ +  + ]:    2681462 :     if (!compressed || keep_compressed) RETURN(compressed);
    1235                 :            : 
    1236                 :            :     // FIXME: Perhaps we should we decompress each chunk as we read it so we
    1237                 :            :     // don't need both the full compressed and uncompressed tags in memory
    1238                 :            :     // at once.
    1239                 :            : 
    1240                 :     207427 :     string utag;
    1241                 :            :     // May not be enough for a compressed tag, but it's a reasonable guess.
    1242                 :     207427 :     utag.reserve(tag->size() + tag->size() / 2);
    1243                 :            : 
    1244                 :            :     Bytef buf[8192];
    1245                 :            : 
    1246                 :     207427 :     lazy_alloc_inflate_zstream();
    1247                 :            : 
    1248                 :     207427 :     inflate_zstream->next_in = (Bytef*)const_cast<char *>(tag->data());
    1249                 :     207427 :     inflate_zstream->avail_in = (uInt)tag->size();
    1250                 :            : 
    1251                 :     207427 :     int err = Z_OK;
    1252         [ +  + ]:     414854 :     while (err != Z_STREAM_END) {
    1253                 :     207427 :         inflate_zstream->next_out = buf;
    1254                 :     207427 :         inflate_zstream->avail_out = (uInt)sizeof(buf);
    1255                 :     207427 :         err = inflate(inflate_zstream, Z_SYNC_FLUSH);
    1256   [ -  +  #  # ]:     207427 :         if (err == Z_BUF_ERROR && inflate_zstream->avail_in == 0) {
    1257                 :            :             LOGLINE(DB, "Z_BUF_ERROR - faking checksum of " << inflate_zstream->adler);
    1258                 :            :             Bytef header2[4];
    1259                 :          0 :             setint4(header2, 0, inflate_zstream->adler);
    1260                 :          0 :             inflate_zstream->next_in = header2;
    1261                 :          0 :             inflate_zstream->avail_in = 4;
    1262                 :          0 :             err = inflate(inflate_zstream, Z_SYNC_FLUSH);
    1263         [ #  # ]:          0 :             if (err == Z_STREAM_END) break;
    1264                 :            :         }
    1265                 :            : 
    1266 [ +  - ][ -  + ]:     207427 :         if (err != Z_OK && err != Z_STREAM_END) {
    1267         [ #  # ]:          0 :             if (err == Z_MEM_ERROR) throw std::bad_alloc();
    1268                 :          0 :             string msg = "inflate failed";
    1269         [ #  # ]:          0 :             if (inflate_zstream->msg) {
    1270                 :          0 :                 msg += " (";
    1271                 :          0 :                 msg += inflate_zstream->msg;
    1272                 :          0 :                 msg += ')';
    1273                 :            :             }
    1274                 :          0 :             throw Xapian::DatabaseError(msg);
    1275                 :            :         }
    1276                 :            : 
    1277                 :            :         utag.append(reinterpret_cast<const char *>(buf),
    1278                 :     207427 :                     inflate_zstream->next_out - buf);
    1279                 :            :     }
    1280         [ -  + ]:     207427 :     if (utag.size() != inflate_zstream->total_out) {
    1281                 :          0 :         string msg = "compressed tag didn't expand to the expected size: ";
    1282                 :          0 :         msg += str(utag.size());
    1283                 :          0 :         msg += " != ";
    1284                 :            :         // OpenBSD's zlib.h uses off_t instead of uLong for total_out.
    1285                 :          0 :         msg += str((size_t)inflate_zstream->total_out);
    1286                 :          0 :         throw Xapian::DatabaseCorruptError(msg);
    1287                 :            :     }
    1288                 :            : 
    1289                 :     207427 :     swap(*tag, utag);
    1290                 :            : 
    1291                 :    2681462 :     RETURN(false);
    1292                 :            : }
    1293                 :            : 
    1294                 :            : void
    1295                 :         40 : BrassTable::set_full_compaction(bool parity)
    1296                 :            : {
    1297                 :            :     LOGCALL_VOID(DB, "BrassTable::set_full_compaction", parity);
    1298                 :            :     Assert(writable);
    1299                 :            : 
    1300         [ +  - ]:         40 :     if (parity) seq_count = 0;
    1301                 :         40 :     full_compaction = parity;
    1302                 :         40 : }
    1303                 :            : 
    1304                 :    2004150 : BrassCursor * BrassTable::cursor_get() const {
    1305                 :            :     LOGCALL(DB, BrassCursor *, "BrassTable::cursor_get", NO_ARGS);
    1306         [ +  + ]:    2004150 :     if (handle < 0) {
    1307         [ +  + ]:          9 :         if (handle == -2) {
    1308                 :          7 :             BrassTable::throw_database_closed();
    1309                 :            :         }
    1310                 :          2 :         RETURN(NULL);
    1311                 :            :     }
    1312                 :            :     // FIXME Ick - casting away const is nasty
    1313                 :    2004143 :     RETURN(new BrassCursor(const_cast<BrassTable *>(this)));
    1314                 :            : }
    1315                 :            : 
    1316                 :            : /************ B-tree opening and closing ************/
    1317                 :            : 
    1318                 :            : bool
    1319                 :       8793 : BrassTable::basic_open(bool revision_supplied, brass_revision_number_t revision_)
    1320                 :            : {
    1321                 :            :     LOGCALL(DB, bool, "BrassTable::basic_open", revision_supplied | revision_);
    1322                 :       8793 :     int ch = 'X'; /* will be 'A' or 'B' */
    1323                 :            : 
    1324                 :            :     {
    1325                 :       8793 :         const size_t BTREE_BASES = 2;
    1326                 :       8793 :         string err_msg;
    1327                 :            :         static const char basenames[BTREE_BASES] = { 'A', 'B' };
    1328                 :            : 
    1329 [ +  + ][ #  # ]:      26379 :         BrassTable_base bases[BTREE_BASES];
                 [ #  # ]
    1330                 :            :         bool base_ok[BTREE_BASES];
    1331                 :            : 
    1332                 :       8793 :         both_bases = true;
    1333                 :       8793 :         bool valid_base = false;
    1334                 :            :         {
    1335         [ +  + ]:      26379 :             for (size_t i = 0; i < BTREE_BASES; ++i) {
    1336                 :      17586 :                 bool ok = bases[i].read(name, basenames[i], writable, err_msg);
    1337                 :      17586 :                 base_ok[i] = ok;
    1338         [ +  + ]:      17586 :                 if (ok) {
    1339                 :      15152 :                     valid_base = true;
    1340                 :            :                 } else {
    1341                 :       2434 :                     both_bases = false;
    1342                 :            :                 }
    1343                 :            :             }
    1344                 :            :         }
    1345                 :            : 
    1346         [ -  + ]:       8793 :         if (!valid_base) {
    1347         [ #  # ]:          0 :             if (handle >= 0) {
    1348                 :          0 :                 ::close(handle);
    1349                 :          0 :                 handle = -1;
    1350                 :            :             }
    1351                 :          0 :             string message = "Error opening table `";
    1352                 :          0 :             message += name;
    1353                 :          0 :             message += "':\n";
    1354                 :          0 :             message += err_msg;
    1355                 :          0 :             throw Xapian::DatabaseOpeningError(message);
    1356                 :            :         }
    1357                 :            : 
    1358         [ +  + ]:       8793 :         if (revision_supplied) {
    1359                 :       5255 :             bool found_revision = false;
    1360         [ +  - ]:       9535 :             for (size_t i = 0; i < BTREE_BASES; ++i) {
    1361 [ +  + ][ +  + ]:       9535 :                 if (base_ok[i] && bases[i].get_revision() == revision_) {
                 [ +  + ]
    1362                 :       5255 :                     ch = basenames[i];
    1363                 :       5255 :                     found_revision = true;
    1364                 :       5255 :                     break;
    1365                 :            :                 }
    1366                 :            :             }
    1367         [ -  + ]:       5255 :             if (!found_revision) {
    1368                 :            :                 /* Couldn't open the revision that was asked for.
    1369                 :            :                  * This shouldn't throw an exception, but should just return
    1370                 :            :                  * false to upper levels.
    1371                 :            :                  */
    1372                 :          0 :                 RETURN(false);
    1373                 :            :             }
    1374                 :            :         } else {
    1375                 :       3538 :             brass_revision_number_t highest_revision = 0;
    1376         [ +  + ]:      10614 :             for (size_t i = 0; i < BTREE_BASES; ++i) {
    1377 [ +  + ][ +  + ]:       7076 :                 if (base_ok[i] && bases[i].get_revision() >= highest_revision) {
                 [ +  + ]
    1378                 :       5444 :                     ch = basenames[i];
    1379                 :       5444 :                     highest_revision = bases[i].get_revision();
    1380                 :            :                 }
    1381                 :            :             }
    1382                 :            :         }
    1383                 :            : 
    1384                 :       8793 :         BrassTable_base *basep = 0;
    1385                 :       8793 :         BrassTable_base *other_base = 0;
    1386                 :            : 
    1387         [ +  - ]:      14979 :         for (size_t i = 0; i < BTREE_BASES; ++i) {
    1388                 :            :             LOGLINE(DB, "Checking (ch == " << ch << ") against "
    1389                 :            :                     "basenames[" << i << "] == " << basenames[i]);
    1390                 :            :             LOGLINE(DB, "bases[" << i << "].get_revision() == " <<
    1391                 :            :                     bases[i].get_revision());
    1392                 :            :             LOGLINE(DB, "base_ok[" << i << "] == " << base_ok[i]);
    1393         [ +  + ]:      14979 :             if (ch == basenames[i]) {
    1394                 :       8793 :                 basep = &bases[i];
    1395                 :            : 
    1396                 :            :                 // FIXME: assuming only two bases for other_base
    1397                 :       8793 :                 size_t otherbase_num = 1-i;
    1398         [ +  + ]:       8793 :                 if (base_ok[otherbase_num]) {
    1399                 :       6359 :                     other_base = &bases[otherbase_num];
    1400                 :            :                 }
    1401                 :       8793 :                 break;
    1402                 :            :             }
    1403                 :            :         }
    1404                 :            :         Assert(basep);
    1405                 :            : 
    1406                 :            :         /* basep now points to the most recent base block */
    1407                 :            : 
    1408                 :            :         /* Avoid copying the bitmap etc. - swap contents with the base
    1409                 :            :          * object in the vector, since it'll be destroyed anyway soon.
    1410                 :            :          */
    1411                 :       8793 :         base.swap(*basep);
    1412                 :            : 
    1413                 :       8793 :         revision_number =  base.get_revision();
    1414                 :       8793 :         block_size =       base.get_block_size();
    1415                 :       8793 :         root =             base.get_root();
    1416                 :       8793 :         level =            base.get_level();
    1417                 :            :         //bit_map_size =     basep->get_bit_map_size();
    1418                 :       8793 :         item_count =       base.get_item_count();
    1419                 :       8793 :         faked_root_block = base.get_have_fakeroot();
    1420                 :       8793 :         sequential =       base.get_sequential();
    1421                 :            : 
    1422         [ +  + ]:       8793 :         if (other_base != 0) {
    1423                 :       6359 :             latest_revision_number = other_base->get_revision();
    1424         [ +  - ]:       6359 :             if (revision_number > latest_revision_number)
    1425                 :       6359 :                 latest_revision_number = revision_number;
    1426                 :            :         } else {
    1427                 :       8793 :             latest_revision_number = revision_number;
    1428 [ #  # ][ +  + ]:      26379 :         }
         [ -  + ][ +  - ]
    1429                 :            :     }
    1430                 :            : 
    1431                 :            :     /* kt holds constructed items as well as keys */
    1432                 :       8793 :     kt = Item_wr(zeroed_new(block_size));
    1433                 :            : 
    1434                 :       8793 :     set_max_item_size(BLOCK_CAPACITY);
    1435                 :            : 
    1436                 :       8793 :     base_letter = ch;
    1437                 :            : 
    1438                 :            :     /* ready to open the main file */
    1439                 :            : 
    1440                 :       8793 :     RETURN(true);
    1441                 :            : }
    1442                 :            : 
    1443                 :            : void
    1444                 :      11001 : BrassTable::read_root()
    1445                 :            : {
    1446                 :            :     LOGCALL_VOID(DB, "BrassTable::read_root", NO_ARGS);
    1447         [ +  + ]:      11001 :     if (faked_root_block) {
    1448                 :            :         /* root block for an unmodified database. */
    1449                 :       2960 :         byte * p = C[0].p;
    1450                 :            :         Assert(p);
    1451                 :            : 
    1452                 :            :         /* clear block - shouldn't be necessary, but is a bit nicer,
    1453                 :            :          * and means that the same operations should always produce
    1454                 :            :          * the same database. */
    1455                 :       2960 :         memset(p, 0, block_size);
    1456                 :            : 
    1457                 :       2960 :         int o = block_size - I2 - K1 - C2 - C2;
    1458                 :       2960 :         Item_wr(p + o).fake_root_item();
    1459                 :            : 
    1460                 :       2960 :         setD(p, DIR_START, o);         // its directory entry
    1461                 :       2960 :         SET_DIR_END(p, DIR_START + D2);// the directory size
    1462                 :            : 
    1463                 :       2960 :         o -= (DIR_START + D2);
    1464                 :       2960 :         SET_MAX_FREE(p, o);
    1465                 :       2960 :         SET_TOTAL_FREE(p, o);
    1466                 :       2960 :         SET_LEVEL(p, 0);
    1467                 :            : 
    1468         [ +  + ]:       2960 :         if (!writable) {
    1469                 :            :             /* reading - revision number doesn't matter as long as
    1470                 :            :              * it's not greater than the current one. */
    1471                 :        572 :             SET_REVISION(p, 0);
    1472                 :        572 :             C[0].n = 0;
    1473                 :            :         } else {
    1474                 :            :             /* writing - */
    1475                 :       2388 :             SET_REVISION(p, latest_revision_number + 1);
    1476                 :       2388 :             C[0].n = base.next_free_block();
    1477                 :            :         }
    1478                 :            :     } else {
    1479                 :            :         /* using a root block stored on disk */
    1480                 :       8041 :         block_to_cursor(C, level, root);
    1481                 :            : 
    1482         [ -  + ]:       8041 :         if (REVISION(C[level].p) > revision_number) set_overwritten();
    1483                 :            :         /* although this is unlikely */
    1484                 :            :     }
    1485                 :      11001 : }
    1486                 :            : 
    1487                 :            : bool
    1488                 :       3159 : BrassTable::do_open_to_write(bool revision_supplied,
    1489                 :            :                              brass_revision_number_t revision_,
    1490                 :            :                              bool create_db)
    1491                 :            : {
    1492                 :            :     LOGCALL(DB, bool, "BrassTable::do_open_to_write", revision_supplied | revision_ | create_db);
    1493         [ -  + ]:       3159 :     if (handle == -2) {
    1494                 :          0 :         BrassTable::throw_database_closed();
    1495                 :            :     }
    1496                 :       3159 :     int flags = O_RDWR | O_BINARY;
    1497         [ +  + ]:       3159 :     if (create_db) flags |= O_CREAT | O_TRUNC;
    1498                 :       3159 :     handle = ::open((name + "DB").c_str(), flags, 0666);
    1499         [ +  + ]:       3159 :     if (handle < 0) {
    1500                 :            :         // lazy doesn't make a lot of sense with create_db anyway, but ENOENT
    1501                 :            :         // with O_CREAT means a parent directory doesn't exist.
    1502 [ +  - ][ +  - ]:        925 :         if (lazy && !create_db && errno == ENOENT) {
                 [ +  - ]
    1503                 :        925 :             revision_number = revision_;
    1504                 :        925 :             RETURN(true);
    1505                 :            :         }
    1506         [ #  # ]:          0 :         string message(create_db ? "Couldn't create " : "Couldn't open ");
    1507                 :          0 :         message += name;
    1508                 :          0 :         message += "DB read/write: ";
    1509                 :          0 :         message += strerror(errno);
    1510                 :          0 :         throw Xapian::DatabaseOpeningError(message);
    1511                 :            :     }
    1512                 :            : 
    1513         [ -  + ]:       2234 :     if (!basic_open(revision_supplied, revision_)) {
    1514                 :          0 :         ::close(handle);
    1515                 :          0 :         handle = -1;
    1516         [ #  # ]:          0 :         if (!revision_supplied) {
    1517                 :          0 :             throw Xapian::DatabaseOpeningError("Failed to open for writing");
    1518                 :            :         }
    1519                 :            :         /* When the revision is supplied, it's not an exceptional
    1520                 :            :          * case when open failed, so we just return false here.
    1521                 :            :          */
    1522                 :          0 :         RETURN(false);
    1523                 :            :     }
    1524                 :            : 
    1525                 :       2234 :     writable = true;
    1526                 :            : 
    1527         [ +  + ]:       4532 :     for (int j = 0; j <= level; j++) {
    1528                 :       2298 :         C[j].n = BLK_UNUSED;
    1529                 :       2298 :         C[j].p = new byte[block_size];
    1530         [ -  + ]:       2298 :         if (C[j].p == 0) {
    1531                 :          0 :             throw std::bad_alloc();
    1532                 :            :         }
    1533                 :            :     }
    1534                 :       2234 :     split_p = new byte[block_size];
    1535         [ -  + ]:       2234 :     if (split_p == 0) {
    1536                 :          0 :         throw std::bad_alloc();
    1537                 :            :     }
    1538                 :       2234 :     read_root();
    1539                 :            : 
    1540                 :       2234 :     buffer = zeroed_new(block_size);
    1541                 :            : 
    1542                 :       2234 :     changed_n = 0;
    1543                 :       2234 :     changed_c = DIR_START;
    1544                 :       2234 :     seq_count = SEQ_START_POINT;
    1545                 :            : 
    1546                 :       3159 :     RETURN(true);
    1547                 :            : }
    1548                 :            : 
    1549                 :      13402 : BrassTable::BrassTable(const char * tablename_, const string & path_,
    1550                 :            :                        bool readonly_, int compress_strategy_, bool lazy_)
    1551                 :            :         : tablename(tablename_),
    1552                 :            :           revision_number(0),
    1553                 :            :           item_count(0),
    1554                 :            :           block_size(0),
    1555                 :            :           latest_revision_number(0),
    1556                 :            :           both_bases(false),
    1557                 :            :           base_letter('A'),
    1558                 :            :           faked_root_block(true),
    1559                 :            :           sequential(true),
    1560                 :            :           handle(-1),
    1561                 :            :           level(0),
    1562                 :            :           root(0),
    1563                 :            :           kt(0),
    1564                 :            :           buffer(0),
    1565                 :            :           base(),
    1566                 :            :           name(path_),
    1567                 :            :           seq_count(0),
    1568                 :            :           changed_n(0),
    1569                 :            :           changed_c(0),
    1570                 :            :           max_item_size(0),
    1571                 :            :           Btree_modified(false),
    1572                 :            :           full_compaction(false),
    1573                 :            :           writable(!readonly_),
    1574                 :            :           cursor_created_since_last_modification(false),
    1575                 :            :           cursor_version(0),
    1576                 :            :           split_p(0),
    1577                 :            :           compress_strategy(compress_strategy_),
    1578                 :            :           deflate_zstream(NULL),
    1579                 :            :           inflate_zstream(NULL),
    1580 [ +  + ][ +  + ]:     147422 :           lazy(lazy_)
    1581                 :            : {
    1582                 :            :     LOGCALL_CTOR(DB, "BrassTable", tablename_ | path_ | readonly_ | compress_strategy_ | lazy_);
    1583                 :      13402 : }
    1584                 :            : 
    1585                 :            : bool
    1586                 :        893 : BrassTable::really_empty() const
    1587                 :            : {
    1588         [ +  + ]:        893 :     if (handle < 0) {
    1589         [ -  + ]:        426 :         if (handle == -2) {
    1590                 :          0 :             BrassTable::throw_database_closed();
    1591                 :            :         }
    1592                 :        426 :         return true;
    1593                 :            :     }
    1594                 :        467 :     BrassCursor cur(const_cast<BrassTable*>(this));
    1595                 :        467 :     cur.find_entry(string());
    1596                 :        893 :     return !cur.next();
    1597                 :            : }
    1598                 :            : 
    1599                 :            : void
    1600                 :      58202 : BrassTable::lazy_alloc_deflate_zstream() const {
    1601         [ +  + ]:      58202 :     if (usual(deflate_zstream)) {
    1602         [ +  - ]:      57844 :         if (usual(deflateReset(deflate_zstream) == Z_OK)) return;
    1603                 :            :         // Try to recover by deleting the stream and starting from scratch.
    1604                 :          0 :         delete deflate_zstream;
    1605                 :            :     }
    1606                 :            : 
    1607                 :        358 :     deflate_zstream = new z_stream;
    1608                 :            : 
    1609                 :        358 :     deflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
    1610                 :        358 :     deflate_zstream->zfree = reinterpret_cast<free_func>(0);
    1611                 :        358 :     deflate_zstream->opaque = (voidpf)0;
    1612                 :            : 
    1613                 :            :     // -15 means raw deflate with 32K LZ77 window (largest)
    1614                 :            :     // memLevel 9 is the highest (8 is default)
    1615                 :            :     int err;
    1616                 :            :     err = deflateInit2(deflate_zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
    1617                 :        358 :                        -15, 9, compress_strategy);
    1618         [ -  + ]:        358 :     if (rare(err != Z_OK)) {
    1619         [ #  # ]:          0 :         if (err == Z_MEM_ERROR) {
    1620                 :          0 :             delete deflate_zstream;
    1621                 :          0 :             deflate_zstream = 0;
    1622                 :          0 :             throw std::bad_alloc();
    1623                 :            :         }
    1624                 :          0 :         string msg = "deflateInit2 failed (";
    1625         [ #  # ]:          0 :         if (deflate_zstream->msg) {
    1626                 :          0 :             msg += deflate_zstream->msg;
    1627                 :            :         } else {
    1628                 :          0 :             msg += str(err);
    1629                 :            :         }
    1630                 :          0 :         msg += ')';
    1631                 :          0 :         delete deflate_zstream;
    1632                 :          0 :         deflate_zstream = 0;
    1633                 :      58202 :         throw Xapian::DatabaseError(msg);
    1634                 :            :     }
    1635                 :            : }
    1636                 :            : 
    1637                 :            : void
    1638                 :     207427 : BrassTable::lazy_alloc_inflate_zstream() const {
    1639         [ +  + ]:     207427 :     if (usual(inflate_zstream)) {
    1640         [ +  - ]:     207217 :         if (usual(inflateReset(inflate_zstream) == Z_OK)) return;
    1641                 :            :         // Try to recover by deleting the stream and starting from scratch.
    1642                 :          0 :         delete inflate_zstream;
    1643                 :            :     }
    1644                 :            : 
    1645                 :        210 :     inflate_zstream = new z_stream;
    1646                 :            : 
    1647                 :        210 :     inflate_zstream->zalloc = reinterpret_cast<alloc_func>(0);
    1648                 :        210 :     inflate_zstream->zfree = reinterpret_cast<free_func>(0);
    1649                 :            : 
    1650                 :        210 :     inflate_zstream->next_in = Z_NULL;
    1651                 :        210 :     inflate_zstream->avail_in = 0;
    1652                 :            : 
    1653                 :        210 :     int err = inflateInit2(inflate_zstream, -15);
    1654         [ -  + ]:        210 :     if (rare(err != Z_OK)) {
    1655         [ #  # ]:          0 :         if (err == Z_MEM_ERROR) {
    1656                 :          0 :             delete inflate_zstream;
    1657                 :          0 :             inflate_zstream = 0;
    1658                 :          0 :             throw std::bad_alloc();
    1659                 :            :         }
    1660                 :          0 :         string msg = "inflateInit2 failed (";
    1661         [ #  # ]:          0 :         if (inflate_zstream->msg) {
    1662                 :          0 :             msg += inflate_zstream->msg;
    1663                 :            :         } else {
    1664                 :          0 :             msg += str(err);
    1665                 :            :         }
    1666                 :          0 :         msg += ')';
    1667                 :          0 :         delete inflate_zstream;
    1668                 :          0 :         inflate_zstream = 0;
    1669                 :     207427 :         throw Xapian::DatabaseError(msg);
    1670                 :            :     }
    1671                 :            : }
    1672                 :            : 
    1673                 :            : bool
    1674                 :        588 : BrassTable::exists() const {
    1675                 :            :     LOGCALL(DB, bool, "BrassTable::exists", NO_ARGS);
    1676                 :            :     return (file_exists(name + "DB") &&
    1677 [ +  + ][ -  + ]:        588 :             (file_exists(name + "baseA") || file_exists(name + "baseB")));
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ +  + ][ #  # ]
                 [ +  - ]
    1678                 :            : }
    1679                 :            : 
    1680                 :            : void
    1681                 :        931 : BrassTable::erase()
    1682                 :            : {
    1683                 :            :     LOGCALL_VOID(DB, "BrassTable::erase", NO_ARGS);
    1684                 :        931 :     close();
    1685                 :            : 
    1686                 :        931 :     (void)io_unlink(name + "baseA");
    1687                 :        931 :     (void)io_unlink(name + "baseB");
    1688                 :        931 :     (void)io_unlink(name + "DB");
    1689                 :        931 : }
    1690                 :            : 
    1691                 :            : void
    1692                 :       9761 : BrassTable::set_block_size(unsigned int block_size_)
    1693                 :            : {
    1694                 :            :     LOGCALL_VOID(DB, "BrassTable::set_block_size", block_size_);
    1695                 :            :     // Block size must in the range 2048..BYTE_PAIR_RANGE, and a power of two.
    1696 [ +  - ][ +  - ]:       9761 :     if (block_size_ < 2048 || block_size_ > BYTE_PAIR_RANGE ||
                 [ -  + ]
    1697                 :            :         (block_size_ & (block_size_ - 1)) != 0) {
    1698                 :          0 :         block_size_ = BRASS_DEFAULT_BLOCK_SIZE;
    1699                 :            :     }
    1700                 :       9761 :     block_size = block_size_;
    1701                 :       9761 : }
    1702                 :            : 
    1703                 :            : void
    1704                 :       1134 : BrassTable::create_and_open(unsigned int block_size_)
    1705                 :            : {
    1706                 :            :     LOGCALL_VOID(DB, "BrassTable::create_and_open", block_size_);
    1707         [ -  + ]:       1134 :     if (handle == -2) {
    1708                 :          0 :         BrassTable::throw_database_closed();
    1709                 :            :     }
    1710                 :            :     Assert(writable);
    1711                 :       1134 :     close();
    1712                 :            : 
    1713         [ -  + ]:       1134 :     if (block_size_ == 0) abort();
    1714                 :       1134 :     set_block_size(block_size_);
    1715                 :            : 
    1716                 :            :     // FIXME: it would be good to arrange that this works such that there's
    1717                 :            :     // always a valid table in place if you run create_and_open() on an
    1718                 :            :     // existing table.
    1719                 :            : 
    1720                 :            :     /* write initial values to files */
    1721                 :            : 
    1722                 :            :     /* create the base file */
    1723                 :       1134 :     BrassTable_base base_;
    1724                 :       1134 :     base_.set_revision(revision_number);
    1725                 :       1134 :     base_.set_block_size(block_size_);
    1726                 :       1134 :     base_.set_have_fakeroot(true);
    1727                 :       1134 :     base_.set_sequential(true);
    1728                 :       1134 :     base_.write_to_file(name + "baseA", 'A', string(), -1, NULL);
    1729                 :            : 
    1730                 :            :     /* remove the alternative base file, if any */
    1731                 :       1134 :     (void)io_unlink(name + "baseB");
    1732                 :            : 
    1733                 :            :     // Any errors are thrown if revision_supplied is false.
    1734                 :       1134 :     (void)do_open_to_write(false, 0, true);
    1735                 :       1134 : }
    1736                 :            : 
    1737                 :      13402 : BrassTable::~BrassTable() {
    1738                 :            :     LOGCALL_DTOR(DB, "BrassTable");
    1739                 :      13402 :     BrassTable::close();
    1740                 :            : 
    1741   [ +  +  +  + ]:      13402 :     if (deflate_zstream) {
    1742                 :            :         // Errors which we care about have already been handled, so just ignore
    1743                 :            :         // any which get returned here.
    1744                 :        358 :         (void) deflateEnd(deflate_zstream);
    1745                 :        358 :         delete deflate_zstream;
    1746                 :            :     }
    1747                 :            : 
    1748 [ -  + ][ +  + ]:      13402 :     if (inflate_zstream) {
    1749                 :            :         // Errors which we care about have already been handled, so just ignore
    1750                 :            :         // any which get returned here.
    1751                 :        210 :         (void) inflateEnd(inflate_zstream);
    1752                 :        210 :         delete inflate_zstream;
    1753                 :            :     }
    1754                 :      13402 : }
    1755                 :            : 
    1756                 :      27575 : void BrassTable::close(bool permanent) {
    1757                 :            :     LOGCALL_VOID(DB, "BrassTable::close", NO_ARGS);
    1758                 :            : 
    1759         [ +  + ]:      27575 :     if (handle >= 0) {
    1760                 :            :         // If an error occurs here, we just ignore it, since we're just
    1761                 :            :         // trying to free everything.
    1762                 :       8793 :         (void)::close(handle);
    1763                 :       8793 :         handle = -1;
    1764                 :            :     }
    1765                 :            : 
    1766         [ +  + ]:      27575 :     if (permanent) {
    1767                 :         78 :         handle = -2;
    1768                 :            :         // Don't delete the resources in the table, since they may
    1769                 :            :         // still be used to look up cached content.
    1770                 :         78 :         return;
    1771                 :            :     }
    1772         [ +  + ]:      57354 :     for (int j = level; j >= 0; j--) {
    1773         [ +  + ]:      29857 :         delete [] C[j].p;
    1774                 :      29857 :         C[j].p = 0;
    1775                 :            :     }
    1776         [ +  + ]:      27497 :     delete [] split_p;
    1777                 :      27497 :     split_p = 0;
    1778                 :            : 
    1779         [ +  + ]:      27497 :     delete [] kt.get_address();
    1780                 :      27497 :     kt = 0;
    1781         [ +  + ]:      27497 :     delete [] buffer;
    1782                 :      27575 :     buffer = 0;
    1783                 :            : }
    1784                 :            : 
    1785                 :            : void
    1786                 :       2878 : BrassTable::flush_db()
    1787                 :            : {
    1788                 :            :     LOGCALL_VOID(DB, "BrassTable::flush_db", NO_ARGS);
    1789                 :            :     Assert(writable);
    1790         [ +  + ]:       2878 :     if (handle < 0) {
    1791         [ -  + ]:       1139 :         if (handle == -2) {
    1792                 :          0 :             BrassTable::throw_database_closed();
    1793                 :            :         }
    1794                 :       1139 :         return;
    1795                 :            :     }
    1796                 :            : 
    1797         [ +  + ]:       3828 :     for (int j = level; j >= 0; j--) {
    1798         [ +  + ]:       2089 :         if (C[j].rewrite) {
    1799                 :       1887 :             write_block(C[j].n, C[j].p);
    1800                 :            :         }
    1801                 :            :     }
    1802                 :            : 
    1803         [ +  + ]:       1739 :     if (Btree_modified) {
    1804                 :       2878 :         faked_root_block = false;
    1805                 :            :     }
    1806                 :            : }
    1807                 :            : 
    1808                 :            : void
    1809                 :       2878 : BrassTable::commit(brass_revision_number_t revision, int changes_fd,
    1810                 :            :                    const string * changes_tail)
    1811                 :            : {
    1812                 :            :     LOGCALL_VOID(DB, "BrassTable::commit", revision | changes_fd | changes_tail);
    1813                 :            :     Assert(writable);
    1814                 :            : 
    1815         [ -  + ]:       2878 :     if (revision <= revision_number) {
    1816                 :          0 :         throw Xapian::DatabaseError("New revision too low");
    1817                 :            :     }
    1818                 :            : 
    1819         [ +  + ]:       2878 :     if (handle < 0) {
    1820         [ -  + ]:       1139 :         if (handle == -2) {
    1821                 :          0 :             BrassTable::throw_database_closed();
    1822                 :            :         }
    1823                 :       1139 :         latest_revision_number = revision_number = revision;
    1824                 :       1139 :         return;
    1825                 :            :     }
    1826                 :            : 
    1827                 :            :     try {
    1828         [ +  + ]:       1739 :         if (faked_root_block) {
    1829                 :            :             /* We will use a dummy bitmap. */
    1830                 :        102 :             base.clear_bit_map();
    1831                 :            :         }
    1832                 :            : 
    1833                 :       1739 :         base.set_revision(revision);
    1834                 :       1739 :         base.set_root(C[level].n);
    1835                 :       1739 :         base.set_level(level);
    1836                 :       1739 :         base.set_item_count(item_count);
    1837                 :       1739 :         base.set_have_fakeroot(faked_root_block);
    1838                 :       1739 :         base.set_sequential(sequential);
    1839                 :            : 
    1840                 :       1739 :         base_letter = other_base_letter();
    1841                 :            : 
    1842                 :       1739 :         both_bases = true;
    1843                 :       1739 :         latest_revision_number = revision_number = revision;
    1844                 :       1739 :         root = C[level].n;
    1845                 :            : 
    1846                 :       1739 :         Btree_modified = false;
    1847                 :            : 
    1848         [ +  + ]:      19129 :         for (int i = 0; i < BTREE_CURSOR_LEVELS; ++i) {
    1849                 :      17390 :             C[i].n = BLK_UNUSED;
    1850                 :      17390 :             C[i].c = -1;
    1851                 :      17390 :             C[i].rewrite = false;
    1852                 :            :         }
    1853                 :            : 
    1854                 :            :         // Save to "<table>.tmp" and then rename to "<table>.base<letter>" so
    1855                 :            :         // that a reader can't try to read a partially written base file.
    1856                 :       1739 :         string tmp = name;
    1857                 :       1739 :         tmp += "tmp";
    1858                 :       1739 :         string basefile = name;
    1859                 :       1739 :         basefile += "base";
    1860                 :       1739 :         basefile += char(base_letter);
    1861                 :       1739 :         base.write_to_file(tmp, base_letter, tablename, changes_fd, changes_tail);
    1862                 :            : 
    1863                 :            :         // Do this as late as possible to allow maximum time for writes to
    1864                 :            :         // happen, and so the calls to io_sync() are adjacent which may be
    1865                 :            :         // more efficient, at least with some Linux kernel versions.
    1866         [ -  + ]:       1739 :         if (!io_sync(handle)) {
    1867                 :          0 :             (void)::close(handle);
    1868                 :          0 :             handle = -1;
    1869                 :          0 :             (void)unlink(tmp);
    1870                 :          0 :             throw Xapian::DatabaseError("Can't commit new revision - failed to flush DB to disk");
    1871                 :            :         }
    1872                 :            : 
    1873                 :            : #if defined __WIN32__
    1874                 :            :         if (msvc_posix_rename(tmp.c_str(), basefile.c_str()) < 0)
    1875                 :            : #else
    1876         [ -  + ]:       1739 :         if (rename(tmp.c_str(), basefile.c_str()) < 0)
    1877                 :            : #endif
    1878                 :            :         {
    1879                 :            :             // With NFS, rename() failing may just mean that the server crashed
    1880                 :            :             // after successfully renaming, but before reporting this, and then
    1881                 :            :             // the retried operation fails.  So we need to check if the source
    1882                 :            :             // file still exists, which we do by calling unlink(), since we want
    1883                 :            :             // to remove the temporary file anyway.
    1884                 :          0 :             int saved_errno = errno;
    1885   [ #  #  #  # ]:          0 :             if (unlink(tmp) == 0 || errno != ENOENT) {
                 [ #  # ]
    1886                 :          0 :                 string msg("Couldn't update base file ");
    1887                 :          0 :                 msg += basefile;
    1888                 :          0 :                 msg += ": ";
    1889                 :          0 :                 msg += strerror(saved_errno);
    1890                 :          0 :                 throw Xapian::DatabaseError(msg);
    1891                 :            :             }
    1892                 :            :         }
    1893                 :       1739 :         base.commit();
    1894                 :            : 
    1895                 :       1739 :         read_root();
    1896                 :            : 
    1897                 :       1739 :         changed_n = 0;
    1898                 :       1739 :         changed_c = DIR_START;
    1899                 :       1739 :         seq_count = SEQ_START_POINT;
    1900                 :       2878 :     } catch (...) {
    1901                 :          0 :         BrassTable::close();
    1902                 :          0 :         throw;
    1903                 :            :     }
    1904                 :            : }
    1905                 :            : 
    1906                 :            : void
    1907                 :        372 : BrassTable::write_changed_blocks(int changes_fd)
    1908                 :            : {
    1909                 :            :     LOGCALL_VOID(DB, "BrassTable::write_changed_blocks", changes_fd);
    1910                 :            :     Assert(changes_fd >= 0);
    1911         [ +  + ]:        372 :     if (handle < 0) return;
    1912         [ +  + ]:        228 :     if (faked_root_block) return;
    1913                 :            : 
    1914                 :        207 :     string buf;
    1915                 :        207 :     pack_uint(buf, 2u); // Indicate the item is a list of blocks
    1916                 :        207 :     pack_string(buf, tablename);
    1917                 :        207 :     pack_uint(buf, block_size);
    1918                 :        207 :     io_write(changes_fd, buf.data(), buf.size());
    1919                 :            : 
    1920                 :            :     // Compare the old and new bitmaps to find blocks which have changed, and
    1921                 :            :     // write them to the file descriptor.
    1922                 :        207 :     uint4 n = 0;
    1923                 :        207 :     byte * p = new byte[block_size];
    1924                 :            :     try {
    1925                 :        207 :         base.calculate_last_block();
    1926         [ +  + ]:        646 :         while (base.find_changed_block(&n)) {
    1927                 :        439 :             buf.resize(0);
    1928                 :        439 :             pack_uint(buf, n + 1);
    1929                 :        439 :             io_write(changes_fd, buf.data(), buf.size());
    1930                 :            : 
    1931                 :            :             // Read block n.
    1932                 :        439 :             read_block(n, p);
    1933                 :            : 
    1934                 :            :             // Write block n to the file.
    1935                 :        439 :             io_write(changes_fd, reinterpret_cast<const char *>(p), block_size);
    1936                 :        439 :             ++n;
    1937                 :            :         }
    1938         [ +  - ]:        207 :         delete[] p;
    1939                 :        207 :         p = 0;
    1940                 :          0 :     } catch (...) {
    1941         [ #  # ]:          0 :         delete[] p;
    1942                 :          0 :         throw;
    1943                 :            :     }
    1944                 :        207 :     buf.resize(0);
    1945                 :        207 :     pack_uint(buf, 0u);
    1946                 :        372 :     io_write(changes_fd, buf.data(), buf.size());
    1947                 :            : }
    1948                 :            : 
    1949                 :            : void
    1950                 :        914 : BrassTable::cancel()
    1951                 :            : {
    1952                 :            :     LOGCALL_VOID(DB, "BrassTable::cancel", NO_ARGS);
    1953                 :            :     Assert(writable);
    1954                 :            : 
    1955         [ +  + ]:        914 :     if (handle < 0) {
    1956         [ +  + ]:        445 :         if (handle == -2) {
    1957                 :          2 :             BrassTable::throw_database_closed();
    1958                 :            :         }
    1959                 :        443 :         latest_revision_number = revision_number; // FIXME: we can end up reusing a revision if we opened a btree at an older revision, start to modify it, then cancel...
    1960                 :        443 :         return;
    1961                 :            :     }
    1962                 :            : 
    1963                 :            :     // This causes problems: if (!Btree_modified) return;
    1964                 :            : 
    1965                 :        469 :     string err_msg;
    1966         [ -  + ]:        469 :     if (!base.read(name, base_letter, writable, err_msg)) {
    1967                 :          0 :         throw Xapian::DatabaseCorruptError(string("Couldn't reread base ") + base_letter);
    1968                 :            :     }
    1969                 :            : 
    1970                 :        469 :     revision_number =  base.get_revision();
    1971                 :        469 :     block_size =       base.get_block_size();
    1972                 :        469 :     root =             base.get_root();
    1973                 :        469 :     level =            base.get_level();
    1974                 :            :     //bit_map_size =     basep->get_bit_map_size();
    1975                 :        469 :     item_count =       base.get_item_count();
    1976                 :        469 :     faked_root_block = base.get_have_fakeroot();
    1977                 :        469 :     sequential =       base.get_sequential();
    1978                 :            : 
    1979                 :        469 :     latest_revision_number = revision_number; // FIXME: we can end up reusing a revision if we opened a btree at an older revision, start to modify it, then cancel...
    1980                 :            : 
    1981                 :        469 :     Btree_modified = false;
    1982                 :            : 
    1983         [ +  + ]:        976 :     for (int j = 0; j <= level; j++) {
    1984                 :        507 :         C[j].n = BLK_UNUSED;
    1985                 :        507 :         C[j].rewrite = false;
    1986                 :            :     }
    1987                 :        469 :     read_root();
    1988                 :            : 
    1989                 :        469 :     changed_n = 0;
    1990                 :        469 :     changed_c = DIR_START;
    1991                 :        912 :     seq_count = SEQ_START_POINT;
    1992                 :            : }
    1993                 :            : 
    1994                 :            : /************ B-tree reading ************/
    1995                 :            : 
    1996                 :            : bool
    1997                 :      10005 : BrassTable::do_open_to_read(bool revision_supplied, brass_revision_number_t revision_)
    1998                 :            : {
    1999                 :            :     LOGCALL(DB, bool, "BrassTable::do_open_to_read", revision_supplied | revision_);
    2000         [ +  + ]:      10005 :     if (handle == -2) {
    2001                 :          4 :         BrassTable::throw_database_closed();
    2002                 :            :     }
    2003                 :      10001 :     handle = ::open((name + "DB").c_str(), O_RDONLY | O_BINARY);
    2004         [ +  + ]:      10001 :     if (handle < 0) {
    2005         [ +  - ]:       3442 :         if (lazy) {
    2006                 :            :             // This table is optional when reading!
    2007                 :       3442 :             revision_number = revision_;
    2008                 :       3442 :             RETURN(true);
    2009                 :            :         }
    2010                 :          0 :         string message("Couldn't open ");
    2011                 :          0 :         message += name;
    2012                 :          0 :         message += "DB to read: ";
    2013                 :          0 :         message += strerror(errno);
    2014                 :          0 :         throw Xapian::DatabaseOpeningError(message);
    2015                 :            :     }
    2016                 :            : 
    2017         [ -  + ]:       6559 :     if (!basic_open(revision_supplied, revision_)) {
    2018                 :          0 :         ::close(handle);
    2019                 :          0 :         handle = -1;
    2020         [ #  # ]:          0 :         if (revision_supplied) {
    2021                 :            :             // The requested revision was not available.
    2022                 :            :             // This could be because the database was modified underneath us, or
    2023                 :            :             // because a base file is missing.  Return false, and work out what
    2024                 :            :             // the problem was at a higher level.
    2025                 :          0 :             RETURN(false);
    2026                 :            :         }
    2027                 :          0 :         throw Xapian::DatabaseOpeningError("Failed to open table for reading");
    2028                 :            :     }
    2029                 :            : 
    2030         [ +  + ]:      15223 :     for (int j = 0; j <= level; j++) {
    2031                 :       8664 :         C[j].n = BLK_UNUSED;
    2032                 :       8664 :         C[j].p = new byte[block_size];
    2033         [ -  + ]:       8664 :         if (C[j].p == 0) {
    2034                 :          0 :             throw std::bad_alloc();
    2035                 :            :         }
    2036                 :            :     }
    2037                 :            : 
    2038                 :       6559 :     read_root();
    2039                 :      10001 :     RETURN(true);
    2040                 :            : }
    2041                 :            : 
    2042                 :            : void
    2043                 :       2410 : BrassTable::open()
    2044                 :            : {
    2045                 :            :     LOGCALL_VOID(DB, "BrassTable::open", NO_ARGS);
    2046                 :            :     LOGLINE(DB, "opening at path " << name);
    2047                 :       2410 :     close();
    2048                 :            : 
    2049         [ +  + ]:       2410 :     if (!writable) {
    2050                 :            :         // Any errors are thrown if revision_supplied is false
    2051                 :       2070 :         (void)do_open_to_read(false, 0);
    2052                 :       2066 :         return;
    2053                 :            :     }
    2054                 :            : 
    2055                 :            :     // Any errors are thrown if revision_supplied is false.
    2056                 :       2406 :     (void)do_open_to_write(false, 0);
    2057                 :            : }
    2058                 :            : 
    2059                 :            : bool
    2060                 :       9620 : BrassTable::open(brass_revision_number_t revision)
    2061                 :            : {
    2062                 :            :     LOGCALL(DB, bool, "BrassTable::open", revision);
    2063                 :            :     LOGLINE(DB, "opening for particular revision at path " << name);
    2064                 :       9620 :     close();
    2065                 :            : 
    2066         [ +  + ]:       9620 :     if (!writable) {
    2067         [ +  - ]:       7935 :         if (do_open_to_read(true, revision)) {
    2068                 :            :             AssertEq(revision_number, revision);
    2069                 :       7935 :             RETURN(true);
    2070                 :            :         } else {
    2071                 :          0 :             close();
    2072                 :          0 :             RETURN(false);
    2073                 :            :         }
    2074                 :            :     }
    2075                 :            : 
    2076         [ -  + ]:       1685 :     if (!do_open_to_write(true, revision)) {
    2077                 :            :         // Can't open at the requested revision.
    2078                 :          0 :         close();
    2079                 :          0 :         RETURN(false);
    2080                 :            :     }
    2081                 :            : 
    2082                 :            :     AssertEq(revision_number, revision);
    2083                 :       9620 :     RETURN(true);
    2084                 :            : }
    2085                 :            : 
    2086                 :            : bool
    2087                 :         30 : BrassTable::prev_for_sequential(Brass::Cursor * C_, int /*dummy*/) const
    2088                 :            : {
    2089                 :            :     LOGCALL(DB, bool, "BrassTable::prev_for_sequential", Literal("C_") | Literal("/*dummy*/"));
    2090                 :         30 :     int c = C_[0].c;
    2091         [ -  + ]:         30 :     if (c == DIR_START) {
    2092                 :          0 :         byte * p = C_[0].p;
    2093                 :            :         Assert(p);
    2094                 :          0 :         uint4 n = C_[0].n;
    2095                 :          0 :         while (true) {
    2096         [ #  # ]:          0 :             if (n == 0) RETURN(false);
    2097                 :          0 :             n--;
    2098         [ #  # ]:          0 :             if (writable) {
    2099         [ #  # ]:          0 :                 if (n == C[0].n) {
    2100                 :            :                     // Block is a leaf block in the built-in cursor
    2101                 :            :                     // (potentially in modified form).
    2102                 :          0 :                     memcpy(p, C[0].p, block_size);
    2103                 :            :                 } else {
    2104                 :            :                     // Blocks in the built-in cursor may not have been written
    2105                 :            :                     // to disk yet, so we have to check that the block number
    2106                 :            :                     // isn't in the built-in cursor or we'll read an
    2107                 :            :                     // uninitialised block (for which GET_LEVEL(p) will
    2108                 :            :                     // probably return 0).
    2109                 :            :                     int j;
    2110         [ #  # ]:          0 :                     for (j = 1; j <= level; ++j) {
    2111         [ #  # ]:          0 :                         if (n == C[j].n) break;
    2112                 :            :                     }
    2113         [ #  # ]:          0 :                     if (j <= level) continue;
    2114                 :            : 
    2115                 :            :                     // Block isn't in the built-in cursor, so the form on disk
    2116                 :            :                     // is valid, so read it to check if it's the next level 0
    2117                 :            :                     // block.
    2118                 :          0 :                     read_block(n, p);
    2119                 :            :                 }
    2120                 :            :             } else {
    2121                 :          0 :                 read_block(n, p);
    2122                 :            :             }
    2123                 :          0 :             if (writable) AssertEq(revision_number, latest_revision_number);
    2124         [ #  # ]:          0 :             if (REVISION(p) > revision_number + writable) {
    2125                 :          0 :                 set_overwritten();
    2126                 :            :                 RETURN(false);
    2127                 :            :             }
    2128         [ #  # ]:          0 :             if (GET_LEVEL(p) == 0) break;
    2129                 :            :         }
    2130                 :          0 :         c = DIR_END(p);
    2131                 :          0 :         C_[0].n = n;
    2132                 :            :     }
    2133                 :         30 :     c -= D2;
    2134                 :         30 :     C_[0].c = c;
    2135                 :         30 :     RETURN(true);
    2136                 :            : }
    2137                 :            : 
    2138                 :            : bool
    2139                 :     116217 : BrassTable::next_for_sequential(Brass::Cursor * C_, int /*dummy*/) const
    2140                 :            : {
    2141                 :            :     LOGCALL(DB, bool, "BrassTable::next_for_sequential", Literal("C_") | Literal("/*dummy*/"));
    2142                 :     116217 :     byte * p = C_[0].p;
    2143                 :            :     Assert(p);
    2144                 :     116217 :     int c = C_[0].c;
    2145                 :     116217 :     c += D2;
    2146                 :            :     Assert((unsigned)c < block_size);
    2147         [ +  + ]:     116217 :     if (c == DIR_END(p)) {
    2148                 :      14821 :         uint4 n = C_[0].n;
    2149                 :         19 :         while (true) {
    2150                 :      14840 :             n++;
    2151         [ +  + ]:      14840 :             if (n > base.get_last_block()) RETURN(false);
    2152         [ +  + ]:      14507 :             if (writable) {
    2153         [ -  + ]:         48 :                 if (n == C[0].n) {
    2154                 :            :                     // Block is a leaf block in the built-in cursor
    2155                 :            :                     // (potentially in modified form).
    2156                 :          0 :                     memcpy(p, C[0].p, block_size);
    2157                 :            :                 } else {
    2158                 :            :                     // Blocks in the built-in cursor may not have been written
    2159                 :            :                     // to disk yet, so we have to check that the block number
    2160                 :            :                     // isn't in the built-in cursor or we'll read an
    2161                 :            :                     // uninitialised block (for which GET_LEVEL(p) will
    2162                 :            :                     // probably return 0).
    2163                 :            :                     int j;
    2164         [ +  + ]:         90 :                     for (j = 1; j <= level; ++j) {
    2165         [ +  + ]:         48 :                         if (n == C[j].n) break;
    2166                 :            :                     }
    2167         [ +  + ]:         48 :                     if (j <= level) continue;
    2168                 :            : 
    2169                 :            :                     // Block isn't in the built-in cursor, so the form on disk
    2170                 :            :                     // is valid, so read it to check if it's the next level 0
    2171                 :            :                     // block.
    2172                 :         42 :                     read_block(n, p);
    2173                 :            :                 }
    2174                 :            :             } else {
    2175                 :      14459 :                 read_block(n, p);
    2176                 :            :             }
    2177                 :      14501 :             if (writable) AssertEq(revision_number, latest_revision_number);
    2178         [ -  + ]:      14501 :             if (REVISION(p) > revision_number + writable) {
    2179                 :          0 :                 set_overwritten();
    2180                 :            :                 RETURN(false);
    2181                 :            :             }
    2182         [ +  + ]:      14501 :             if (GET_LEVEL(p) == 0) break;
    2183                 :            :         }
    2184                 :      14488 :         c = DIR_START;
    2185                 :      14488 :         C_[0].n = n;
    2186                 :            :     }
    2187                 :     115884 :     C_[0].c = c;
    2188                 :     116217 :     RETURN(true);
    2189                 :            : }
    2190                 :            : 
    2191                 :            : bool
    2192                 :    4814747 : BrassTable::prev_default(Brass::Cursor * C_, int j) const
    2193                 :            : {
    2194                 :            :     LOGCALL(DB, bool, "BrassTable::prev_default", Literal("C_") | j);
    2195                 :    4814747 :     byte * p = C_[j].p;
    2196                 :    4814747 :     int c = C_[j].c;
    2197                 :            :     Assert(c >= DIR_START);
    2198                 :            :     Assert((unsigned)c < block_size);
    2199                 :            :     Assert(c <= DIR_END(p));
    2200         [ +  + ]:    4814747 :     if (c == DIR_START) {
    2201         [ -  + ]:     933400 :         if (j == level) RETURN(false);
    2202         [ -  + ]:     933400 :         if (!prev_default(C_, j + 1)) RETURN(false);
    2203                 :     933400 :         c = DIR_END(p);
    2204                 :            :     }
    2205                 :    4814747 :     c -= D2;
    2206                 :    4814747 :     C_[j].c = c;
    2207         [ +  + ]:    4814747 :     if (j > 0) {
    2208                 :     933400 :         block_to_cursor(C_, j - 1, Item(p, c).block_given_by());
    2209                 :            :     }
    2210                 :    4814747 :     RETURN(true);
    2211                 :            : }
    2212                 :            : 
    2213                 :            : bool
    2214                 :    7797500 : BrassTable::next_default(Brass::Cursor * C_, int j) const
    2215                 :            : {
    2216                 :            :     LOGCALL(DB, bool, "BrassTable::next_default", Literal("C_") | j);
    2217                 :    7797500 :     byte * p = C_[j].p;
    2218                 :    7797500 :     int c = C_[j].c;
    2219                 :            :     Assert(c >= DIR_START);
    2220                 :    7797500 :     c += D2;
    2221                 :            :     Assert((unsigned)c < block_size);
    2222                 :            :     // Sometimes c can be DIR_END(p) + 2 here it appears...
    2223         [ +  + ]:    7797500 :     if (c >= DIR_END(p)) {
    2224         [ +  + ]:    1567596 :         if (j == level) RETURN(false);
    2225         [ +  + ]:    1546005 :         if (!next_default(C_, j + 1)) RETURN(false);
    2226                 :    1525506 :         c = DIR_START;
    2227                 :            :     }
    2228                 :    7755410 :     C_[j].c = c;
    2229         [ +  + ]:    7755410 :     if (j > 0) {
    2230                 :    1525506 :         block_to_cursor(C_, j - 1, Item(p, c).block_given_by());
    2231                 :            : #ifdef BTREE_DEBUG_FULL
    2232                 :            :         printf("Block in BrassTable:next_default");
    2233                 :            :         report_block_full(j - 1, C_[j - 1].n, C_[j - 1].p);
    2234                 :            : #endif /* BTREE_DEBUG_FULL */
    2235                 :            :     }
    2236                 :    7797500 :     RETURN(true);
    2237                 :            : }
    2238                 :            : 
    2239                 :            : void
    2240                 :         13 : BrassTable::throw_database_closed()
    2241                 :            : {
    2242                 :         13 :     throw Xapian::DatabaseError("Database has been closed");
    2243                 :            : }
    2244                 :            : 
    2245                 :            : /** Compares this key with key2.
    2246                 :            : 
    2247                 :            :    The result is true if this key precedes key2. The comparison is for byte
    2248                 :            :    sequence collating order, taking lengths into account. So if the keys are
    2249                 :            :    made up of lower case ASCII letters we get alphabetical ordering.
    2250                 :            : 
    2251                 :            :    Now remember that items are added into the B-tree in fastest time
    2252                 :            :    when they are preordered by their keys. This is therefore the piece
    2253                 :            :    of code that needs to be followed to arrange for the preordering.
    2254                 :            : 
    2255                 :            :    This is complicated by the fact that keys have two parts - a value
    2256                 :            :    and then a count.  We first compare the values, and only if they
    2257                 :            :    are equal do we compare the counts.
    2258                 :            : */
    2259                 :            : 
    2260                 :   38389196 : bool Key::operator<(Key key2) const
    2261                 :            : {
    2262                 :            :     LOGCALL(DB, bool, "Key::operator<", static_cast<const void*>(key2.p));
    2263                 :   38389196 :     int key1_len = length();
    2264                 :   38389196 :     int key2_len = key2.length();
    2265         [ +  + ]:   38389196 :     if (key1_len == key2_len) {
    2266                 :            :         // The keys are the same length, so we can compare the counts
    2267                 :            :         // in the same operation since they're stored as 2 byte
    2268                 :            :         // bigendian numbers.
    2269                 :   23344438 :         RETURN(memcmp(p + K1, key2.p + K1, key1_len + C2) < 0);
    2270                 :            :     }
    2271                 :            : 
    2272         [ +  + ]:   15044758 :     int k_smaller = (key2_len < key1_len ? key2_len : key1_len);
    2273                 :            : 
    2274                 :            :     // Compare the common part of the keys
    2275                 :   15044758 :     int diff = memcmp(p + K1, key2.p + K1, k_smaller);
    2276         [ +  + ]:   15044758 :     if (diff != 0) RETURN(diff < 0);
    2277                 :            : 
    2278                 :            :     // We dealt with the "same length" case above so we never need to check
    2279                 :            :     // the count here.
    2280                 :   38389196 :     RETURN(key1_len < key2_len);
    2281                 :            : }
    2282                 :            : 
    2283                 :    4502843 : bool Key::operator==(Key key2) const
    2284                 :            : {
    2285                 :            :     LOGCALL(DB, bool, "Key::operator==", static_cast<const void*>(key2.p));
    2286                 :    4502843 :     int key1_len = length();
    2287         [ +  + ]:    4502843 :     if (key1_len != key2.length()) RETURN(false);
    2288                 :            :     // The keys are the same length, so we can compare the counts
    2289                 :            :     // in the same operation since they're stored as 2 byte
    2290                 :            :     // bigendian numbers.
    2291                 :    4502843 :     RETURN(memcmp(p + K1, key2.p + K1, key1_len + C2) == 0);
    2292                 :            : }

Generated by: LCOV version 1.8