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

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

Generated by: LCOV version 1.8