LCOV - code coverage report
Current view: top level - backends - databaseinternal.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 7028d852e609 Lines: 69 131 52.7 %
Date: 2019-02-17 14:59:59 Functions: 14 38 36.8 %
Branches: 52 146 35.6 %

           Branch data     Line data    Source code
       1                 :            : /** @file databaseinternal.cc
       2                 :            :  * @brief Virtual base class for Database internals
       3                 :            :  */
       4                 :            : /* Copyright 2003,2004,2006,2007,2008,2009,2011,2014,2015,2017 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 USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : 
      24                 :            : #include "databaseinternal.h"
      25                 :            : 
      26                 :            : #include "api/leafpostlist.h"
      27                 :            : #include "omassert.h"
      28                 :            : #include "slowvaluelist.h"
      29                 :            : #include "xapian/error.h"
      30                 :            : 
      31                 :            : #include <algorithm>
      32                 :            : #include <memory>
      33                 :            : #include <string>
      34                 :            : 
      35                 :            : using namespace std;
      36                 :            : using Xapian::Internal::intrusive_ptr;
      37                 :            : 
      38                 :            : namespace Xapian {
      39                 :            : 
      40                 :            : [[noreturn]]
      41                 :         36 : static void invalid_operation(const char* msg)
      42                 :            : {
      43 [ +  - ][ +  - ]:         36 :     throw InvalidOperationError(msg);
                 [ +  - ]
      44                 :            : }
      45                 :            : 
      46                 :            : Database::Internal::size_type
      47                 :     254904 : Database::Internal::size() const
      48                 :            : {
      49                 :     254904 :     return 1;
      50                 :            : }
      51                 :            : 
      52                 :            : void
      53                 :         26 : Database::Internal::keep_alive()
      54                 :            : {
      55                 :            :     // No-op except for remote databases.
      56                 :         26 : }
      57                 :            : 
      58                 :            : void
      59                 :      28719 : Database::Internal::readahead_for_query(const Xapian::Query &) const
      60                 :            : {
      61                 :      28719 : }
      62                 :            : 
      63                 :            : Xapian::termcount
      64                 :          0 : Database::Internal::get_unique_terms_lower_bound() const
      65                 :            : {
      66                 :          0 :     return 1;
      67                 :            : }
      68                 :            : 
      69                 :            : Xapian::termcount
      70                 :          0 : Database::Internal::get_unique_terms_upper_bound() const
      71                 :            : {
      72                 :          0 :     return get_doclength_upper_bound();
      73                 :            : }
      74                 :            : 
      75                 :            : // Discard any exceptions - we're called from the destructors of derived
      76                 :            : // classes so we can't safely throw.
      77                 :            : void
      78                 :       1619 : Database::Internal::dtor_called_()
      79                 :            : {
      80                 :            :     try {
      81         [ +  + ]:       1619 :         if (transaction_active()) {
      82         [ +  + ]:          6 :             end_transaction(false);
      83                 :            :         } else {
      84                 :            :             // TRANSACTION_READONLY and TRANSACTION_UNIMPLEMENTED should be
      85                 :            :             // handled by the inlined dtor_called() wrapper.
      86                 :            :             AssertEq(state, TRANSACTION_NONE);
      87         [ +  + ]:       1613 :             commit();
      88                 :            :         }
      89                 :         24 :     } catch (...) {
      90                 :            :         // We can't safely throw exceptions from a destructor in case an
      91                 :            :         // exception is already active and causing us to be destroyed.
      92                 :            :     }
      93                 :       1643 : }
      94                 :            : 
      95                 :            : void
      96                 :          0 : Database::Internal::commit()
      97                 :            : {
      98                 :            :     // Writable databases should override this method, but this can get called
      99                 :            :     // if a read-only shard gets added to a WritableDatabase.
     100                 :          0 :     invalid_operation("WritableDatabase::commit() called with a read-only shard");
     101                 :            : }
     102                 :            : 
     103                 :            : void
     104                 :          0 : Database::Internal::cancel()
     105                 :            : {
     106                 :            :     // Writable databases should override this method, but this can get called
     107                 :            :     // if a read-only shard gets added to a WritableDatabase.
     108                 :          0 :     invalid_operation("WritableDatabase::cancel() called with a read-only shard");
     109                 :            : }
     110                 :            : 
     111                 :            : void
     112                 :         63 : Database::Internal::begin_transaction(bool flushed)
     113                 :            : {
     114         [ +  + ]:         63 :     if (state != TRANSACTION_NONE) {
     115         [ +  - ]:         12 :         if (transaction_active()) {
     116                 :            :             invalid_operation("WritableDatabase::begin_transaction(): already "
     117                 :         12 :                               "in a transaction");
     118                 :            :         }
     119         [ #  # ]:          0 :         if (is_read_only()) {
     120                 :            :             invalid_operation("WritableDatabase::begin_transaction(): called "
     121                 :          0 :                               "with a read-only shard");
     122                 :            :         }
     123 [ #  # ][ #  # ]:          0 :         throw UnimplementedError("This backend doesn't implement transactions");
                 [ #  # ]
     124                 :            :     }
     125         [ +  + ]:         51 :     if (flushed) {
     126                 :            :         // N.B. Call commit() before we set state since commit() isn't allowed
     127                 :            :         // during a transaction.
     128                 :         34 :         commit();
     129                 :         30 :         state = TRANSACTION_FLUSHED;
     130                 :            :     } else {
     131                 :         17 :         state = TRANSACTION_UNFLUSHED;
     132                 :            :     }
     133                 :         47 : }
     134                 :            : 
     135                 :            : void
     136                 :         71 : Database::Internal::end_transaction(bool do_commit)
     137                 :            : {
     138         [ +  + ]:         71 :     if (!transaction_active()) {
     139         [ -  + ]:         24 :         if (state != TRANSACTION_NONE) {
     140         [ #  # ]:          0 :             if (is_read_only()) {
     141                 :            :                 invalid_operation(do_commit ?
     142                 :            :                                   "WritableDatabase::commit_transaction(): "
     143                 :            :                                   "called with a read-only shard" :
     144                 :            :                                   "WritableDatabase::cancel_transaction(): "
     145         [ #  # ]:          0 :                                   "called with a read-only shard");
     146                 :            :             }
     147 [ #  # ][ #  # ]:          0 :             throw UnimplementedError("This backend doesn't implement transactions");
                 [ #  # ]
     148                 :            :         }
     149                 :            :         invalid_operation(do_commit ?
     150                 :            :                           "WritableDatabase::commit_transaction(): not in a "
     151                 :            :                           "transaction" :
     152                 :            :                           "WritableDatabase::cancel_transaction(): not in a "
     153         [ +  + ]:         24 :                           "transaction");
     154                 :            :     }
     155                 :            : 
     156                 :         47 :     auto old_state = state;
     157                 :         47 :     state = TRANSACTION_NONE;
     158         [ +  + ]:         47 :     if (!do_commit) {
     159                 :         37 :         cancel();
     160         [ +  - ]:         10 :     } else if (old_state == TRANSACTION_FLUSHED) {
     161                 :            :         // N.B. Call commit() after we clear state since commit() isn't
     162                 :            :         // allowed during a transaction.
     163                 :         10 :         commit();
     164                 :            :     }
     165                 :         44 : }
     166                 :            : 
     167                 :            : Xapian::docid
     168                 :          0 : Database::Internal::add_document(const Xapian::Document &)
     169                 :            : {
     170                 :            :     // Writable databases should override this method, but this can get called
     171                 :            :     // if a read-only shard gets added to a WritableDatabase.
     172                 :            :     invalid_operation("WritableDatabase::add_document() called with a "
     173                 :          0 :                       "read-only shard");
     174                 :            : }
     175                 :            : 
     176                 :            : void
     177                 :          0 : Database::Internal::delete_document(Xapian::docid)
     178                 :            : {
     179                 :            :     // Writable databases should override this method, but this can get called
     180                 :            :     // if a read-only shard gets added to a WritableDatabase.
     181                 :            :     invalid_operation("WritableDatabase::delete_document() called with a "
     182                 :          0 :                       "read-only shard");
     183                 :            : }
     184                 :            : 
     185                 :            : void
     186                 :         25 : Database::Internal::delete_document(const string& unique_term)
     187                 :            : {
     188                 :            :     // Default implementation - overridden for remote and sharded databases.
     189                 :            : 
     190         [ -  + ]:         25 :     if (is_read_only()) {
     191                 :            :         // This can happen if a read-only shard gets added to a
     192                 :            :         // WritableDatabase.
     193                 :            :         invalid_operation("WritableDatabase::delete_document() called with a "
     194                 :          0 :                           "read-only shard");
     195                 :            :     }
     196                 :            : 
     197         [ +  - ]:         25 :     unique_ptr<PostList> pl(open_post_list(unique_term));
     198                 :            : 
     199                 :            :     // We want this operation to be atomic if possible, so if we aren't in a
     200                 :            :     // transaction and the backend supports transactions, temporarily enter an
     201                 :            :     // unflushed transaction.
     202                 :         25 :     auto old_state = state;
     203         [ +  + ]:         25 :     if (state != TRANSACTION_UNIMPLEMENTED)
     204                 :         22 :         state = TRANSACTION_UNFLUSHED;
     205                 :            :     try {
     206 [ +  - ][ +  - ]:        834 :         while (pl->next(), !pl->at_end()) {
                 [ +  + ]
     207 [ +  - ][ +  - ]:        809 :             delete_document(pl->get_docid());
     208                 :            :         }
     209                 :          0 :     } catch (...) {
     210                 :          0 :         state = old_state;
     211                 :          0 :         throw;
     212                 :            :     }
     213                 :         25 :     state = old_state;
     214                 :         25 : }
     215                 :            : 
     216                 :            : void
     217                 :          0 : Database::Internal::replace_document(Xapian::docid, const Xapian::Document &)
     218                 :            : {
     219                 :            :     // Writable databases should override this method, but this can get called
     220                 :            :     // if a read-only shard gets added to a WritableDatabase.
     221                 :            :     invalid_operation("WritableDatabase::replace_document() called with a "
     222                 :          0 :                       "read-only shard");
     223                 :            : }
     224                 :            : 
     225                 :            : Xapian::docid
     226                 :        188 : Database::Internal::replace_document(const string & unique_term,
     227                 :            :                                      const Xapian::Document & document)
     228                 :            : {
     229                 :            :     // Default implementation - overridden for remote and sharded databases.
     230                 :            : 
     231         [ -  + ]:        188 :     if (is_read_only()) {
     232                 :            :         // This can happen if a read-only shard gets added to a
     233                 :            :         // WritableDatabase.
     234                 :            :         invalid_operation("WritableDatabase::replace_document() called with a "
     235                 :          0 :                           "read-only shard");
     236                 :            :     }
     237                 :            : 
     238         [ +  + ]:        188 :     unique_ptr<PostList> pl(open_post_list(unique_term));
     239         [ +  - ]:        186 :     pl->next();
     240 [ +  - ][ +  + ]:        186 :     if (pl->at_end()) {
     241         [ +  - ]:        114 :         return add_document(document);
     242                 :            :     }
     243         [ +  - ]:         72 :     Xapian::docid did = pl->get_docid();
     244                 :            : 
     245                 :            :     // We want this operation to be atomic if possible, so if we aren't in a
     246                 :            :     // transaction and the backend supports transactions, temporarily enter an
     247                 :            :     // unflushed transaction.
     248                 :         72 :     auto old_state = state;
     249         [ +  + ]:         72 :     if (state != TRANSACTION_UNIMPLEMENTED)
     250                 :         54 :         state = TRANSACTION_UNFLUSHED;
     251                 :            :     try {
     252         [ +  - ]:         72 :         replace_document(did, document);
     253 [ +  - ][ +  - ]:         84 :         while (pl->next(), !pl->at_end()) {
                 [ +  + ]
     254 [ +  - ][ +  - ]:         12 :             delete_document(pl->get_docid());
     255                 :            :         }
     256                 :          0 :     } catch (...) {
     257                 :          0 :         state = old_state;
     258                 :          0 :         throw;
     259                 :            :     }
     260                 :         72 :     state = old_state;
     261                 :        186 :     return did;
     262                 :            : }
     263                 :            : 
     264                 :            : ValueList *
     265                 :       5492 : Database::Internal::open_value_list(Xapian::valueno slot) const
     266                 :            : {
     267         [ +  + ]:       5492 :     return new SlowValueList(this, slot);
     268                 :            : }
     269                 :            : 
     270                 :            : TermList *
     271                 :          0 : Database::Internal::open_spelling_termlist(const string &) const
     272                 :            : {
     273                 :            :     // Only implemented for some database backends - others will just not
     274                 :            :     // suggest spelling corrections (or not contribute to them in a multiple
     275                 :            :     // database situation).
     276                 :          0 :     return NULL;
     277                 :            : }
     278                 :            : 
     279                 :            : TermList *
     280                 :          0 : Database::Internal::open_spelling_wordlist() const
     281                 :            : {
     282                 :            :     // Only implemented for some database backends - others will just not
     283                 :            :     // suggest spelling corrections (or not contribute to them in a multiple
     284                 :            :     // database situation).
     285                 :          0 :     return NULL;
     286                 :            : }
     287                 :            : 
     288                 :            : Xapian::doccount
     289                 :          0 : Database::Internal::get_spelling_frequency(const string &) const
     290                 :            : {
     291                 :            :     // Only implemented for some database backends - others will just not
     292                 :            :     // suggest spelling corrections (or not contribute to them in a multiple
     293                 :            :     // database situation).
     294                 :          0 :     return 0;
     295                 :            : }
     296                 :            : 
     297                 :            : void
     298                 :          0 : Database::Internal::add_spelling(const string &, Xapian::termcount) const
     299                 :            : {
     300 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement spelling correction");
                 [ #  # ]
     301                 :            : }
     302                 :            : 
     303                 :            : Xapian::termcount
     304                 :          0 : Database::Internal::remove_spelling(const string &, Xapian::termcount) const
     305                 :            : {
     306 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement spelling correction");
                 [ #  # ]
     307                 :            : }
     308                 :            : 
     309                 :            : TermList *
     310                 :          0 : Database::Internal::open_synonym_termlist(const string &) const
     311                 :            : {
     312                 :            :     // Only implemented for some database backends - others will just not
     313                 :            :     // expand synonyms (or not contribute to them in a multiple database
     314                 :            :     // situation).
     315                 :          0 :     return NULL;
     316                 :            : }
     317                 :            : 
     318                 :            : TermList *
     319                 :          0 : Database::Internal::open_synonym_keylist(const string &) const
     320                 :            : {
     321                 :            :     // Only implemented for some database backends - others will just not
     322                 :            :     // expand synonyms (or not contribute to them in a multiple database
     323                 :            :     // situation).
     324                 :          0 :     return NULL;
     325                 :            : }
     326                 :            : 
     327                 :            : void
     328                 :          0 : Database::Internal::add_synonym(const string &, const string &) const
     329                 :            : {
     330 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement synonyms");
                 [ #  # ]
     331                 :            : }
     332                 :            : 
     333                 :            : void
     334                 :          0 : Database::Internal::remove_synonym(const string &, const string &) const
     335                 :            : {
     336 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement synonyms");
                 [ #  # ]
     337                 :            : }
     338                 :            : 
     339                 :            : void
     340                 :          0 : Database::Internal::clear_synonyms(const string &) const
     341                 :            : {
     342 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement synonyms");
                 [ #  # ]
     343                 :            : }
     344                 :            : 
     345                 :            : string
     346                 :          0 : Database::Internal::get_metadata(const string &) const
     347                 :            : {
     348                 :          0 :     return string();
     349                 :            : }
     350                 :            : 
     351                 :            : TermList*
     352                 :          0 : Database::Internal::open_metadata_keylist(const string&) const
     353                 :            : {
     354                 :            :     // Only implemented for some database backends - others will simply report
     355                 :            :     // there being no metadata keys.
     356                 :          0 :     return NULL;
     357                 :            : }
     358                 :            : 
     359                 :            : void
     360                 :          0 : Database::Internal::set_metadata(const string&, const string&)
     361                 :            : {
     362 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement metadata");
                 [ #  # ]
     363                 :            : }
     364                 :            : 
     365                 :            : bool
     366                 :          0 : Database::Internal::reopen()
     367                 :            : {
     368                 :            :     // Database backends which don't support simultaneous update and reading
     369                 :            :     // probably don't need to do anything here.  And since we didn't do
     370                 :            :     // anything we should return false to indicate that nothing has changed.
     371                 :          0 :     return false;
     372                 :            : }
     373                 :            : 
     374                 :            : void
     375                 :         18 : Database::Internal::request_document(Xapian::docid) const
     376                 :            : {
     377                 :         18 : }
     378                 :            : 
     379                 :            : void
     380                 :          0 : Database::Internal::write_changesets_to_fd(int, const string&, bool, ReplicationInfo*)
     381                 :            : {
     382 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't provide changesets");
                 [ #  # ]
     383                 :            : }
     384                 :            : 
     385                 :            : Xapian::rev
     386                 :          0 : Database::Internal::get_revision() const
     387                 :            : {
     388 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't provide access to revision information");
                 [ #  # ]
     389                 :            : }
     390                 :            : 
     391                 :            : string
     392                 :         12 : Database::Internal::get_uuid() const
     393                 :            : {
     394                 :         12 :     return string();
     395                 :            : }
     396                 :            : 
     397                 :            : void
     398                 :     900886 : Database::Internal::invalidate_doc_object(Xapian::Document::Internal*) const
     399                 :            : {
     400                 :            :     // Do nothing, by default.
     401                 :     900886 : }
     402                 :            : 
     403                 :            : void
     404                 :          0 : Database::Internal::get_used_docid_range(Xapian::docid &,
     405                 :            :                                          Xapian::docid &) const
     406                 :            : {
     407 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("This backend doesn't implement get_used_docid_range()");
                 [ #  # ]
     408                 :            : }
     409                 :            : 
     410                 :            : bool
     411                 :          3 : Database::Internal::locked() const
     412                 :            : {
     413                 :          3 :     return false;
     414                 :            : }
     415                 :            : 
     416                 :            : }

Generated by: LCOV version 1.11