LCOV - code coverage report
Current view: top level - backends/honey - honey_alltermslist.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 954b5873a738 Lines: 67 83 80.7 %
Date: 2019-06-30 05:20:33 Functions: 7 9 77.8 %
Branches: 52 110 47.3 %

           Branch data     Line data    Source code
       1                 :            : /** @file honey_alltermslist.cc
       2                 :            :  * @brief A termlist containing all terms in a honey database.
       3                 :            :  */
       4                 :            : /* Copyright (C) 2005,2007,2008,2009,2010,2017,2018 Olly Betts
       5                 :            :  *
       6                 :            :  * This program is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU General Public License as
       8                 :            :  * published by the Free Software Foundation; either version 2 of the
       9                 :            :  * License, or (at your option) any later version.
      10                 :            :  *
      11                 :            :  * This program is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :            :  * GNU General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU General Public License
      17                 :            :  * along with this program; if not, write to the Free Software
      18                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      19                 :            :  * USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : 
      24                 :            : #include "honey_alltermslist.h"
      25                 :            : #include "honey_cursor.h"
      26                 :            : #include "honey_postlist.h"
      27                 :            : #include "honey_postlist_encodings.h"
      28                 :            : 
      29                 :            : #include "debuglog.h"
      30                 :            : #include "pack.h"
      31                 :            : #include "stringutils.h"
      32                 :            : 
      33                 :            : #include "xapian/error.h"
      34                 :            : 
      35                 :            : using namespace std;
      36                 :            : 
      37                 :            : void
      38                 :        269 : HoneyAllTermsList::read_termfreq_and_collfreq() const
      39                 :            : {
      40                 :            :     LOGCALL_VOID(DB, "HoneyAllTermsList::read_termfreq_and_collfreq", NO_ARGS);
      41                 :            :     Assert(!at_end());
      42                 :            : 
      43                 :            :     // Unpack the termfreq and collfreq from the tag.  Only do this if
      44                 :            :     // one or other is actually read.
      45         [ +  + ]:        269 :     cursor->read_tag();
      46                 :        268 :     const char *p = cursor->current_tag.data();
      47                 :        268 :     const char *pend = p + cursor->current_tag.size();
      48         [ -  + ]:        268 :     if (!decode_initial_chunk_header_freqs(&p, pend,
      49         [ +  - ]:        268 :                                            termfreq, collfreq)) {
      50                 :            :         throw Xapian::DatabaseCorruptError("Postlist initial chunk header not "
      51 [ #  # ][ #  # ]:          0 :                                            "as expected");
                 [ #  # ]
      52                 :            :     }
      53                 :        268 : }
      54                 :            : 
      55                 :        261 : HoneyAllTermsList::~HoneyAllTermsList()
      56                 :            : {
      57                 :            :     LOGCALL_DTOR(DB, "HoneyAllTermsList");
      58         [ +  + ]:         87 :     delete cursor;
      59         [ -  + ]:        174 : }
      60                 :            : 
      61                 :            : Xapian::termcount
      62                 :          0 : HoneyAllTermsList::get_approx_size() const
      63                 :            : {
      64                 :            :     // This is an over-estimate and not entirely proportional between shards,
      65                 :            :     // but we only use this value to build a balanced or-tree, and it'll at
      66                 :            :     // least tend to distinguish large databases from small ones.
      67                 :          0 :     return database->postlist_table.get_approx_entry_count();
      68                 :            : }
      69                 :            : 
      70                 :            : string
      71                 :      12503 : HoneyAllTermsList::get_termname() const
      72                 :            : {
      73                 :            :     LOGCALL(DB, string, "HoneyAllTermsList::get_termname", NO_ARGS);
      74                 :            :     Assert(!at_end());
      75                 :      12503 :     RETURN(current_term);
      76                 :            : }
      77                 :            : 
      78                 :            : Xapian::doccount
      79                 :        269 : HoneyAllTermsList::get_termfreq() const
      80                 :            : {
      81                 :            :     LOGCALL(DB, Xapian::doccount, "HoneyAllTermsList::get_termfreq", NO_ARGS);
      82                 :            :     Assert(!at_end());
      83         [ +  - ]:        269 :     if (termfreq == 0) read_termfreq_and_collfreq();
      84                 :        268 :     RETURN(termfreq);
      85                 :            : }
      86                 :            : 
      87                 :            : Xapian::termcount
      88                 :          0 : HoneyAllTermsList::get_collection_freq() const
      89                 :            : {
      90                 :            :     LOGCALL(DB, Xapian::termcount, "HoneyAllTermsList::get_collection_freq", NO_ARGS);
      91                 :            :     Assert(!at_end());
      92         [ #  # ]:          0 :     if (termfreq == 0) read_termfreq_and_collfreq();
      93                 :          0 :     RETURN(collfreq);
      94                 :            : }
      95                 :            : 
      96                 :            : TermList *
      97                 :       1323 : HoneyAllTermsList::next()
      98                 :            : {
      99                 :            :     LOGCALL(DB, TermList *, "HoneyAllTermsList::next", NO_ARGS);
     100                 :            :     // Set termfreq to 0 to indicate no termfreq/collfreq have been read for
     101                 :            :     // the current term.
     102                 :       1323 :     termfreq = 0;
     103                 :            : 
     104         [ +  + ]:       1323 :     if (rare(!cursor)) {
     105                 :            :         Assert(database.get());
     106                 :         87 :         cursor = database->postlist_table.cursor_get();
     107                 :            :         Assert(cursor); // The postlist table isn't optional.
     108                 :            : 
     109         [ +  + ]:         85 :         if (prefix.empty()) {
     110 [ +  - ][ +  - ]:         30 :             (void)cursor->find_entry_ge(string("\x00\xff", 2));
     111                 :            :         } else {
     112                 :         55 :             const string& key = pack_honey_postlist_key(prefix);
     113 [ +  - ][ +  + ]:         55 :             if (cursor->find_entry_ge(key)) {
     114                 :            :                 // The exact term we asked for is there, so just copy it rather
     115                 :            :                 // than wasting effort unpacking it from the key.
     116         [ +  - ]:          9 :                 current_term = prefix;
     117         [ +  + ]:         55 :                 RETURN(NULL);
     118                 :         46 :             }
     119                 :            :         }
     120         [ +  + ]:         76 :         if (cursor->after_end()) {
     121         [ +  - ]:          6 :             delete cursor;
     122                 :          6 :             cursor = NULL;
     123                 :          6 :             database = NULL;
     124                 :          6 :             RETURN(NULL);
     125                 :            :         }
     126                 :         70 :         goto first_time;
     127                 :            :     }
     128                 :            : 
     129                 :            :     while (true) {
     130 [ +  + ][ +  + ]:       1240 :         if (!cursor->next()) {
     131         [ +  - ]:         16 :             delete cursor;
     132                 :         16 :             cursor = NULL;
     133         [ +  - ]:         16 :             database = NULL;
     134                 :         16 :             RETURN(NULL);
     135                 :            :         }
     136                 :            : 
     137                 :            : first_time:
     138                 :       1293 :         const char *p = cursor->current_key.data();
     139                 :       1293 :         const char *pend = p + cursor->current_key.size();
     140 [ +  - ][ -  + ]:       1293 :         if (!unpack_string_preserving_sort(&p, pend, current_term)) {
     141                 :            :             throw Xapian::DatabaseCorruptError("PostList table key has "
     142 [ #  # ][ #  # ]:          0 :                                                "unexpected format");
                 [ #  # ]
     143                 :            :         }
     144                 :            : 
     145                 :            :         // If this key is for the first chunk of a postlist, we're done.
     146                 :            :         // Otherwise we need to skip past continuation chunks until we find the
     147                 :            :         // first chunk of the next postlist.
     148         [ +  + ]:       1293 :         if (p == pend) break;
     149                 :            :     }
     150                 :            : 
     151         [ +  + ]:       1289 :     if (!startswith(current_term, prefix)) {
     152                 :            :         // We've reached the end of the prefixed terms.
     153         [ +  - ]:         44 :         delete cursor;
     154                 :         44 :         cursor = NULL;
     155                 :         44 :         database = NULL;
     156                 :            :     }
     157                 :            : 
     158                 :       1324 :     RETURN(NULL);
     159                 :            : }
     160                 :            : 
     161                 :            : TermList *
     162                 :          9 : HoneyAllTermsList::skip_to(const string &term)
     163                 :            : {
     164                 :            :     LOGCALL(DB, TermList *, "HoneyAllTermsList::skip_to", term);
     165                 :            :     // Set termfreq to 0 to indicate we've not read termfreq and collfreq for
     166                 :            :     // the current term.
     167                 :          9 :     termfreq = 0;
     168                 :            : 
     169         [ -  + ]:          9 :     if (rare(!cursor)) {
     170         [ #  # ]:          0 :         if (!database.get()) {
     171                 :            :             // skip_to() once at_end() is allowed but a no-op.
     172                 :          0 :             RETURN(NULL);
     173                 :            :         }
     174         [ #  # ]:          0 :         if (rare(term.empty())) {
     175         [ #  # ]:          0 :             RETURN(next());
     176                 :            :         }
     177         [ #  # ]:          0 :         cursor = database->postlist_table.cursor_get();
     178                 :            :         Assert(cursor); // The postlist table isn't optional.
     179                 :            :     }
     180                 :            : 
     181         [ -  + ]:          9 :     if (rare(term.empty())) {
     182                 :          0 :         RETURN(NULL);
     183                 :            :     }
     184                 :            : 
     185         [ +  - ]:          9 :     string key = pack_honey_postlist_key(term);
     186 [ +  - ][ +  + ]:          9 :     if (cursor->find_entry_ge(key)) {
     187                 :            :         // The exact term we asked for is there, so just copy it rather than
     188                 :            :         // wasting effort unpacking it from the key.
     189         [ +  - ]:          4 :         current_term = term;
     190                 :            :     } else {
     191         [ +  + ]:          5 :         if (cursor->after_end()) {
     192         [ +  - ]:          2 :             delete cursor;
     193                 :          2 :             cursor = NULL;
     194         [ +  - ]:          2 :             database = NULL;
     195                 :          2 :             RETURN(NULL);
     196                 :            :         }
     197                 :            : 
     198                 :          3 :         const char *p = cursor->current_key.data();
     199                 :          3 :         const char *pend = p + cursor->current_key.size();
     200 [ +  - ][ +  - ]:          3 :         if (!unpack_string_preserving_sort(&p, pend, current_term) ||
         [ -  + ][ -  + ]
     201                 :          3 :             p != pend) {
     202                 :            :             throw Xapian::DatabaseCorruptError("PostList table key has "
     203 [ #  # ][ #  # ]:          3 :                                                "unexpected format");
                 [ #  # ]
     204                 :            :         }
     205                 :            :     }
     206                 :            : 
     207         [ -  + ]:          7 :     if (!startswith(current_term, prefix)) {
     208                 :            :         // We've reached the end of the prefixed terms.
     209         [ #  # ]:          0 :         delete cursor;
     210                 :          0 :         cursor = NULL;
     211         [ #  # ]:          0 :         database = NULL;
     212                 :            :     }
     213                 :            : 
     214                 :          9 :     RETURN(NULL);
     215                 :            : }
     216                 :            : 
     217                 :            : bool
     218                 :       1334 : HoneyAllTermsList::at_end() const
     219                 :            : {
     220                 :            :     LOGCALL(DB, bool, "HoneyAllTermsList::at_end", NO_ARGS);
     221                 :            :     // Either next() or skip_to() should be called before at_end().
     222                 :            :     Assert(!(cursor == NULL && database.get() != NULL));
     223                 :       1334 :     RETURN(cursor == NULL);
     224                 :            : }

Generated by: LCOV version 1.11