LCOV - code coverage report
Current view: top level - backends/flint - flint_btreebase.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 189 221 85.5 %
Date: 2011-08-21 Functions: 16 20 80.0 %
Branches: 75 116 64.7 %

           Branch data     Line data    Source code
       1                 :            : /* flint_btreebase.cc: Btree base file implementation
       2                 :            :  *
       3                 :            :  * Copyright 1999,2000,2001 BrightStation PLC
       4                 :            :  * Copyright 2002,2003,2004,2006,2008,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 "flint_btreebase.h"
      31                 :            : #include "flint_utils.h"
      32                 :            : #include "io_utils.h"
      33                 :            : #include "str.h"
      34                 :            : #include "utils.h"
      35                 :            : #include <xapian/error.h>
      36                 :            : #include "omassert.h"
      37                 :            : 
      38                 :            : #include <climits>
      39                 :            : 
      40                 :            : #include <algorithm>
      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 F_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                 :      37830 : FlintTable_base::FlintTable_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                 :      37830 :           bit_map(0)
      89                 :            : {
      90                 :      37830 : }
      91                 :            : 
      92                 :          0 : FlintTable_base::FlintTable_base(const FlintTable_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                 :      10447 : FlintTable_base::swap(FlintTable_base &other)
     120                 :            : {
     121                 :      10447 :     std::swap(revision, other.revision);
     122                 :      10447 :     std::swap(block_size, other.block_size);
     123                 :      10447 :     std::swap(root, other.root);
     124                 :      10447 :     std::swap(level, other.level);
     125                 :      10447 :     std::swap(bit_map_size, other.bit_map_size);
     126                 :      10447 :     std::swap(item_count, other.item_count);
     127                 :      10447 :     std::swap(last_block, other.last_block);
     128                 :      10447 :     std::swap(have_fakeroot, other.have_fakeroot);
     129                 :      10447 :     std::swap(sequential, other.sequential);
     130                 :      10447 :     std::swap(bit_map_low, other.bit_map_low);
     131                 :      10447 :     std::swap(bit_map0, other.bit_map0);
     132                 :      10447 :     std::swap(bit_map, other.bit_map);
     133                 :      10447 : }
     134                 :            : 
     135                 :      37830 : FlintTable_base::~FlintTable_base()
     136                 :            : {
     137 [ +  + ][ #  # ]:      37830 :     delete [] bit_map;
     138                 :      37830 :     bit_map = 0;
     139 [ +  + ][ #  # ]:      37830 :     delete [] bit_map0;
     140                 :      37830 :     bit_map0 = 0;
     141                 :      37830 : }
     142                 :            : 
     143                 :            : bool
     144                 :     207185 : FlintTable_base::do_unpack_uint(const char **start, const char *end,
     145                 :            :                            uint4 *dest, string &err_msg, 
     146                 :            :                            const string &basename,
     147                 :            :                            const char *varname)
     148                 :            : {
     149                 :     207185 :     bool result = F_unpack_uint(start, end, dest);
     150         [ -  + ]:     207185 :     if (!result) {
     151                 :            :         err_msg += "Unable to read " + string(varname) + " from " +
     152                 :          0 :                     basename + "\n";
     153                 :            :     }
     154                 :     207185 :     return result;
     155                 :            : }
     156                 :            : 
     157                 :            : #define DO_UNPACK_UINT_ERRCHECK(start, end, var) \
     158                 :            : do { \
     159                 :            :     if (!do_unpack_uint(start, end, &var, err_msg, basename, #var)) { \
     160                 :            :         return false; \
     161                 :            :     } \
     162                 :            : } while(0)
     163                 :            : 
     164                 :            : /* How much of the base file to read at the first go (in bytes).
     165                 :            :  * This must be big enough that the base file without bitmap
     166                 :            :  * will fit in to this size with no problem.  Other than that
     167                 :            :  * it's fairly arbitrary, but shouldn't be big enough to cause
     168                 :            :  * serious memory problems!
     169                 :            :  */
     170                 :            : #define REASONABLE_BASE_SIZE 1024
     171                 :            : 
     172                 :            : bool
     173                 :      21503 : FlintTable_base::read(const string & name, char ch, bool read_bitmap,
     174                 :            :                       string &err_msg)
     175                 :            : {
     176                 :      21503 :     string basename = name + "base" + ch;
     177                 :            : #ifdef __WIN32__
     178                 :            :     int h = msvc_posix_open(basename.c_str(), O_RDONLY | O_BINARY);
     179                 :            : #else
     180                 :      21503 :     int h = open(basename.c_str(), O_RDONLY | O_BINARY);
     181                 :            : #endif
     182                 :            : 
     183         [ +  + ]:      21503 :     if (h == -1) {
     184                 :       2668 :         err_msg += "Couldn't open " + basename + ": " + strerror(errno) + "\n";
     185                 :       2668 :         return false;
     186                 :            :     }
     187                 :      18835 :     fdcloser closefd(h);
     188                 :            : 
     189                 :            :     char buf[REASONABLE_BASE_SIZE];
     190                 :            : 
     191                 :      18835 :     const char *start = buf;
     192                 :      18835 :     const char *end = buf + io_read(h, buf, REASONABLE_BASE_SIZE, 0);
     193                 :            : 
     194         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, revision);
     195                 :            :     uint4 format;
     196         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, format);
     197         [ -  + ]:      18835 :     if (format != CURR_FORMAT) {
     198                 :            :         err_msg += "Bad base file format " + str(format) + " in " +
     199                 :          0 :                     basename + "\n";
     200                 :          0 :         return false;
     201                 :            :     }
     202         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, block_size);
     203         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, root);
     204         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, level);
     205         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, bit_map_size);
     206         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, item_count);
     207         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, last_block);
     208                 :            :     uint4 have_fakeroot_;
     209         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, have_fakeroot_);
     210                 :      18835 :     have_fakeroot = have_fakeroot_;
     211                 :            : 
     212                 :            :     uint4 sequential_;
     213         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, sequential_);
     214                 :      18835 :     sequential = sequential_;
     215                 :            : 
     216 [ +  + ][ -  + ]:      18835 :     if (have_fakeroot && !sequential) {
     217                 :          0 :         sequential = true; // FIXME : work out why we need this...
     218                 :            :         /*
     219                 :            :         err_msg += "Corrupt base file, `" + basename + "':\n"
     220                 :            :                 "sequential must be set whenever have_fakeroot is set.\n" +
     221                 :            :                 "sequential=" + (sequential?"true":"false") +
     222                 :            :                 ", have_fakeroot=" + (have_fakeroot?"true":"false") + "\n";
     223                 :            :         return false;
     224                 :            :         */
     225                 :            :     }
     226                 :            : 
     227                 :            :     uint4 revision2;
     228         [ -  + ]:      18835 :     DO_UNPACK_UINT_ERRCHECK(&start, end, revision2);
     229         [ -  + ]:      18835 :     if (revision != revision2) {
     230                 :            :         err_msg += "Revision number mismatch in " +
     231                 :            :                 basename + ": " +
     232                 :          0 :                 str(revision) + " vs " + str(revision2) + "\n";
     233                 :          0 :         return false;
     234                 :            :     }
     235                 :            : 
     236                 :            :     /* It's ok to delete a zero pointer */
     237         [ +  + ]:      18835 :     delete [] bit_map0;
     238                 :      18835 :     bit_map0 = 0;
     239         [ +  + ]:      18835 :     delete [] bit_map;
     240                 :      18835 :     bit_map = 0;
     241                 :            : 
     242         [ +  + ]:      18835 :     if (!read_bitmap)
     243                 :      15140 :         return true;
     244                 :            : 
     245                 :       3695 :     bit_map0 = new byte[bit_map_size];
     246                 :       3695 :     bit_map = new byte[bit_map_size];
     247                 :            : 
     248                 :       3695 :     size_t n = end - start;
     249         [ -  + ]:       3695 :     if (n < bit_map_size) {
     250                 :          0 :         memcpy(bit_map0, start, n);
     251                 :            :         (void)io_read(h, reinterpret_cast<char *>(bit_map0) + n,
     252                 :          0 :                       bit_map_size - n, bit_map_size - n);
     253                 :          0 :         n = 0;
     254                 :            :     } else {
     255                 :       3695 :         memcpy(bit_map0, start, bit_map_size);
     256                 :       3695 :         n -= bit_map_size;
     257         [ +  - ]:       3695 :         if (n) memmove(buf, start + bit_map_size, n);
     258                 :            :     }
     259                 :       3695 :     memcpy(bit_map, bit_map0, bit_map_size);
     260                 :            : 
     261                 :       3695 :     start = buf;
     262                 :       3695 :     end = buf + n;
     263                 :       3695 :     end += io_read(h, buf + n, REASONABLE_BASE_SIZE - n, 0);
     264                 :            : 
     265                 :            :     uint4 revision3;
     266         [ -  + ]:       3695 :     if (!F_unpack_uint(&start, end, &revision3)) {
     267                 :            :         err_msg += "Couldn't read revision3 from base file " +
     268                 :          0 :         basename + "\n";
     269                 :          0 :         return false;
     270                 :            :     }
     271                 :            : 
     272         [ -  + ]:       3695 :     if (revision != revision3) {
     273                 :            :         err_msg += "Revision number mismatch in " +
     274                 :            :                 basename + ": " +
     275                 :          0 :                 str(revision) + " vs " + str(revision3) + "\n";
     276                 :          0 :         return false;
     277                 :            :     }
     278                 :            : 
     279         [ -  + ]:       3695 :     if (start != end) {
     280                 :          0 :         err_msg += "Junk at end of base file " + basename + "\n";
     281                 :          0 :         return false;
     282                 :            :     }
     283                 :            : 
     284                 :      21503 :     return true;
     285                 :            : }
     286                 :            : 
     287                 :            : void
     288                 :       3526 : FlintTable_base::write_to_file(const string &filename,
     289                 :            :                                char base_letter,
     290                 :            :                                const string &tablename,
     291                 :            :                                int changes_fd,
     292                 :            :                                const string * changes_tail)
     293                 :            : {
     294                 :       3526 :     calculate_last_block();
     295                 :            : 
     296                 :       3526 :     string buf;
     297                 :       3526 :     buf += F_pack_uint(revision);
     298                 :       3526 :     buf += F_pack_uint(CURR_FORMAT);
     299                 :       3526 :     buf += F_pack_uint(block_size);
     300                 :       3526 :     buf += F_pack_uint(static_cast<uint4>(root));
     301                 :       3526 :     buf += F_pack_uint(static_cast<uint4>(level));
     302                 :       3526 :     buf += F_pack_uint(static_cast<uint4>(bit_map_size));
     303                 :       3526 :     buf += F_pack_uint(static_cast<uint4>(item_count));
     304                 :       3526 :     buf += F_pack_uint(static_cast<uint4>(last_block));
     305                 :       3526 :     buf += F_pack_uint(have_fakeroot);
     306                 :       3526 :     buf += F_pack_uint(sequential);
     307                 :       3526 :     buf += F_pack_uint(revision);  // REVISION2
     308         [ +  + ]:       3526 :     if (bit_map_size > 0) {
     309                 :       2133 :         buf.append(reinterpret_cast<const char *>(bit_map), bit_map_size);
     310                 :            :     }
     311                 :       3526 :     buf += F_pack_uint(revision);  // REVISION3
     312                 :            : 
     313                 :            : #ifdef __WIN32__
     314                 :            :     int h = msvc_posix_open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
     315                 :            : #else
     316                 :       3526 :     int h = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
     317                 :            : #endif
     318         [ -  + ]:       3526 :     if (h < 0) {
     319                 :            :         string message = string("Couldn't open base ")
     320                 :          0 :                 + filename + " to write: " + strerror(errno);
     321                 :          0 :         throw Xapian::DatabaseOpeningError(message);
     322                 :            :     }
     323                 :       3526 :     fdcloser closefd(h);
     324                 :            : 
     325         [ +  + ]:       3526 :     if (changes_fd >= 0) {
     326                 :         50 :         string changes_buf;
     327                 :         50 :         changes_buf += F_pack_uint(1u); // Indicate the item is a base file.
     328                 :         50 :         changes_buf += F_pack_string(tablename);
     329                 :         50 :         changes_buf += base_letter; // The base file letter.
     330                 :         50 :         changes_buf += F_pack_uint(buf.size());
     331                 :         50 :         io_write(changes_fd, changes_buf.data(), changes_buf.size());
     332                 :         50 :         io_write(changes_fd, buf.data(), buf.size());
     333         [ +  + ]:         50 :         if (changes_tail != NULL) {
     334                 :         10 :             io_write(changes_fd, changes_tail->data(), changes_tail->size());
     335                 :            :             // changes_tail is only specified for the final table, so sync.
     336                 :         10 :             io_sync(changes_fd);
     337                 :         50 :         }
     338                 :            :     }
     339                 :            : 
     340                 :       3526 :     io_write(h, buf.data(), buf.size());
     341                 :       3526 :     io_sync(h);
     342                 :       3526 : }
     343                 :            : 
     344                 :            : /*
     345                 :            :    block_free_at_start(B, n) is true iff (if and only if) block n was free at
     346                 :            :    the start of the transaction on the B-tree.
     347                 :            : */
     348                 :            : 
     349                 :            : bool
     350                 :      55333 : FlintTable_base::block_free_at_start(uint4 n) const
     351                 :            : {
     352                 :      55333 :     size_t i = n / CHAR_BIT;
     353                 :      55333 :     int bit = 0x1 << n % CHAR_BIT;
     354                 :      55333 :     return (bit_map0[i] & bit) == 0;
     355                 :            : }
     356                 :            : 
     357                 :            : /* free_block(B, n) causes block n to be marked free in the bit map.
     358                 :            :    B->bit_map_low is the lowest byte in the bit map known to have a free bit
     359                 :            :    set. Searching starts from there when looking for a free block.
     360                 :            : */
     361                 :            : 
     362                 :            : void
     363                 :       2136 : FlintTable_base::free_block(uint4 n)
     364                 :            : {
     365                 :       2136 :     uint4 i = n / CHAR_BIT;
     366                 :       2136 :     int bit = 0x1 << n % CHAR_BIT;
     367                 :       2136 :     bit_map[i] &= ~ bit;
     368                 :            : 
     369         [ +  + ]:       2136 :     if (bit_map_low > i)
     370         [ +  + ]:        450 :         if ((bit_map0[i] & bit) == 0) /* free at start */
     371                 :        129 :             bit_map_low = i;
     372                 :       2136 : }
     373                 :            : 
     374                 :            : /* extend(B) increases the size of the two bit maps in an obvious way.
     375                 :            :    The bitmap file grows and shrinks as the DB file grows and shrinks in
     376                 :            :    internal usage. But the DB file itself does not reduce in size, no matter
     377                 :            :    how many blocks are freed.
     378                 :            : */
     379                 :            : 
     380                 :            : #define BIT_MAP_INC 1000
     381                 :            :     /* increase the bit map by this number of bytes if it overflows */
     382                 :            : 
     383                 :            : void
     384                 :       2731 : FlintTable_base::extend_bit_map()
     385                 :            : {
     386                 :       2731 :     int n = bit_map_size + BIT_MAP_INC;
     387                 :       2731 :     byte *new_bit_map0 = 0;
     388                 :       2731 :     byte *new_bit_map = 0;
     389                 :            : 
     390                 :            :     try {
     391                 :       2731 :         new_bit_map0 = new byte[n];
     392                 :       2731 :         new_bit_map = new byte[n];
     393                 :            : 
     394                 :       2731 :         memcpy(new_bit_map0, bit_map0, bit_map_size);
     395                 :       2731 :         memset(new_bit_map0 + bit_map_size, 0, n - bit_map_size);
     396                 :            :         
     397                 :       2731 :         memcpy(new_bit_map, bit_map, bit_map_size);
     398                 :       2731 :         memset(new_bit_map + bit_map_size, 0, n - bit_map_size);
     399                 :          0 :     } catch (...) {
     400         [ #  # ]:          0 :         delete [] new_bit_map0;
     401         [ #  # ]:          0 :         delete [] new_bit_map;
     402                 :          0 :         throw;
     403                 :            :     }
     404         [ +  - ]:       2731 :     delete [] bit_map0;
     405                 :       2731 :     bit_map0 = new_bit_map0;
     406         [ +  - ]:       2731 :     delete [] bit_map;
     407                 :       2731 :     bit_map = new_bit_map;
     408                 :       2731 :     bit_map_size = n;
     409                 :       2731 : }
     410                 :            : 
     411                 :            : /* next_free_block(B) returns the number of the next available free block in
     412                 :            :    the bitmap, marking it as 'in use' before returning. More precisely, we get
     413                 :            :    a block that is both free now (in bit_map) and was free at the beginning of
     414                 :            :    the transaction on the B-tree (in bit_map0).
     415                 :            : 
     416                 :            :    Starting at bit_map_low we go up byte at a time until we find a byte with a
     417                 :            :    free (zero) bit, and then go up that byte bit at a time. If the bit map has
     418                 :            :    no free bits it is extended so that it will have.
     419                 :            : */
     420                 :            : 
     421                 :            : uint4
     422                 :      17120 : FlintTable_base::next_free_block()
     423                 :            : {
     424                 :            :     uint4 i;
     425                 :            :     int x;
     426                 :      19398 :     for (i = bit_map_low;; i++) {
     427         [ +  + ]:      19398 :         if (i >= bit_map_size) {
     428                 :       2731 :             extend_bit_map();
     429                 :            :         }
     430                 :      19398 :         x = bit_map0[i] | bit_map[i];
     431         [ +  + ]:      19398 :         if (x != UCHAR_MAX) break;
     432                 :            :     }
     433                 :      17120 :     uint4 n = i * CHAR_BIT;
     434                 :      17120 :     int d = 0x1;
     435         [ +  + ]:      64856 :     while ((x & d) != 0) { d <<= 1; n++; }
     436                 :      17120 :     bit_map[i] |= d;   /* set as 'in use' */
     437                 :      17120 :     bit_map_low = i;
     438         [ +  + ]:      17120 :     if (n > last_block) {
     439                 :      13488 :         last_block = n;
     440                 :            :     }
     441                 :      17120 :     return n;
     442                 :            : }
     443                 :            : 
     444                 :            : bool
     445                 :         99 : FlintTable_base::find_changed_block(uint4 * n)
     446                 :            : {
     447                 :            :     // Search for a block which was free at the start of the transaction, but
     448                 :            :     // isn't now.
     449         [ +  + ]:        124 :     while ((*n) <= last_block) {
     450                 :         74 :         size_t offset = (*n) / CHAR_BIT;
     451                 :         74 :         int bit = 0x1 << (*n) % CHAR_BIT;
     452                 :            : 
     453 [ +  + ][ +  - ]:         74 :         if (((bit_map0[offset] & bit) == 0) && ((bit_map[offset] & bit) != 0)) {
     454                 :         49 :             return true;
     455                 :            :         }
     456                 :         25 :         ++(*n);
     457                 :            :     }
     458                 :            :     
     459                 :         99 :     return false;
     460                 :            : }
     461                 :            : 
     462                 :            : bool
     463                 :          4 : FlintTable_base::block_free_now(uint4 n)
     464                 :            : {
     465                 :          4 :     uint4 i = n / CHAR_BIT;
     466                 :          4 :     int bit = 0x1 << n % CHAR_BIT;
     467                 :          4 :     return (bit_map[i] & bit) == 0;
     468                 :            : }
     469                 :            : 
     470                 :            : void
     471                 :       3576 : FlintTable_base::calculate_last_block()
     472                 :            : {
     473         [ +  + ]:       3576 :     if (bit_map_size == 0) {
     474                 :       1393 :         last_block = 0;
     475                 :       1393 :         return;
     476                 :            :     }
     477                 :       2183 :     int i = bit_map_size - 1;
     478 [ +  + ][ +  + ]:    1365367 :     while (bit_map[i] == 0 && i > 0) {
                 [ +  + ]
     479                 :    1363184 :         i--;
     480                 :            :     }
     481                 :       2183 :     bit_map_size = i + 1;
     482                 :            : 
     483                 :       2183 :     int x = bit_map[i];
     484                 :            : 
     485                 :            :     /* Check for when there are no blocks */
     486         [ +  + ]:       2183 :     if (x == 0) {
     487                 :        102 :         last_block = 0;
     488                 :        102 :         return;
     489                 :            :     }
     490                 :       2081 :     uint4 n = (i + 1) * CHAR_BIT - 1;
     491                 :       2081 :     int d = 0x1 << (CHAR_BIT - 1);
     492         [ +  + ]:      14838 :     while ((x & d) == 0) { d >>= 1; n--; }
     493                 :            : 
     494                 :       3576 :     last_block = n;
     495                 :            : }
     496                 :            : 
     497                 :            : bool
     498                 :          4 : FlintTable_base::is_empty() const
     499                 :            : {
     500         [ +  + ]:         11 :     for (uint4 i = 0; i < bit_map_size; i++) {
     501         [ -  + ]:          7 :         if (bit_map[i] != 0) {
     502                 :          0 :             return false;
     503                 :            :         }
     504                 :            :     }
     505                 :          4 :     return true;
     506                 :            : }
     507                 :            : 
     508                 :            : void
     509                 :        102 : FlintTable_base::clear_bit_map()
     510                 :            : {
     511                 :        102 :     memset(bit_map, 0, bit_map_size);
     512                 :        102 : }
     513                 :            : 
     514                 :            : // We've commited, so "bitmap at start" needs to be reset to the current bitmap.
     515                 :            : void
     516                 :       2133 : FlintTable_base::commit()
     517                 :            : {
     518                 :       2133 :     memcpy(bit_map0, bit_map, bit_map_size);
     519                 :       2133 :     bit_map_low = 0;
     520                 :       2133 : }

Generated by: LCOV version 1.8