LCOV - code coverage report
Current view: top level - backends/chert - chert_btreebase.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 193 234 82.5 %
Date: 2011-08-21 Functions: 17 21 81.0 %
Branches: 77 118 65.3 %

           Branch data     Line data    Source code
       1                 :            : /* chert_btreebase.cc: Btree base file implementation
       2                 :            :  *
       3                 :            :  * Copyright 1999,2000,2001 BrightStation PLC
       4                 :            :  * Copyright 2002,2003,2004,2006,2008,2009,2011 Olly Betts
       5                 :            :  * Copyright 2010 Richard Boulton
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      20                 :            :  * USA
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : 
      25                 :            : #include "safeerrno.h"
      26                 :            : #ifdef __WIN32__
      27                 :            : # include "msvc_posix_wrapper.h"
      28                 :            : #endif
      29                 :            : 
      30                 :            : #include <xapian/error.h>
      31                 :            : 
      32                 :            : #include "chert_btreebase.h"
      33                 :            : #include "io_utils.h"
      34                 :            : #include "omassert.h"
      35                 :            : #include "pack.h"
      36                 :            : #include "str.h"
      37                 :            : #include "utils.h"
      38                 :            : 
      39                 :            : #include <algorithm>
      40                 :            : #include <climits>
      41                 :            : #include <cstring>
      42                 :            : 
      43                 :            : using namespace std;
      44                 :            : 
      45                 :            : /************ Base file parameters ************/
      46                 :            : 
      47                 :            : /** This is the current description of the base file format:
      48                 :            :  *
      49                 :            :  * Numbers are (unless mentioned otherwise) stored in the variable
      50                 :            :  * length format used by pack_uint() - that is 7 bits at a time in
      51                 :            :  * a byte, starting with lower-order bits, and setting the high bit
      52                 :            :  * on all bytes before the last one.
      53                 :            :  *
      54                 :            :  * The format consists of a sequence of numbers in this order:
      55                 :            :  *
      56                 :            :  * REVISION
      57                 :            :  * FORMAT       will be = CURR_FORMAT for the current format.  If this value
      58                 :            :  *              higher then it is a different format which we
      59                 :            :  *              doesn't yet understand, so we bomb out.  If it's lower,
      60                 :            :  *              then it depends if we have backwards-compatibility code
      61                 :            :  *              implemented (we don't for format versions < 5).
      62                 :            :  * BLOCK_SIZE
      63                 :            :  * ROOT
      64                 :            :  * LEVEL
      65                 :            :  * BIT_MAP_SIZE
      66                 :            :  * ITEM_COUNT
      67                 :            :  * LAST_BLOCK
      68                 :            :  * HAVE_FAKEROOT
      69                 :            :  * SEQUENTIAL
      70                 :            :  * REVISION2    A second copy of the revision number, for consistency checks.
      71                 :            :  * BITMAP       The bitmap.  This will be BIT_MAP_SIZE raw bytes.
      72                 :            :  * REVISION3    A third copy of the revision number, for consistency checks.
      73                 :            :  */
      74                 :            : #define CURR_FORMAT 5U
      75                 :            : 
      76                 :      33339 : ChertTable_base::ChertTable_base()
      77                 :            :         : revision(0),
      78                 :            :           block_size(0),
      79                 :            :           root(0),
      80                 :            :           level(0),
      81                 :            :           bit_map_size(0),
      82                 :            :           item_count(0),
      83                 :            :           last_block(0),
      84                 :            :           have_fakeroot(false),
      85                 :            :           sequential(false),
      86                 :            :           bit_map_low(0),
      87                 :            :           bit_map0(0),
      88                 :      33339 :           bit_map(0)
      89                 :            : {
      90                 :      33339 : }
      91                 :            : 
      92                 :          0 : ChertTable_base::ChertTable_base(const ChertTable_base &other)
      93                 :            :         : revision(other.revision),
      94                 :            :           block_size(other.block_size),
      95                 :            :           root(other.root),
      96                 :            :           level(other.level),
      97                 :            :           bit_map_size(other.bit_map_size),
      98                 :            :           item_count(other.item_count),
      99                 :            :           last_block(other.last_block),
     100                 :            :           have_fakeroot(other.have_fakeroot),
     101                 :            :           sequential(other.sequential),
     102                 :            :           bit_map_low(other.bit_map_low),
     103                 :            :           bit_map0(0),
     104                 :          0 :           bit_map(0)
     105                 :            : {
     106                 :            :     try {
     107                 :          0 :         bit_map0 = new byte[bit_map_size];
     108                 :          0 :         bit_map = new byte[bit_map_size];
     109                 :            : 
     110                 :          0 :         memcpy(bit_map0, other.bit_map0, bit_map_size);
     111                 :          0 :         memcpy(bit_map, other.bit_map, bit_map_size);
     112                 :          0 :     } catch (...) {
     113 [ #  # ][ #  # ]:          0 :         delete [] bit_map0;
     114 [ #  # ][ #  # ]:          0 :         delete [] bit_map;
     115                 :            :     }
     116                 :          0 : }
     117                 :            : 
     118                 :            : void
     119                 :       9113 : ChertTable_base::swap(ChertTable_base &other)
     120                 :            : {
     121                 :       9113 :     std::swap(revision, other.revision);
     122                 :       9113 :     std::swap(block_size, other.block_size);
     123                 :       9113 :     std::swap(root, other.root);
     124                 :       9113 :     std::swap(level, other.level);
     125                 :       9113 :     std::swap(bit_map_size, other.bit_map_size);
     126                 :       9113 :     std::swap(item_count, other.item_count);
     127                 :       9113 :     std::swap(last_block, other.last_block);
     128                 :       9113 :     std::swap(have_fakeroot, other.have_fakeroot);
     129                 :       9113 :     std::swap(sequential, other.sequential);
     130                 :       9113 :     std::swap(bit_map_low, other.bit_map_low);
     131                 :       9113 :     std::swap(bit_map0, other.bit_map0);
     132                 :       9113 :     std::swap(bit_map, other.bit_map);
     133                 :       9113 : }
     134                 :            : 
     135                 :      33339 : ChertTable_base::~ChertTable_base()
     136                 :            : {
     137 [ +  + ][ #  # ]:      33339 :     delete [] bit_map;
     138                 :      33339 :     bit_map = 0;
     139 [ +  + ][ #  # ]:      33339 :     delete [] bit_map0;
     140                 :      33339 :     bit_map0 = 0;
     141                 :      33339 : }
     142                 :            : 
     143                 :            : /** Do most of the error handling from unpack_uint() */
     144                 :            : static bool
     145                 :     161740 : do_unpack_uint(const char **start, const char *end,
     146                 :            :                uint4 *dest, string &err_msg, 
     147                 :            :                const string &basename,
     148                 :            :                const char *varname)
     149                 :            : {
     150                 :     161740 :     bool result = unpack_uint(start, end, dest);
     151         [ -  + ]:     161740 :     if (rare(!result)) {
     152                 :          0 :         err_msg += "Unable to read ";
     153                 :          0 :         err_msg += varname;
     154                 :          0 :         err_msg += " from ";
     155                 :          0 :         err_msg += basename;
     156                 :          0 :         err_msg += '\n';
     157                 :            :     }
     158                 :     161740 :     return result;
     159                 :            : }
     160                 :            : 
     161                 :            : static bool
     162                 :      16174 : do_unpack_uint(const char **start, const char *end,
     163                 :            :                chert_tablesize_t *dest, string &err_msg, 
     164                 :            :                const string &basename,
     165                 :            :                const char *varname)
     166                 :            : {
     167                 :      16174 :     bool result = unpack_uint(start, end, dest);
     168         [ -  + ]:      16174 :     if (rare(!result)) {
     169                 :          0 :         err_msg += "Unable to read ";
     170                 :          0 :         err_msg += varname;
     171                 :          0 :         err_msg += " from ";
     172                 :          0 :         err_msg += basename;
     173                 :          0 :         err_msg += '\n';
     174                 :            :     }
     175                 :      16174 :     return result;
     176                 :            : }
     177                 :            : 
     178                 :            : #define DO_UNPACK_UINT_ERRCHECK(start, end, var) \
     179                 :            : do { \
     180                 :            :     if (!do_unpack_uint(start, end, &var, err_msg, basename, #var)) { \
     181                 :            :         return false; \
     182                 :            :     } \
     183                 :            : } while(0)
     184                 :            : 
     185                 :            : /* How much of the base file to read at the first go (in bytes).
     186                 :            :  * This must be big enough that the base file without bitmap
     187                 :            :  * will fit in to this size with no problem.  Other than that
     188                 :            :  * it's fairly arbitrary, but shouldn't be big enough to cause
     189                 :            :  * serious memory problems!
     190                 :            :  */
     191                 :            : #define REASONABLE_BASE_SIZE 1024
     192                 :            : 
     193                 :            : bool
     194                 :      18695 : ChertTable_base::read(const string & name, char ch, bool read_bitmap,
     195                 :            :                       string &err_msg)
     196                 :            : {
     197                 :      18695 :     string basename = name + "base" + ch;
     198                 :            : #ifdef __WIN32__
     199                 :            :     int h = msvc_posix_open(basename.c_str(), O_RDONLY | O_BINARY);
     200                 :            : #else
     201                 :      18695 :     int h = open(basename.c_str(), O_RDONLY | O_BINARY);
     202                 :            : #endif
     203                 :            : 
     204         [ +  + ]:      18695 :     if (h == -1) {
     205                 :       2521 :         err_msg += "Couldn't open " + basename + ": " + strerror(errno) + "\n";
     206                 :       2521 :         return false;
     207                 :            :     }
     208                 :      16174 :     fdcloser closefd(h);
     209                 :            : 
     210                 :            :     char buf[REASONABLE_BASE_SIZE];
     211                 :            : 
     212                 :      16174 :     const char *start = buf;
     213                 :      16174 :     const char *end = buf + io_read(h, buf, REASONABLE_BASE_SIZE, 0);
     214                 :            : 
     215         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, revision);
     216                 :            :     uint4 format;
     217         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, format);
     218         [ -  + ]:      16174 :     if (format != CURR_FORMAT) {
     219                 :            :         err_msg += "Bad base file format " + str(format) + " in " +
     220                 :          0 :                     basename + "\n";
     221                 :          0 :         return false;
     222                 :            :     }
     223         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, block_size);
     224         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, root);
     225         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, level);
     226         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, bit_map_size);
     227         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, item_count);
     228         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, last_block);
     229                 :            :     uint4 have_fakeroot_;
     230         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, have_fakeroot_);
     231                 :      16174 :     have_fakeroot = have_fakeroot_;
     232                 :            : 
     233                 :            :     uint4 sequential_;
     234         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, sequential_);
     235                 :      16174 :     sequential = sequential_;
     236                 :            : 
     237 [ +  + ][ -  + ]:      16174 :     if (have_fakeroot && !sequential) {
     238                 :          0 :         sequential = true; // FIXME : work out why we need this...
     239                 :            :         /*
     240                 :            :         err_msg += "Corrupt base file, `" + basename + "':\n"
     241                 :            :                 "sequential must be set whenever have_fakeroot is set.\n" +
     242                 :            :                 "sequential=" + (sequential?"true":"false") +
     243                 :            :                 ", have_fakeroot=" + (have_fakeroot?"true":"false") + "\n";
     244                 :            :         return false;
     245                 :            :         */
     246                 :            :     }
     247                 :            : 
     248                 :            :     uint4 revision2;
     249         [ -  + ]:      16174 :     DO_UNPACK_UINT_ERRCHECK(&start, end, revision2);
     250         [ -  + ]:      16174 :     if (revision != revision2) {
     251                 :            :         err_msg += "Revision number mismatch in " +
     252                 :            :                 basename + ": " +
     253                 :          0 :                 str(revision) + " vs " + str(revision2) + "\n";
     254                 :          0 :         return false;
     255                 :            :     }
     256                 :            : 
     257                 :            :     /* It's ok to delete a zero pointer */
     258         [ +  + ]:      16174 :     delete [] bit_map0;
     259                 :      16174 :     bit_map0 = 0;
     260         [ +  + ]:      16174 :     delete [] bit_map;
     261                 :      16174 :     bit_map = 0;
     262                 :            : 
     263         [ +  + ]:      16174 :     if (!read_bitmap)
     264                 :      12978 :         return true;
     265                 :            : 
     266                 :       3196 :     bit_map0 = new byte[bit_map_size];
     267                 :       3196 :     bit_map = new byte[bit_map_size];
     268                 :            : 
     269                 :       3196 :     size_t n = end - start;
     270         [ -  + ]:       3196 :     if (n < bit_map_size) {
     271                 :          0 :         memcpy(bit_map0, start, n);
     272                 :            :         (void)io_read(h, reinterpret_cast<char *>(bit_map0) + n,
     273                 :          0 :                       bit_map_size - n, bit_map_size - n);
     274                 :          0 :         n = 0;
     275                 :            :     } else {
     276                 :       3196 :         memcpy(bit_map0, start, bit_map_size);
     277                 :       3196 :         n -= bit_map_size;
     278         [ +  - ]:       3196 :         if (n) memmove(buf, start + bit_map_size, n);
     279                 :            :     }
     280                 :       3196 :     memcpy(bit_map, bit_map0, bit_map_size);
     281                 :            : 
     282                 :       3196 :     start = buf;
     283                 :       3196 :     end = buf + n;
     284                 :       3196 :     end += io_read(h, buf + n, REASONABLE_BASE_SIZE - n, 0);
     285                 :            : 
     286                 :            :     uint4 revision3;
     287         [ -  + ]:       3196 :     if (!unpack_uint(&start, end, &revision3)) {
     288                 :            :         err_msg += "Couldn't read revision3 from base file " +
     289                 :          0 :         basename + "\n";
     290                 :          0 :         return false;
     291                 :            :     }
     292                 :            : 
     293         [ -  + ]:       3196 :     if (revision != revision3) {
     294                 :            :         err_msg += "Revision number mismatch in " +
     295                 :            :                 basename + ": " +
     296                 :          0 :                 str(revision) + " vs " + str(revision3) + "\n";
     297                 :          0 :         return false;
     298                 :            :     }
     299                 :            : 
     300         [ -  + ]:       3196 :     if (start != end) {
     301                 :          0 :         err_msg += "Junk at end of base file " + basename + "\n";
     302                 :          0 :         return false;
     303                 :            :     }
     304                 :            : 
     305                 :      18695 :     return true;
     306                 :            : }
     307                 :            : 
     308                 :            : void
     309                 :       3016 : ChertTable_base::write_to_file(const string &filename,
     310                 :            :                                char base_letter,
     311                 :            :                                const string &tablename,
     312                 :            :                                int changes_fd,
     313                 :            :                                const string * changes_tail)
     314                 :            : {
     315                 :       3016 :     calculate_last_block();
     316                 :            : 
     317                 :       3016 :     string buf;
     318                 :       3016 :     pack_uint(buf, revision);
     319                 :       3016 :     pack_uint(buf, CURR_FORMAT);
     320                 :       3016 :     pack_uint(buf, block_size);
     321                 :       3016 :     pack_uint(buf, static_cast<uint4>(root));
     322                 :       3016 :     pack_uint(buf, static_cast<uint4>(level));
     323                 :       3016 :     pack_uint(buf, static_cast<uint4>(bit_map_size));
     324                 :       3016 :     pack_uint(buf, item_count);
     325                 :       3016 :     pack_uint(buf, static_cast<uint4>(last_block));
     326                 :       3016 :     pack_uint(buf, have_fakeroot);
     327                 :       3016 :     pack_uint(buf, sequential);
     328                 :       3016 :     pack_uint(buf, revision);  // REVISION2
     329         [ +  + ]:       3016 :     if (bit_map_size > 0) {
     330                 :       1792 :         buf.append(reinterpret_cast<const char *>(bit_map), bit_map_size);
     331                 :            :     }
     332                 :       3016 :     pack_uint(buf, revision);  // REVISION3
     333                 :            : 
     334                 :            : #ifdef __WIN32__
     335                 :            :     int h = msvc_posix_open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
     336                 :            : #else
     337                 :       3016 :     int h = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
     338                 :            : #endif
     339         [ -  + ]:       3016 :     if (h < 0) {
     340                 :            :         string message = string("Couldn't open base ")
     341                 :          0 :                 + filename + " to write: " + strerror(errno);
     342                 :          0 :         throw Xapian::DatabaseOpeningError(message);
     343                 :            :     }
     344                 :       3016 :     fdcloser closefd(h);
     345                 :            : 
     346         [ +  + ]:       3016 :     if (changes_fd >= 0) {
     347                 :         86 :         string changes_buf;
     348                 :         86 :         pack_uint(changes_buf, 1u); // Indicate the item is a base file.
     349                 :         86 :         pack_string(changes_buf, tablename);
     350                 :         86 :         changes_buf += base_letter; // The base file letter.
     351                 :         86 :         pack_uint(changes_buf, buf.size());
     352                 :         86 :         io_write(changes_fd, changes_buf.data(), changes_buf.size());
     353                 :         86 :         io_write(changes_fd, buf.data(), buf.size());
     354         [ +  + ]:         86 :         if (changes_tail != NULL) {
     355                 :         23 :             io_write(changes_fd, changes_tail->data(), changes_tail->size());
     356                 :            :             // changes_tail is only specified for the final table, so sync.
     357                 :         23 :             io_sync(changes_fd);
     358                 :         86 :         }
     359                 :            :     }
     360                 :            : 
     361                 :       3016 :     io_write(h, buf.data(), buf.size());
     362                 :       3016 :     io_sync(h);
     363                 :       3016 : }
     364                 :            : 
     365                 :            : /*
     366                 :            :    block_free_at_start(B, n) is true iff (if and only if) block n was free at
     367                 :            :    the start of the transaction on the B-tree.
     368                 :            : */
     369                 :            : 
     370                 :            : bool
     371                 :     303981 : ChertTable_base::block_free_at_start(uint4 n) const
     372                 :            : {
     373                 :     303981 :     size_t i = n / CHAR_BIT;
     374                 :     303981 :     int bit = 0x1 << n % CHAR_BIT;
     375                 :     303981 :     return (bit_map0[i] & bit) == 0;
     376                 :            : }
     377                 :            : 
     378                 :            : /* free_block(B, n) causes block n to be marked free in the bit map.
     379                 :            :    B->bit_map_low is the lowest byte in the bit map known to have a free bit
     380                 :            :    set. Searching starts from there when looking for a free block.
     381                 :            : */
     382                 :            : 
     383                 :            : void
     384                 :       1927 : ChertTable_base::free_block(uint4 n)
     385                 :            : {
     386                 :       1927 :     uint4 i = n / CHAR_BIT;
     387                 :       1927 :     int bit = 0x1 << n % CHAR_BIT;
     388                 :       1927 :     bit_map[i] &= ~ bit;
     389                 :            : 
     390         [ +  + ]:       1927 :     if (bit_map_low > i)
     391         [ +  + ]:        494 :         if ((bit_map0[i] & bit) == 0) /* free at start */
     392                 :        106 :             bit_map_low = i;
     393                 :       1927 : }
     394                 :            : 
     395                 :            : /* extend(B) increases the size of the two bit maps in an obvious way.
     396                 :            :    The bitmap file grows and shrinks as the DB file grows and shrinks in
     397                 :            :    internal usage. But the DB file itself does not reduce in size, no matter
     398                 :            :    how many blocks are freed.
     399                 :            : */
     400                 :            : 
     401                 :            : #define BIT_MAP_INC 1000
     402                 :            :     /* increase the bit map by this number of bytes if it overflows */
     403                 :            : 
     404                 :            : void
     405                 :       2432 : ChertTable_base::extend_bit_map()
     406                 :            : {
     407                 :       2432 :     int n = bit_map_size + BIT_MAP_INC;
     408                 :       2432 :     byte *new_bit_map0 = 0;
     409                 :       2432 :     byte *new_bit_map = 0;
     410                 :            : 
     411                 :            :     try {
     412                 :       2432 :         new_bit_map0 = new byte[n];
     413                 :       2432 :         new_bit_map = new byte[n];
     414                 :            : 
     415                 :       2432 :         memcpy(new_bit_map0, bit_map0, bit_map_size);
     416                 :       2432 :         memset(new_bit_map0 + bit_map_size, 0, n - bit_map_size);
     417                 :            :         
     418                 :       2432 :         memcpy(new_bit_map, bit_map, bit_map_size);
     419                 :       2432 :         memset(new_bit_map + bit_map_size, 0, n - bit_map_size);
     420                 :          0 :     } catch (...) {
     421         [ #  # ]:          0 :         delete [] new_bit_map0;
     422         [ #  # ]:          0 :         delete [] new_bit_map;
     423                 :          0 :         throw;
     424                 :            :     }
     425         [ +  - ]:       2432 :     delete [] bit_map0;
     426                 :       2432 :     bit_map0 = new_bit_map0;
     427         [ +  - ]:       2432 :     delete [] bit_map;
     428                 :       2432 :     bit_map = new_bit_map;
     429                 :       2432 :     bit_map_size = n;
     430                 :       2432 : }
     431                 :            : 
     432                 :            : /* next_free_block(B) returns the number of the next available free block in
     433                 :            :    the bitmap, marking it as 'in use' before returning. More precisely, we get
     434                 :            :    a block that is both free now (in bit_map) and was free at the beginning of
     435                 :            :    the transaction on the B-tree (in bit_map0).
     436                 :            : 
     437                 :            :    Starting at bit_map_low we go up byte at a time until we find a byte with a
     438                 :            :    free (zero) bit, and then go up that byte bit at a time. If the bit map has
     439                 :            :    no free bits it is extended so that it will have.
     440                 :            : */
     441                 :            : 
     442                 :            : uint4
     443                 :      20938 : ChertTable_base::next_free_block()
     444                 :            : {
     445                 :            :     uint4 i;
     446                 :            :     int x;
     447                 :      23612 :     for (i = bit_map_low;; i++) {
     448         [ +  + ]:      23612 :         if (i >= bit_map_size) {
     449                 :       2432 :             extend_bit_map();
     450                 :            :         }
     451                 :      23612 :         x = bit_map0[i] | bit_map[i];
     452         [ +  + ]:      23612 :         if (x != UCHAR_MAX) break;
     453                 :            :     }
     454                 :      20938 :     uint4 n = i * CHAR_BIT;
     455                 :      20938 :     int d = 0x1;
     456         [ +  + ]:      83728 :     while ((x & d) != 0) { d <<= 1; n++; }
     457                 :      20938 :     bit_map[i] |= d;   /* set as 'in use' */
     458                 :      20938 :     bit_map_low = i;
     459         [ +  + ]:      20938 :     if (n > last_block) {
     460                 :      17638 :         last_block = n;
     461                 :            :     }
     462                 :      20938 :     return n;
     463                 :            : }
     464                 :            : 
     465                 :            : bool
     466                 :        161 : ChertTable_base::find_changed_block(uint4 * n)
     467                 :            : {
     468                 :            :     // Search for a block which was free at the start of the transaction, but
     469                 :            :     // isn't now.
     470         [ +  + ]:        246 :     while ((*n) <= last_block) {
     471                 :        160 :         size_t offset = (*n) / CHAR_BIT;
     472                 :        160 :         int bit = 0x1 << (*n) % CHAR_BIT;
     473                 :            : 
     474 [ +  + ][ +  + ]:        160 :         if (((bit_map0[offset] & bit) == 0) && ((bit_map[offset] & bit) != 0)) {
     475                 :         75 :             return true;
     476                 :            :         }
     477                 :         85 :         ++(*n);
     478                 :            :     }
     479                 :            :     
     480                 :        161 :     return false;
     481                 :            : }
     482                 :            : 
     483                 :            : bool
     484                 :          3 : ChertTable_base::block_free_now(uint4 n)
     485                 :            : {
     486                 :          3 :     uint4 i = n / CHAR_BIT;
     487                 :          3 :     int bit = 0x1 << n % CHAR_BIT;
     488                 :          3 :     return (bit_map[i] & bit) == 0;
     489                 :            : }
     490                 :            : 
     491                 :            : void
     492                 :       3102 : ChertTable_base::calculate_last_block()
     493                 :            : {
     494         [ +  + ]:       3102 :     if (bit_map_size == 0) {
     495                 :       1224 :         last_block = 0;
     496                 :       1224 :         return;
     497                 :            :     }
     498                 :       1878 :     int i = bit_map_size - 1;
     499 [ +  + ][ +  + ]:    1161720 :     while (bit_map[i] == 0 && i > 0) {
                 [ +  + ]
     500                 :    1159842 :         i--;
     501                 :            :     }
     502                 :       1878 :     bit_map_size = i + 1;
     503                 :            : 
     504                 :       1878 :     int x = bit_map[i];
     505                 :            : 
     506                 :            :     /* Check for when there are no blocks */
     507         [ +  + ]:       1878 :     if (x == 0) {
     508                 :        135 :         last_block = 0;
     509                 :        135 :         return;
     510                 :            :     }
     511                 :       1743 :     uint4 n = (i + 1) * CHAR_BIT - 1;
     512                 :       1743 :     int d = 0x1 << (CHAR_BIT - 1);
     513         [ +  + ]:      12344 :     while ((x & d) == 0) { d >>= 1; n--; }
     514                 :            : 
     515                 :       3102 :     last_block = n;
     516                 :            : }
     517                 :            : 
     518                 :            : bool
     519                 :          3 : ChertTable_base::is_empty() const
     520                 :            : {
     521         [ +  + ]:          9 :     for (uint4 i = 0; i < bit_map_size; i++) {
     522         [ -  + ]:          6 :         if (bit_map[i] != 0) {
     523                 :          0 :             return false;
     524                 :            :         }
     525                 :            :     }
     526                 :          3 :     return true;
     527                 :            : }
     528                 :            : 
     529                 :            : void
     530                 :        135 : ChertTable_base::clear_bit_map()
     531                 :            : {
     532                 :        135 :     memset(bit_map, 0, bit_map_size);
     533                 :        135 : }
     534                 :            : 
     535                 :            : // We've commited, so "bitmap at start" needs to be reset to the current bitmap.
     536                 :            : void
     537                 :       1792 : ChertTable_base::commit()
     538                 :            : {
     539                 :       1792 :     memcpy(bit_map0, bit_map, bit_map_size);
     540                 :       1792 :     bit_map_low = 0;
     541                 :       1792 : }

Generated by: LCOV version 1.8