LCOV - code coverage report
Current view: top level - backends/flint - flint_table.h (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 101 101 100.0 %
Date: 2011-08-21 Functions: 44 44 100.0 %
Branches: 15 16 93.8 %

           Branch data     Line data    Source code
       1                 :            : /* flint_table.h: Btree implementation
       2                 :            :  *
       3                 :            :  * Copyright 1999,2000,2001 BrightStation PLC
       4                 :            :  * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010 Olly Betts
       5                 :            :  * Copyright 2008 Lemur Consulting Ltd
       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                 :            : #ifndef OM_HGUARD_FLINT_TABLE_H
      24                 :            : #define OM_HGUARD_FLINT_TABLE_H
      25                 :            : 
      26                 :            : #include <xapian/error.h>
      27                 :            : #include <xapian/visibility.h>
      28                 :            : 
      29                 :            : #include "flint_types.h"
      30                 :            : #include "flint_btreebase.h"
      31                 :            : #include "flint_cursor.h"
      32                 :            : 
      33                 :            : #include "noreturn.h"
      34                 :            : #include "str.h"
      35                 :            : #include "stringutils.h"
      36                 :            : #include "unaligned.h"
      37                 :            : 
      38                 :            : #include <algorithm>
      39                 :            : #include <string>
      40                 :            : 
      41                 :            : #include <zlib.h>
      42                 :            : 
      43                 :            : #define DONT_COMPRESS -1
      44                 :            : 
      45                 :            : /** The largest possible value of a key_len.
      46                 :            :  *
      47                 :            :  *  This gives the upper limit of the size of a key that may be stored in the
      48                 :            :  *  B-tree (252 bytes with the present implementation).
      49                 :            :  */
      50                 :            : #define FLINT_BTREE_MAX_KEY_LEN 252
      51                 :            : 
      52                 :            : /** Even for items of at maximum size, it must be possible to get this number of
      53                 :            :  *  items in a block */
      54                 :            : #define BLOCK_CAPACITY 4
      55                 :            : 
      56                 :            : // FIXME: This named constant probably isn't used everywhere it should be...
      57                 :            : #define BYTES_PER_BLOCK_NUMBER 4
      58                 :            : 
      59                 :            : /*  The B-tree blocks have a number of internal lengths and offsets held in 1, 2
      60                 :            :     or 4 bytes. To make the coding a little clearer,
      61                 :            :        we use  for
      62                 :            :        ------  ---
      63                 :            :        K1      the 1 byte length of key
      64                 :            :        I2      the 2 byte length of an item (key-tag pair)
      65                 :            :        D2      the 2 byte offset to the item from the directory
      66                 :            :        C2      the 2 byte counter that ends each key and begins each tag
      67                 :            : */
      68                 :            : 
      69                 :            : #define K1 1
      70                 :            : #define I2 2
      71                 :            : #define D2 2
      72                 :            : #define C2 2
      73                 :            : 
      74                 :            : /*  and when getting K1 or setting D2, we use getK, setD defined as: */
      75                 :            : 
      76                 :            : #define getK(p, c)    getint1(p, c)
      77                 :            : #define setD(p, c, x) setint2(p, c, x)
      78                 :            : 
      79                 :            : /* if you've been reading the comments from the top, the next four procedures
      80                 :            :    will not cause any headaches.
      81                 :            : 
      82                 :            :    Recall that item has this form:
      83                 :            : 
      84                 :            :            i k
      85                 :            :            | |
      86                 :            :            I K key x C tag
      87                 :            :              <--K-->
      88                 :            :            <------I------>
      89                 :            : 
      90                 :            : 
      91                 :            :    item_of(p, c) returns i, the address of the item at block address p,
      92                 :            :    directory offset c,
      93                 :            : 
      94                 :            :    component_of(p, c) returns the number marked 'x' above,
      95                 :            : 
      96                 :            :    components_of(p, c) returns the number marked 'C' above,
      97                 :            : */
      98                 :            : 
      99                 :            : class XAPIAN_VISIBILITY_DEFAULT Key_ {
     100                 :            :     const byte *p;
     101                 :            : public:
     102                 :   20535888 :     explicit Key_(const byte * p_) : p(p_) { }
     103                 :      25166 :     const byte * get_address() const { return p; }
     104                 :      83736 :     void read(std::string * key) const {
     105                 :      83736 :         key->assign(reinterpret_cast<const char *>(p + K1), length());
     106                 :      83736 :     }
     107                 :            :     bool operator==(Key_ key2) const;
     108                 :            :     bool operator!=(Key_ key2) const { return !(*this == key2); }
     109                 :            :     bool operator<(Key_ key2) const;
     110                 :          1 :     bool operator>=(Key_ key2) const { return !(*this < key2); }
     111                 :            :     bool operator>(Key_ key2) const { return key2 < *this; }
     112                 :    5007041 :     bool operator<=(Key_ key2) const { return !(key2 < *this); }
     113                 :   35104760 :     int length() const {
     114                 :   35104760 :         return getK(p, 0) - C2 - K1;
     115                 :            :     }
     116                 :     158876 :     char operator[](size_t i) const {
     117                 :     158876 :         return p[i + K1];
     118                 :            :     }
     119                 :            : };
     120                 :            : 
     121                 :            : // Item_wr_ wants to be "Item_ with non-const p and more methods" - we can't
     122                 :            : // achieve that nicely with inheritance, so we use a template base class.
     123                 :            : template <class T> class Item_base_ {
     124                 :            : protected:
     125                 :            :     T p;
     126                 :            : public:
     127                 :            :     /* Item_ from block address and offset to item pointer */
     128                 :   23596282 :     Item_base_(T p_, int c) : p(p_ + getint2(p_, c)) { }
     129                 :      74051 :     Item_base_(T p_) : p(p_) { }
     130                 :    2125024 :     T get_address() const { return p; }
     131                 :    8282151 :     int size() const { return getint2(p, 0) & 0x7fff; } /* I in diagram above */
     132                 :    1284142 :     bool get_compressed() const { return *p & 0x80; }
     133                 :      50188 :     int component_of() const {
     134                 :      50188 :         return getint2(p, getK(p, I2) + I2 - C2);
     135                 :            :     }
     136                 :    1382221 :     int components_of() const {
     137                 :    1382221 :         return getint2(p, getK(p, I2) + I2);
     138                 :            :     }
     139                 :   20535888 :     Key_ key() const { return Key_(p + I2); }
     140                 :    1808255 :     void append_chunk(std::string * tag) const {
     141                 :            :         /* number of bytes to extract from current component */
     142                 :    1808255 :         int cd = getK(p, I2) + I2 + C2;
     143                 :    1808255 :         int l = size() - cd;
     144                 :    1808255 :         tag->append(reinterpret_cast<const char *>(p + cd), l);
     145                 :    1808255 :     }
     146                 :            :     /** Get this item's tag as a block number (this block should not be at
     147                 :            :      *  level 0).
     148                 :            :      */
     149                 :    3332019 :     uint4 block_given_by() const {
     150                 :    3332019 :         return getint4(p, size() - BYTES_PER_BLOCK_NUMBER);
     151                 :            :     }
     152                 :            : };
     153                 :            : 
     154                 :            : class Item_ : public Item_base_<const byte *> {
     155                 :            : public:
     156                 :            :     /* Item_ from block address and offset to item pointer */
     157                 :   23595381 :     Item_(const byte * p_, int c) : Item_base_<const byte *>(p_, c) { }
     158                 :            :     Item_(const byte * p_) : Item_base_<const byte *>(p_) { }
     159                 :            : };
     160                 :            : 
     161                 :            : class Item_wr_ : public Item_base_<byte *> {
     162                 :    2432179 :     void set_key_len(int x) { setint1(p, I2, x); }
     163                 :            : public:
     164                 :            :     /* Item_wr_ from block address and offset to item pointer */
     165                 :        901 :     Item_wr_(byte * p_, int c) : Item_base_<byte *>(p_, c) { }
     166                 :      74051 :     Item_wr_(byte * p_) : Item_base_<byte *>(p_) { }
     167                 :    3412890 :     void set_component_of(int i) {
     168                 :    3412890 :         setint2(p, getK(p, I2) + I2 - C2, i);
     169                 :    3412890 :     }
     170                 :     976726 :     void set_components_of(int m) {
     171                 :     976726 :         setint2(p, getK(p, I2) + I2, m);
     172                 :     976726 :     }
     173                 :            :     // Takes size as we may be truncating newkey.
     174                 :      12487 :     void set_key_and_block(Key_ newkey, int truncate_size, uint4 n) {
     175                 :      12487 :         int i = truncate_size;
     176                 :            :         // Read the length now because we may be copying the key over itself.
     177                 :            :         // FIXME that's stupid!  sort this out
     178                 :      12487 :         int newkey_len = newkey.length();
     179                 :      12487 :         int newsize = I2 + K1 + i + C2;
     180                 :            :         // Item size (4 since tag contains block number)
     181                 :      12487 :         setint2(p, 0, newsize + 4);
     182                 :            :         // Key size
     183                 :      12487 :         setint1(p, I2, newsize - I2);
     184                 :            :         // Copy the main part of the key, possibly truncating.
     185                 :      12487 :         std::memmove(p + I2 + K1, newkey.get_address() + K1, i);
     186                 :            :         // Copy the count part.
     187                 :      12487 :         std::memmove(p + I2 + K1 + i, newkey.get_address() + K1 + newkey_len, C2);
     188                 :            :         // Set tag contents to block number
     189                 :            : //      set_block_given_by(n);
     190                 :      12487 :         setint4(p, newsize, n);
     191                 :      12487 :     }
     192                 :            : 
     193                 :            :     /** Set this item's tag to point to block n (this block should not be at
     194                 :            :      *  level 0).
     195                 :            :      */
     196                 :        901 :     void set_block_given_by(uint4 n) {
     197                 :        901 :         setint4(p, size() - BYTES_PER_BLOCK_NUMBER, n);
     198                 :        901 :     }
     199                 :     984560 :     void set_size(int l) { setint2(p, 0, l); }
     200                 :            :     /** Form an item with a null key and with block number n in the tag.
     201                 :            :      */
     202                 :        321 :     void form_null_key(uint4 n) {
     203                 :        321 :         setint4(p, I2 + K1, n);
     204                 :        321 :         set_key_len(K1);        /* null key */
     205                 :        321 :         set_size(I2 + K1 + 4);  /* total length */
     206                 :        321 :     }
     207                 :    2428533 :     void form_key(const std::string & key_) {
     208                 :    2428533 :         std::string::size_type key_len = key_.length();
     209         [ +  + ]:    2428533 :         if (key_len > FLINT_BTREE_MAX_KEY_LEN) {
     210                 :            :             // We check term length when a term is added to a document but
     211                 :            :             // flint doubles zero bytes, so this can still happen for terms
     212                 :            :             // which contain one or more zero bytes.
     213                 :          8 :             std::string msg("Key too long: length was ");
     214                 :          8 :             msg += str(key_len);
     215                 :            :             msg += " bytes, maximum length of a key is "
     216                 :          8 :                    STRINGIZE(FLINT_BTREE_MAX_KEY_LEN) " bytes";
     217                 :         16 :             throw Xapian::InvalidArgumentError(msg);
     218                 :            :         }
     219                 :            : 
     220                 :    2428525 :         set_key_len(key_len + K1 + C2);
     221                 :    2428525 :         std::memmove(p + I2 + K1, key_.data(), key_len);
     222                 :    2428525 :         set_component_of(1);
     223                 :    2428525 :     }
     224                 :            :     // FIXME passing cd here is icky
     225                 :     980906 :     void set_tag(int cd, const char *start, int len, bool compressed) {
     226                 :     980906 :         std::memmove(p + cd, start, len);
     227                 :     980906 :         set_size(cd + len);
     228         [ +  + ]:     980906 :         if (compressed) *p |= 0x80;
     229                 :     980906 :     }
     230                 :       3333 :     void fake_root_item() {
     231                 :       3333 :         set_key_len(K1 + C2);   // null key length
     232                 :       3333 :         set_size(I2 + K1 + 2 * C2);   // length of the item
     233                 :       3333 :         set_component_of(1);
     234                 :       3333 :         set_components_of(1);
     235                 :       3333 :     }
     236                 :            : };
     237                 :            : 
     238                 :            : // Allow for BTREE_CURSOR_LEVELS levels in the B-tree.
     239                 :            : // With 10, overflow is practically impossible
     240                 :            : // FIXME: but we want it to be completely impossible...
     241                 :            : #define BTREE_CURSOR_LEVELS 10
     242                 :            : 
     243                 :            : /** Class managing a Btree table in a Flint database.
     244                 :            :  *
     245                 :            :  *  A table is a store holding a set of key/tag pairs.
     246                 :            :  *
     247                 :            :  *  A key is used to access a block of data in a flint table.
     248                 :            :  * 
     249                 :            :  *  Keys are of limited length.
     250                 :            :  *
     251                 :            :  *  Keys may not be empty (each Btree has a special empty key for internal use).
     252                 :            :  *
     253                 :            :  *  A tag is a piece of data associated with a given key.  The contents
     254                 :            :  *  of the tag are opaque to the Btree.
     255                 :            :  *
     256                 :            :  *  Tags may be of arbitrary length (the Btree imposes a very large limit).
     257                 :            :  *  Note though that they will be loaded into memory in their entirety, so
     258                 :            :  *  should not be permitted to grow without bound in normal usage.
     259                 :            :  *
     260                 :            :  *  Tags which are null strings _are_ valid, and are different from a
     261                 :            :  *  tag simply not being in the table.
     262                 :            :  */
     263                 :            : class XAPIAN_VISIBILITY_DEFAULT FlintTable {
     264                 :            :     friend class FlintCursor; /* Should probably fix this. */
     265                 :            :     private:
     266                 :            :         /// Copying not allowed
     267                 :            :         FlintTable(const FlintTable &);
     268                 :            : 
     269                 :            :         /// Assignment not allowed
     270                 :            :         FlintTable & operator=(const FlintTable &);
     271                 :            : 
     272                 :            :         /// Return true if there are no entries in the table.
     273                 :            :         bool really_empty() const;
     274                 :            : 
     275                 :            :     public:
     276                 :            :         /** Create a new Btree object.
     277                 :            :          *
     278                 :            :          *  This does not create the table on disk - the create_and_open()
     279                 :            :          *  method must be called to create the table on disk.
     280                 :            :          *
     281                 :            :          *  This also does not open the table - either the create_and_open()
     282                 :            :          *  or open() methods must be called before use is made of the table.
     283                 :            :          *
     284                 :            :          *  @param tablename_   The name of the table (used in changesets).
     285                 :            :          *  @param path_        Path at which the table is stored.
     286                 :            :          *  @param readonly_    whether to open the table for read only access.
     287                 :            :          *  @param compress_strategy_   DONT_COMPRESS, Z_DEFAULT_STRATEGY,
     288                 :            :          *                              Z_FILTERED, Z_HUFFMAN_ONLY, or Z_RLE.
     289                 :            :          *  @param lazy         If true, don't create the table until it's
     290                 :            :          *                      needed.
     291                 :            :          */
     292                 :            :         FlintTable(const char * tablename_, const std::string & path_,
     293                 :            :                    bool readonly_, int compress_strategy_ = DONT_COMPRESS,
     294                 :            :                    bool lazy = false);
     295                 :            : 
     296                 :            :         /** Close the Btree.
     297                 :            :          *
     298                 :            :          *  Any outstanding changes (ie, changes made without commit() having
     299                 :            :          *  subsequently been called) will be lost.
     300                 :            :          */
     301                 :            :         ~FlintTable();
     302                 :            : 
     303                 :            :         /** Close the Btree.  This closes and frees any of the btree
     304                 :            :          *  structures which have been created and opened.
     305                 :            :          *
     306                 :            :          *  @param permanent If true, the Btree will not reopen on demand.
     307                 :            :          */
     308                 :            :         void close(bool permanent=false);
     309                 :            : 
     310                 :            :         /** Determine whether the btree exists on disk.
     311                 :            :          */
     312                 :            :         bool exists() const;
     313                 :            : 
     314                 :            :         /** Open the btree at the latest revision.
     315                 :            :          *
     316                 :            :          *  @exception Xapian::DatabaseCorruptError will be thrown if the table
     317                 :            :          *      is in a corrupt state.
     318                 :            :          *  @exception Xapian::DatabaseOpeningError will be thrown if the table
     319                 :            :          *      cannot be opened (but is not corrupt - eg, permission problems,
     320                 :            :          *      not present, etc).
     321                 :            :          */
     322                 :            :         void open();
     323                 :            : 
     324                 :            :         /** Open the btree at a given revision.
     325                 :            :          *
     326                 :            :          *  Like Btree::open, but try to open at the given revision number
     327                 :            :          *  and fail if that isn't possible.
     328                 :            :          *
     329                 :            :          *  @param revision_      - revision number to open.
     330                 :            :          *
     331                 :            :          *  @return true if table is successfully opened at desired revision;
     332                 :            :          *          false if table cannot be opened at desired revision (but
     333                 :            :          *          table is otherwise consistent).
     334                 :            :          *
     335                 :            :          *  @exception Xapian::DatabaseCorruptError will be thrown if the table
     336                 :            :          *      is in a corrupt state.
     337                 :            :          *  @exception Xapian::DatabaseOpeningError will be thrown if the table
     338                 :            :          *      cannot be opened (but is not corrupt - eg, permission problems,
     339                 :            :          *      not present, etc).
     340                 :            :          */
     341                 :            :         bool open(flint_revision_number_t revision_);
     342                 :            : 
     343                 :            :         /** Flush any outstanding changes to the DB file of the table.
     344                 :            :          *
     345                 :            :          *  This must be called before commit, to ensure that the DB file is
     346                 :            :          *  ready to be switched to a new version by the commit.
     347                 :            :          */
     348                 :            :         void flush_db();
     349                 :            : 
     350                 :            :         /** Commit any outstanding changes to the table.
     351                 :            :          *
     352                 :            :          *  Commit changes made by calling add() and del() to the Btree.
     353                 :            :          *
     354                 :            :          *  If an error occurs during the operation, this will be signalled
     355                 :            :          *  by an exception.  In case of error, changes made will not be
     356                 :            :          *  committed to the Btree - they will be discarded.
     357                 :            :          *
     358                 :            :          *  @param new_revision  The new revision number to store.  This must
     359                 :            :          *          be greater than the latest revision number (see
     360                 :            :          *          get_latest_revision_number()), or an exception will be
     361                 :            :          *          thrown.
     362                 :            :          *
     363                 :            :          *  @param changes_fd  The file descriptor to write changes to.
     364                 :            :          *          Defaults to -1, meaning no changes will be written.
     365                 :            :          */
     366                 :            :         void commit(flint_revision_number_t revision, int changes_fd = -1,
     367                 :            :                     const std::string * changes_tail = NULL);
     368                 :            : 
     369                 :            :         /** Append the list of blocks changed to a changeset file.
     370                 :            :          *
     371                 :            :          *  @param changes_fd  The file descriptor to write changes to.
     372                 :            :          */
     373                 :            :         void write_changed_blocks(int changes_fd);
     374                 :            : 
     375                 :            :         /** Cancel any outstanding changes.
     376                 :            :          *
     377                 :            :          *  This will discard any modifications which haven't been committed
     378                 :            :          *  by calling commit().
     379                 :            :          */
     380                 :            :         void cancel();
     381                 :            : 
     382                 :            :         /** Read an entry from the table, if and only if it is exactly that
     383                 :            :          *  being asked for.
     384                 :            :          *
     385                 :            :          *  If the key is found in the table, then the tag is copied to @a
     386                 :            :          *  tag.  If the key is not found tag is left unchanged.
     387                 :            :          * 
     388                 :            :          *  The result is true iff the specified key is found in the Btree.
     389                 :            :          *
     390                 :            :          *  @param key  The key to look for in the table.
     391                 :            :          *  @param tag  A tag object to fill with the value if found.
     392                 :            :          *
     393                 :            :          *  @return true if key is found in table,
     394                 :            :          *          false if key is not found in table.
     395                 :            :          */
     396                 :            :         bool get_exact_entry(const std::string & key, std::string & tag) const;
     397                 :            : 
     398                 :            :         /** Check if a key exists in the Btree.
     399                 :            :          *
     400                 :            :          *  This is just like get_exact_entry() except it doesn't read the tag
     401                 :            :          *  value so is more efficient if you only want to check that the key
     402                 :            :          *  exists.
     403                 :            :          *
     404                 :            :          *  @param key  The key to look for in the table.
     405                 :            :          *
     406                 :            :          *  @return true if key is found in table,
     407                 :            :          *          false if key is not found in table.
     408                 :            :          */
     409                 :            :         bool key_exists(const std::string &key) const;
     410                 :            : 
     411                 :            :         /** Read the tag value for the key pointed to by cursor C_.
     412                 :            :          *
     413                 :            :          *  @param keep_compressed  Don't uncompress the tag - e.g. useful
     414                 :            :          *                          if it's just being opaquely copied.
     415                 :            :          *
     416                 :            :          *  @return     true if current_tag holds compressed data (always
     417                 :            :          *              false if keep_compressed was false).
     418                 :            :          */
     419                 :            :         bool read_tag(Cursor_ * C_, std::string *tag, bool keep_compressed) const;
     420                 :            : 
     421                 :            :         /** Add a key/tag pair to the table, replacing any existing pair with
     422                 :            :          *  the same key.
     423                 :            :          *
     424                 :            :          *  If an error occurs during the operation, an exception will be
     425                 :            :          *  thrown.
     426                 :            :          *
     427                 :            :          *  If key is empty, then the null item is replaced.
     428                 :            :          *
     429                 :            :          *  e.g.    btree.add("TODAY", "Mon 9 Oct 2000");
     430                 :            :          *
     431                 :            :          *  @param key   The key to store in the table.
     432                 :            :          *  @param tag   The tag to store in the table.
     433                 :            :          *  @param already_compressed   true if tag is already compressed,
     434                 :            :          *              for example because it is being opaquely copied
     435                 :            :          *              (default: false).
     436                 :            :          */
     437                 :            :         void add(const std::string &key, std::string tag, bool already_compressed = false);
     438                 :            : 
     439                 :            :         /** Delete an entry from the table.
     440                 :            :          *
     441                 :            :          *  The entry will be removed from the table, if it exists.  If
     442                 :            :          *  it does not exist, no action will be taken.  The item with
     443                 :            :          *  an empty key can't be removed, and false is returned.
     444                 :            :          *
     445                 :            :          *  If an error occurs during the operation, this will be signalled
     446                 :            :          *  by an exception.
     447                 :            :          *
     448                 :            :          *  e.g.    bool deleted = btree.del("TODAY")
     449                 :            :          *
     450                 :            :          *  @param key   The key to remove from the table.
     451                 :            :          *
     452                 :            :          *  @return true if an entry was removed; false if it did not exist.
     453                 :            :          */
     454                 :            :         bool del(const std::string &key);
     455                 :            : 
     456                 :            :         /// Erase this table from disk.
     457                 :            :         void erase();
     458                 :            : 
     459                 :            :         /** Set the block size.
     460                 :            :          *
     461                 :            :          *  It's only safe to do this before the table is created.
     462                 :            :          */
     463                 :            :         void set_block_size(unsigned int block_size_);
     464                 :            : 
     465                 :            :         /** Get the block size.
     466                 :            :          */
     467                 :       1891 :         unsigned int get_block_size() const { return block_size; }
     468                 :            : 
     469                 :            :         /** Create a new empty btree structure on disk and open it at the
     470                 :            :          *  initial revision.
     471                 :            :          *
     472                 :            :          *  The table must be writable - it doesn't make sense to create
     473                 :            :          *  a table that is read-only!
     474                 :            :          *
     475                 :            :          *  The block size must be less than 64K, where K = 1024. It is unwise
     476                 :            :          *  to use a small block size (less than 1024 perhaps), so we enforce a
     477                 :            :          *  minimum block size of 2K.
     478                 :            :          *
     479                 :            :          *  Example:
     480                 :            :          *
     481                 :            :          *    Btree btree("X-");
     482                 :            :          *    btree.create_and_open(8192);
     483                 :            :          *    // Files will be X-DB, X-baseA (and X-baseB).
     484                 :            :          *
     485                 :            :          *  @param blocksize     - Size of blocks to use.
     486                 :            :          *
     487                 :            :          *  @exception Xapian::DatabaseCreateError if the table can't be
     488                 :            :          *      created.
     489                 :            :          *  @exception Xapian::InvalidArgumentError if the requested blocksize
     490                 :            :          *      is unsuitable.
     491                 :            :          */
     492                 :            :         void create_and_open(unsigned int blocksize);
     493                 :            : 
     494                 :            :         void set_full_compaction(bool parity);
     495                 :            : 
     496                 :            :         /** Get the latest revision number stored in this table.
     497                 :            :          *
     498                 :            :          *  This gives the higher of the revision numbers held in the base
     499                 :            :          *  files of the B-tree, or just the revision number if there's only
     500                 :            :          *  one base file.
     501                 :            :          *
     502                 :            :          *  It is possible that there are other, older, revisions of this
     503                 :            :          *  table available, and indeed that the revision currently open
     504                 :            :          *  is one of these older revisions.
     505                 :            :          */
     506                 :        797 :         flint_revision_number_t get_latest_revision_number() const {
     507                 :        797 :             return latest_revision_number;
     508                 :            :         }
     509                 :            : 
     510                 :            :         /** Get the revision number at which this table
     511                 :            :          *  is currently open.
     512                 :            :          *
     513                 :            :          *  It is possible that there are other, more recent or older
     514                 :            :          *  revisions available.
     515                 :            :          *
     516                 :            :          *  @return the current revision number.
     517                 :            :          */
     518                 :       6381 :         flint_revision_number_t get_open_revision_number() const {
     519                 :       6381 :             return revision_number;
     520                 :            :         }
     521                 :            : 
     522                 :            :         /** Return a count of the number of entries in the table.
     523                 :            :          *
     524                 :            :          *  The count does not include the ever-present item with null key.
     525                 :            :          *
     526                 :            :          *  Use @a empty() if you only want to know if the table is empty or
     527                 :            :          *  not.
     528                 :            :          *
     529                 :            :          *  @return The number of entries in the table.
     530                 :            :          */
     531                 :     225993 :         flint_tablesize_t get_entry_count() const {
     532                 :     225993 :             return item_count;
     533                 :            :         }
     534                 :            : 
     535                 :            :         /// Return true if there are no entries in the table.
     536                 :       1662 :         bool empty() const {
     537                 :            :             // Prior to 1.1.4/1.0.18, item_count was stored in 32 bits, so we
     538                 :            :             // can't trust it as there could be more than 1<<32 entries.
     539                 :            :             //
     540                 :            :             // In theory it should wrap, so if non-zero the table isn't empty,
     541                 :            :             // but the table this was first noticed in wasn't off by a multiple
     542                 :            :             // of 1<<32.
     543                 :            : 
     544                 :            :             // An empty table will always have level == 0, and most non-empty
     545                 :            :             // tables will have more levels, so use that as a short-cut.
     546 [ +  + ][ +  + ]:       1662 :             return (level == 0) && really_empty();
     547                 :            :         }
     548                 :            : 
     549                 :            :         /** Get a cursor for reading from the table.
     550                 :            :          *
     551                 :            :          *  The cursor is owned by the caller - it is the caller's
     552                 :            :          *  responsibility to ensure that it is deleted.
     553                 :            :          */
     554                 :            :         FlintCursor * cursor_get() const;
     555                 :            : 
     556                 :            :         /** Determine whether the object contains uncommitted modifications.
     557                 :            :          *
     558                 :            :          *  @return true if there have been modifications since the last
     559                 :            :          *          the last call to commit().
     560                 :            :          */
     561                 :       5172 :         bool is_modified() const { return Btree_modified; }
     562                 :            : 
     563                 :            :         /** Set the maximum item size given the block capacity.
     564                 :            :          *
     565                 :            :          *  At least this many items of maximum size must fit into a block.
     566                 :            :          *  The default is BLOCK_CAPACITY (which is currently 4).
     567                 :            :          */
     568                 :      10447 :         void set_max_item_size(size_t block_capacity) {
     569         [ -  + ]:      10447 :             if (block_capacity > BLOCK_CAPACITY) block_capacity = BLOCK_CAPACITY;
     570                 :            :             max_item_size = (block_size - 11 /*DIR_START*/ - block_capacity * D2)
     571                 :      10447 :                 / block_capacity;
     572                 :      10447 :         }
     573                 :            : 
     574                 :            :     protected:
     575                 :            : 
     576                 :            :         /** Perform the opening operation to read.
     577                 :            :          *
     578                 :            :          *  Return true iff the open succeeded.
     579                 :            :          */
     580                 :            :         bool do_open_to_read(bool revision_supplied, flint_revision_number_t revision_);
     581                 :            : 
     582                 :            :         /** Perform the opening operation to write.
     583                 :            :          *
     584                 :            :          *  Return true iff the open succeeded.
     585                 :            :          */
     586                 :            :         bool do_open_to_write(bool revision_supplied,
     587                 :            :                               flint_revision_number_t revision_,
     588                 :            :                               bool create_db = false);
     589                 :            :         bool basic_open(bool revision_supplied, flint_revision_number_t revision);
     590                 :            : 
     591                 :            :         bool find(Cursor_ *) const;
     592                 :            :         int delete_kt();
     593                 :            :         void read_block(uint4 n, byte *p) const;
     594                 :            :         void write_block(uint4 n, const byte *p) const;
     595                 :            :         XAPIAN_NORETURN(void set_overwritten() const);
     596                 :            :         void block_to_cursor(Cursor_ *C_, int j, uint4 n) const;
     597                 :            :         void alter();
     598                 :            :         void compact(byte *p);
     599                 :            :         void enter_key(int j, Key_ prevkey, Key_ newkey);
     600                 :            :         int mid_point(byte *p);
     601                 :            :         void add_item_to_block(byte *p, Item_wr_ kt, int c);
     602                 :            :         void add_item(Item_wr_ kt, int j);
     603                 :            :         void delete_item(int j, bool repeatedly);
     604                 :            :         int add_kt(bool found);
     605                 :            :         void read_root();
     606                 :            :         void split_root(uint4 split_n);
     607                 :            :         void form_key(const std::string & key) const;
     608                 :            : 
     609                 :            :         /// The name of the table (used when writing changesets).
     610                 :            :         const char * tablename;
     611                 :            : 
     612                 :       2865 :         char other_base_letter() const {
     613         [ +  + ]:       2865 :            return (base_letter == 'A') ? 'B' : 'A';
     614                 :            :         }
     615                 :            : 
     616                 :            :         /// Allocate the zstream for deflating, if not already allocated.
     617                 :            :         void lazy_alloc_deflate_zstream() const;
     618                 :            : 
     619                 :            :         /// Allocate the zstream for inflating, if not already allocated.
     620                 :            :         void lazy_alloc_inflate_zstream() const;
     621                 :            : 
     622                 :            :         /** revision number of the opened B-tree. */
     623                 :            :         flint_revision_number_t revision_number;
     624                 :            : 
     625                 :            :         /** keeps a count of the number of items in the B-tree. */
     626                 :            :         uint4 item_count;
     627                 :            : 
     628                 :            :         /** block size of the B tree in bytes */
     629                 :            :         unsigned int block_size;
     630                 :            : 
     631                 :            :         /** Revision number of the other base, or zero if there is only one
     632                 :            :          *  base file.
     633                 :            :          */
     634                 :            :         mutable flint_revision_number_t latest_revision_number;
     635                 :            : 
     636                 :            :         /** set to true if baseA and baseB both exist as valid bases.
     637                 :            :          *
     638                 :            :          *  The unused base is deleted as soon as a write to the Btree takes
     639                 :            :          *  place. */
     640                 :            :         mutable bool both_bases;
     641                 :            : 
     642                 :            :         /** the value 'A' or 'B' of the current base */
     643                 :            :         char base_letter;
     644                 :            : 
     645                 :            :         /** true if the root block is faked (not written to disk).
     646                 :            :          * false otherwise.  This is true when the btree hasn't been
     647                 :            :          * modified yet.
     648                 :            :          */
     649                 :            :         bool faked_root_block;
     650                 :            : 
     651                 :            :         /** true iff the data has been written in a single write in
     652                 :            :          * sequential order.
     653                 :            :          */
     654                 :            :         bool sequential;
     655                 :            : 
     656                 :            :         /// corresponding file handle
     657                 :            :         int handle;
     658                 :            : 
     659                 :            :         /// number of levels, counting from 0
     660                 :            :         int level;
     661                 :            : 
     662                 :            :         /// the root block of the B-tree
     663                 :            :         uint4 root;
     664                 :            : 
     665                 :            :         /// buffer of size block_size for making up key-tag items
     666                 :            :         mutable Item_wr_ kt;
     667                 :            : 
     668                 :            :         /// buffer of size block_size for reforming blocks
     669                 :            :         byte * buffer;
     670                 :            : 
     671                 :            :         /// For writing back as file baseA or baseB.
     672                 :            :         FlintTable_base base;
     673                 :            : 
     674                 :            :         /// The path name of the B tree.
     675                 :            :         std::string name;
     676                 :            : 
     677                 :            :         /** count of the number of successive instances of purely
     678                 :            :          * sequential addition, starting at SEQ_START_POINT (neg) and
     679                 :            :          * going up to zero. */
     680                 :            :         int seq_count;
     681                 :            : 
     682                 :            :         /** the last block to be changed by an addition */
     683                 :            :         uint4 changed_n;
     684                 :            : 
     685                 :            :         /** directory offset corresponding to last block to be changed
     686                 :            :          *  by an addition */
     687                 :            :         int changed_c;
     688                 :            : 
     689                 :            :         /// maximum size of an item (key-tag pair)
     690                 :            :         size_t max_item_size;
     691                 :            : 
     692                 :            :         /// Set to true the first time the B-tree is modified.
     693                 :            :         mutable bool Btree_modified;
     694                 :            : 
     695                 :            :         /// set to true when full compaction is to be achieved
     696                 :            :         bool full_compaction;
     697                 :            : 
     698                 :            :         /// Set to true when the database is opened to write.
     699                 :            :         bool writable;
     700                 :            : 
     701                 :            :         /// Flag for tracking when cursors need to rebuild.
     702                 :            :         mutable bool cursor_created_since_last_modification;
     703                 :            : 
     704                 :            :         /// Version count for tracking when cursors need to rebuild.
     705                 :            :         unsigned long cursor_version;
     706                 :            : 
     707                 :            :         /* B-tree navigation functions */
     708                 :        107 :         bool prev(Cursor_ *C_, int j) const {
     709         [ +  + ]:        107 :             if (sequential) return prev_for_sequential(C_, j);
     710                 :        107 :             return prev_default(C_, j);
     711                 :            :         }
     712                 :            : 
     713                 :     704458 :         bool next(Cursor_ *C_, int j) const {
     714         [ +  + ]:     704458 :             if (sequential) return next_for_sequential(C_, j);
     715                 :     704458 :             return next_default(C_, j);
     716                 :            :         }
     717                 :            : 
     718                 :            :         /* Default implementations. */
     719                 :            :         bool prev_default(Cursor_ *C_, int j) const;
     720                 :            :         bool next_default(Cursor_ *C_, int j) const;
     721                 :            : 
     722                 :            :         /* Implementations for sequential mode. */
     723                 :            :         bool prev_for_sequential(Cursor_ *C_, int dummy) const;
     724                 :            :         bool next_for_sequential(Cursor_ *C_, int dummy) const;
     725                 :            : 
     726                 :            :         static int find_in_block(const byte * p, Key_ key, bool leaf, int c);
     727                 :            : 
     728                 :            :         /** block_given_by(p, c) finds the item at block address p, directory
     729                 :            :          *  offset c, and returns its tag value as an integer.
     730                 :            :          */
     731                 :            :         static uint4 block_given_by(const byte * p, int c);
     732                 :            : 
     733                 :            :         mutable Cursor_ C[BTREE_CURSOR_LEVELS];
     734                 :            : 
     735                 :            :         /** Buffer used when splitting a block.
     736                 :            :          *
     737                 :            :          *  This buffer holds the split off part of the block.  It's only used
     738                 :            :          *  when updating (in FlintTable::add_item().
     739                 :            :          */
     740                 :            :         byte * split_p;
     741                 :            : 
     742                 :            :         /** DONT_COMPRESS or Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY,
     743                 :            :          *  Z_RLE. */
     744                 :            :         int compress_strategy;
     745                 :            : 
     746                 :            :         /// Zlib state object for deflating
     747                 :            :         mutable z_stream *deflate_zstream;
     748                 :            : 
     749                 :            :         /// Zlib state object for inflating
     750                 :            :         mutable z_stream *inflate_zstream;
     751                 :            : 
     752                 :            :         /// If true, don't create the table until it's needed.
     753                 :            :         bool lazy;
     754                 :            : 
     755                 :            :         /* Debugging methods */
     756                 :            : //      void report_block_full(int m, int n, const byte * p);
     757                 :            : 
     758                 :            :         /// Throw an exception indicating that the database is closed.
     759                 :            :         XAPIAN_NORETURN(static void throw_database_closed());
     760                 :            : };
     761                 :            : 
     762                 :            : #endif /* OM_HGUARD_FLINT_TABLE_H */

Generated by: LCOV version 1.8