LCOV - code coverage report
Current view: top level - bin - xapian-check-flint.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 38 377 10.1 %
Date: 2011-08-21 Functions: 3 4 75.0 %
Branches: 20 228 8.8 %

           Branch data     Line data    Source code
       1                 :            : /** @file xapian-check-flint.cc
       2                 :            :  * @brief Check consistency of a flint table.
       3                 :            :  */
       4                 :            : /* Copyright 1999,2000,2001 BrightStation PLC
       5                 :            :  * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010 Olly Betts
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      20                 :            :  * USA
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : 
      25                 :            : #include "xapian-check-flint.h"
      26                 :            : 
      27                 :            : #include "bitstream.h"
      28                 :            : 
      29                 :            : #include "internaltypes.h"
      30                 :            : 
      31                 :            : #include "flint_check.h"
      32                 :            : #include "flint_cursor.h"
      33                 :            : #include "flint_table.h"
      34                 :            : #include "flint_types.h"
      35                 :            : #include "flint_utils.h"
      36                 :            : #include "valuestats.h"
      37                 :            : 
      38                 :            : #include <xapian.h>
      39                 :            : 
      40                 :            : #include "autoptr.h"
      41                 :            : #include <iostream>
      42                 :            : 
      43                 :            : using namespace std;
      44                 :            : 
      45                 :            : static inline bool
      46                 :          0 : is_user_metadata_key(const string & key)
      47                 :            : {
      48 [ #  # ][ #  # ]:          0 :     return key.size() > 1 && key[0] == '\0' && key[1] == '\xc0';
                 [ #  # ]
      49                 :            : }
      50                 :            : 
      51                 :            : size_t
      52                 :          4 : check_flint_table(const char * tablename, string filename, int opts,
      53                 :            :                   vector<Xapian::termcount> & doclens)
      54                 :            : {
      55                 :          4 :     filename += '.';
      56                 :            : 
      57                 :            :     // Check the btree structure.
      58                 :          4 :     BtreeCheck::check(tablename, filename, opts);
      59                 :            : 
      60                 :            :     // Now check the flint structures inside the btree.
      61                 :          4 :     FlintTable table(tablename, filename, true);
      62                 :          4 :     table.open();
      63                 :          4 :     AutoPtr<FlintCursor> cursor(table.cursor_get());
      64                 :            : 
      65                 :          4 :     size_t errors = 0;
      66                 :            : 
      67                 :          4 :     cursor->find_entry("");
      68                 :          4 :     cursor->next(); // Skip the empty entry.
      69                 :            : 
      70         [ +  + ]:          4 :     if (strcmp(tablename, "postlist") == 0) {
      71                 :            :         // Now check the structure of each postlist in the table.
      72                 :          1 :         string current_term;
      73                 :          1 :         Xapian::docid lastdid = 0;
      74                 :          1 :         Xapian::termcount termfreq = 0, collfreq = 0;
      75                 :          1 :         Xapian::termcount tf = 0, cf = 0;
      76                 :          1 :         bool have_metainfo_key = false;
      77                 :            : 
      78                 :            :         // The first key/tag pair should be the METAINFO - though this may be
      79                 :            :         // missing if the table only contains user-metadata.
      80         [ +  - ]:          1 :         if (!cursor->after_end()) {
      81         [ +  - ]:          1 :             if (cursor->current_key == string("", 1)) {
      82                 :          1 :                 have_metainfo_key = true;
      83                 :          1 :                 cursor->read_tag();
      84                 :            :                 // Check format of the METAINFO key.
      85                 :            :                 Xapian::docid did;
      86                 :            :                 totlen_t totlen;
      87                 :          1 :                 const char * data = cursor->current_tag.data();
      88                 :          1 :                 const char * end = data + cursor->current_tag.size();
      89         [ -  + ]:          1 :                 if (!F_unpack_uint(&data, end, &did)) {
      90                 :          0 :                     cout << "Tag containing meta information is corrupt." << endl;
      91                 :          0 :                     ++errors;
      92         [ -  + ]:          1 :                 } else if (!F_unpack_uint_last(&data, end, &totlen)) {
      93                 :          0 :                     cout << "Tag containing meta information is corrupt." << endl;
      94                 :          0 :                     ++errors;
      95         [ -  + ]:          1 :                 } else if (data != end) {
      96                 :          0 :                     cout << "Tag containing meta information is corrupt." << endl;
      97                 :          0 :                     ++errors;
      98                 :            :                 }
      99                 :          1 :                 cursor->next();
     100                 :            :             }
     101                 :            :         }
     102                 :            : 
     103         [ -  + ]:          1 :         for ( ; !cursor->after_end(); cursor->next()) {
     104                 :          0 :             string & key = cursor->current_key;
     105                 :            : 
     106         [ #  # ]:          0 :             if (is_user_metadata_key(key)) {
     107                 :            :                 // User metadata can be anything, so we can't do any particular
     108                 :            :                 // checks on it other than to check that the tag isn't empty.
     109                 :          0 :                 cursor->read_tag();
     110         [ #  # ]:          0 :                 if (cursor->current_tag.empty()) {
     111                 :          0 :                     cout << "User metadata item is empty" << endl;
     112                 :          0 :                     ++errors;
     113                 :            :                 }
     114                 :          0 :                 continue;
     115                 :            :             }
     116                 :            : 
     117         [ #  # ]:          0 :             if (!have_metainfo_key) {
     118                 :          0 :                 cout << "METAINFO key missing from postlist table" << endl;
     119                 :          0 :                 ++errors;
     120                 :            :             }
     121                 :            : 
     122 [ #  # ][ #  # ]:          0 :             if (key.size() >= 2 && key[0] == '\0' && key[1] == '\xe0') {
         [ #  # ][ #  # ]
     123                 :            :                 // doclen chunk
     124                 :            :                 const char * pos, * end;
     125                 :          0 :                 Xapian::docid did = 1;
     126         [ #  # ]:          0 :                 if (key.size() > 2) {
     127                 :            :                     // Non-initial chunk.
     128                 :          0 :                     pos = key.data();
     129                 :          0 :                     end = pos + key.size();
     130                 :          0 :                     pos += 2;
     131         [ #  # ]:          0 :                     if (!F_unpack_uint_preserving_sort(&pos, end, &did)) {
     132                 :          0 :                         cout << "Error unpacking docid from doclen key" << endl;
     133                 :          0 :                         ++errors;
     134                 :          0 :                         continue;
     135                 :            :                     }
     136                 :            :                 }
     137                 :            : 
     138                 :          0 :                 cursor->read_tag();
     139                 :          0 :                 pos = cursor->current_tag.data();
     140                 :          0 :                 end = pos + cursor->current_tag.size();
     141         [ #  # ]:          0 :                 if (key.size() == 2) {
     142                 :            :                     // Initial chunk.
     143 [ #  # ][ #  # ]:          0 :                     if (end - pos < 2 || pos[0] || pos[1]) {
                 [ #  # ]
     144                 :          0 :                         cout << "Initial doclen chunk has nonzero dummy fields" << endl;
     145                 :          0 :                         ++errors;
     146                 :          0 :                         continue;
     147                 :            :                     }
     148                 :          0 :                     pos += 2;
     149         [ #  # ]:          0 :                     if (!F_unpack_uint(&pos, end, &did)) {
     150                 :          0 :                         cout << "Failed to unpack firstdid for doclen" << endl;
     151                 :          0 :                         ++errors;
     152                 :          0 :                         continue;
     153                 :            :                     }
     154                 :          0 :                     ++did;
     155         [ #  # ]:          0 :                     if (did <= lastdid) {
     156                 :            :                         cout << "First did in this chunk is <= last in "
     157                 :          0 :                             "prev chunk" << endl;
     158                 :          0 :                         ++errors;
     159                 :            :                     }
     160                 :            :                 }
     161                 :            : 
     162                 :            :                 bool is_last_chunk;
     163         [ #  # ]:          0 :                 if (!F_unpack_bool(&pos, end, &is_last_chunk)) {
     164                 :          0 :                     cout << "Failed to unpack last chunk flag for doclen" << endl;
     165                 :          0 :                     ++errors;
     166                 :          0 :                     continue;
     167                 :            :                 }
     168                 :            :                 // Read what the final document ID in this chunk is.
     169         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &lastdid)) {
     170                 :          0 :                     cout << "Failed to unpack increase to last" << endl;
     171                 :          0 :                     ++errors;
     172                 :          0 :                     continue;
     173                 :            :                 }
     174                 :          0 :                 lastdid += did;
     175                 :          0 :                 bool bad = false;
     176                 :          0 :                 while (true) {
     177                 :            :                     Xapian::termcount doclen;
     178         [ #  # ]:          0 :                     if (!F_unpack_uint(&pos, end, &doclen)) {
     179                 :          0 :                         cout << "Failed to unpack doclen" << endl;
     180                 :          0 :                         ++errors;
     181                 :          0 :                         bad = true;
     182                 :          0 :                         break;
     183                 :            :                     }
     184                 :            : 
     185         [ #  # ]:          0 :                     if (!doclens.empty()) {
     186         [ #  # ]:          0 :                         if (did >= doclens.size()) {
     187                 :          0 :                             cout << "document id " << did << " is larger than any in the termlist table!" << endl;
     188                 :          0 :                             ++errors;
     189         [ #  # ]:          0 :                         } else if (doclens[did] != doclen) {
     190                 :            :                             cout << "document id " << did << ": length " << doclen
     191                 :            :                                  << " doesn't match " << doclens[did]
     192                 :          0 :                                  << " in the termlist table" << endl;
     193                 :          0 :                             ++errors;
     194                 :            :                         }
     195                 :            :                     }
     196                 :            : 
     197         [ #  # ]:          0 :                     if (pos == end) break;
     198                 :            : 
     199                 :            :                     Xapian::docid inc;
     200         [ #  # ]:          0 :                     if (!F_unpack_uint(&pos, end, &inc)) {
     201                 :          0 :                         cout << "Failed to unpack docid increase" << endl;
     202                 :          0 :                         ++errors;
     203                 :          0 :                         bad = true;
     204                 :          0 :                         break;
     205                 :            :                     }
     206                 :          0 :                     ++inc;
     207                 :          0 :                     did += inc;
     208         [ #  # ]:          0 :                     if (did > lastdid) {
     209                 :            :                         cout << "docid " << did << " > last docid " << lastdid
     210                 :          0 :                              << endl;
     211                 :          0 :                         ++errors;
     212                 :            :                     }
     213                 :            :                 }
     214         [ #  # ]:          0 :                 if (bad) {
     215                 :          0 :                     continue;
     216                 :            :                 }
     217         [ #  # ]:          0 :                 if (is_last_chunk) {
     218         [ #  # ]:          0 :                     if (did != lastdid) {
     219                 :            :                         cout << "lastdid " << lastdid << " != last did " << did
     220                 :          0 :                              << endl;
     221                 :          0 :                         ++errors;
     222                 :            :                     }
     223                 :            :                 }
     224                 :            : 
     225                 :          0 :                 continue;
     226                 :            :             }
     227                 :            : 
     228                 :            :             const char * pos, * end;
     229                 :            : 
     230                 :            :             // Get term from key.
     231                 :          0 :             pos = key.data();
     232                 :          0 :             end = pos + key.size();
     233                 :            : 
     234                 :          0 :             string term;
     235                 :          0 :             Xapian::docid did = 0;
     236         [ #  # ]:          0 :             if (!F_unpack_string_preserving_sort(&pos, end, term)) {
     237                 :          0 :                 cout << "Error unpacking termname from key" << endl;
     238                 :          0 :                 ++errors;
     239                 :          0 :                 continue;
     240                 :            :             }
     241         [ #  # ]:          0 :             if (current_term.empty()) {
     242                 :          0 :                 current_term = term;
     243                 :          0 :                 tf = cf = 0;
     244         [ #  # ]:          0 :                 if (pos != end) {
     245                 :            :                     cout << "Extra bytes after key for first chunk of "
     246                 :          0 :                         "posting list for term `" << term << "'" << endl;
     247                 :          0 :                     ++errors;
     248                 :          0 :                     continue;
     249                 :            :                 }
     250                 :            :                 // Unpack extra header from first chunk.
     251                 :          0 :                 cursor->read_tag();
     252                 :          0 :                 pos = cursor->current_tag.data();
     253                 :          0 :                 end = pos + cursor->current_tag.size();
     254         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &termfreq)) {
     255                 :            :                     cout << "Failed to unpack termfreq for term `" << term
     256                 :          0 :                          << "'" << endl;
     257                 :          0 :                     ++errors;
     258                 :          0 :                     continue;
     259                 :            :                 }
     260         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &collfreq)) {
     261                 :            :                     cout << "Failed to unpack collfreq for term `" << term
     262                 :          0 :                          << "'" << endl;
     263                 :          0 :                     ++errors;
     264                 :          0 :                     continue;
     265                 :            :                 }
     266         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &did)) {
     267                 :            :                     cout << "Failed to unpack firstdid for term `" << term
     268                 :          0 :                          << "'" << endl;
     269                 :          0 :                     ++errors;
     270                 :          0 :                     continue;
     271                 :            :                 }
     272                 :          0 :                 ++did;
     273                 :            :             } else {
     274         [ #  # ]:          0 :                 if (term != current_term) {
     275         [ #  # ]:          0 :                     if (pos == end) {
     276                 :            :                         cout << "No last chunk for term `" << term << "'"
     277                 :          0 :                              << endl;
     278                 :            :                     } else {
     279                 :            :                         cout << "Mismatch in follow-on chunk in posting "
     280                 :            :                             "list for term `" << current_term << "' (got `"
     281                 :          0 :                             << term << "')" << endl;
     282                 :            :                     }
     283                 :          0 :                     ++errors;
     284                 :          0 :                     current_term = term;
     285                 :            :                 }
     286         [ #  # ]:          0 :                 if (pos != end) {
     287         [ #  # ]:          0 :                     if (!F_unpack_uint_preserving_sort(&pos, end, &did)) {
     288                 :          0 :                         cout << "Failed to unpack did from key" << endl;
     289                 :          0 :                         ++errors;
     290                 :          0 :                         continue;
     291                 :            :                     }
     292         [ #  # ]:          0 :                     if (did <= lastdid) {
     293                 :            :                         cout << "First did in this chunk is <= last in "
     294                 :          0 :                             "prev chunk" << endl;
     295                 :          0 :                         ++errors;
     296                 :            :                     }
     297                 :            :                 }
     298                 :          0 :                 cursor->read_tag();
     299                 :          0 :                 pos = cursor->current_tag.data();
     300                 :          0 :                 end = pos + cursor->current_tag.size();
     301                 :            :             }
     302                 :            : 
     303                 :            :             bool is_last_chunk;
     304         [ #  # ]:          0 :             if (!F_unpack_bool(&pos, end, &is_last_chunk)) {
     305                 :          0 :                 cout << "Failed to unpack last chunk flag" << endl;
     306                 :          0 :                 ++errors;
     307                 :          0 :                 continue;
     308                 :            :             }
     309                 :            :             // Read what the final document ID in this chunk is.
     310         [ #  # ]:          0 :             if (!F_unpack_uint(&pos, end, &lastdid)) {
     311                 :          0 :                 cout << "Failed to unpack increase to last" << endl;
     312                 :          0 :                 ++errors;
     313                 :          0 :                 continue;
     314                 :            :             }
     315                 :          0 :             ++lastdid;
     316                 :          0 :             lastdid += did;
     317                 :          0 :             bool bad = false;
     318                 :          0 :             while (true) {
     319                 :            :                 Xapian::termcount wdf;
     320         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &wdf)) {
     321                 :          0 :                     cout << "Failed to unpack wdf" << endl;
     322                 :          0 :                     ++errors;
     323                 :          0 :                     bad = true;
     324                 :          0 :                     break;
     325                 :            :                 }
     326                 :          0 :                 ++tf;
     327                 :          0 :                 cf += wdf;
     328                 :            : 
     329                 :            :                 Xapian::termcount doclen;
     330         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &doclen)) {
     331                 :          0 :                     cout << "Failed to unpack doc length" << endl;
     332                 :          0 :                     ++errors;
     333                 :          0 :                     bad = true;
     334                 :          0 :                     break;
     335                 :            :                 }
     336                 :            : 
     337         [ #  # ]:          0 :                 if (!doclens.empty()) {
     338         [ #  # ]:          0 :                     if (did >= doclens.size()) {
     339                 :          0 :                         cout << "document id " << did << " is larger than any in the termlist table!" << endl;
     340         [ #  # ]:          0 :                     } else if (doclens[did] != doclen) {
     341                 :          0 :                         cout << "doclen " << doclen << " doesn't match " << doclens[did] << " in the termlist table" << endl;
     342                 :          0 :                         ++errors;
     343                 :            :                     }
     344                 :            :                 }
     345         [ #  # ]:          0 :                 if (pos == end) break;
     346                 :            : 
     347                 :            :                 Xapian::docid inc;
     348         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &inc)) {
     349                 :          0 :                     cout << "Failed to unpack docid increase" << endl;
     350                 :          0 :                     ++errors;
     351                 :          0 :                     bad = true;
     352                 :          0 :                     break;
     353                 :            :                 }
     354                 :          0 :                 ++inc;
     355                 :          0 :                 did += inc;
     356         [ #  # ]:          0 :                 if (did > lastdid) {
     357                 :            :                     cout << "docid " << did << " > last docid " << lastdid
     358                 :          0 :                          << endl;
     359                 :          0 :                     ++errors;
     360                 :            :                 }
     361                 :            :             }
     362         [ #  # ]:          0 :             if (bad) {
     363                 :          0 :                 continue;
     364                 :            :             }
     365         [ #  # ]:          0 :             if (is_last_chunk) {
     366         [ #  # ]:          0 :                 if (tf != termfreq) {
     367                 :            :                     cout << "termfreq " << termfreq << " != # of entries "
     368                 :          0 :                          << tf << endl;
     369                 :          0 :                     ++errors;
     370                 :            :                 }
     371         [ #  # ]:          0 :                 if (cf != collfreq) {
     372                 :            :                     cout << "collfreq " << collfreq << " != sum wdf " << cf
     373                 :          0 :                          << endl;
     374                 :          0 :                     ++errors;
     375                 :            :                 }
     376         [ #  # ]:          0 :                 if (did != lastdid) {
     377                 :            :                     cout << "lastdid " << lastdid << " != last did " << did
     378                 :          0 :                          << endl;
     379                 :          0 :                     ++errors;
     380                 :            :                 }
     381                 :          0 :                 current_term.resize(0);
     382                 :            :             }
     383                 :            :         }
     384         [ -  + ]:          1 :         if (!current_term.empty()) {
     385                 :            :             cout << "Last term `" << current_term << "' has no last chunk"
     386                 :          0 :                  << endl;
     387                 :          0 :             ++errors;
     388                 :          1 :         }
     389         [ +  + ]:          3 :     } else if (strcmp(tablename, "record") == 0) {
     390                 :            :         // Now check the contents of the record table.  Any data is valid as
     391                 :            :         // the tag so we don't check the tags.
     392         [ -  + ]:          1 :         for ( ; !cursor->after_end(); cursor->next()) {
     393                 :          0 :             string & key = cursor->current_key;
     394                 :            : 
     395                 :            :             // Get docid from key.
     396                 :          0 :             const char * pos = key.data();
     397                 :          0 :             const char * end = pos + key.size();
     398                 :            : 
     399                 :            :             Xapian::docid did;
     400         [ #  # ]:          0 :             if (!F_unpack_uint_preserving_sort(&pos, end, &did)) {
     401                 :          0 :                 cout << "Error unpacking docid from key" << endl;
     402                 :          0 :                 ++errors;
     403         [ #  # ]:          0 :             } else if (pos != end) {
     404                 :          0 :                 cout << "Extra junk in key" << endl;
     405                 :          0 :                 ++errors;
     406                 :            :             }
     407                 :            :         }
     408         [ +  + ]:          2 :     } else if (strcmp(tablename, "termlist") == 0) {
     409                 :            :         // Now check the contents of the termlist table.
     410         [ -  + ]:          1 :         for ( ; !cursor->after_end(); cursor->next()) {
     411                 :          0 :             string & key = cursor->current_key;
     412                 :            : 
     413                 :            :             // Get docid from key.
     414                 :          0 :             const char * pos = key.data();
     415                 :          0 :             const char * end = pos + key.size();
     416                 :            : 
     417                 :            :             Xapian::docid did;
     418         [ #  # ]:          0 :             if (!F_unpack_uint_preserving_sort(&pos, end, &did)) {
     419                 :          0 :                 cout << "Error unpacking docid from key" << endl;
     420                 :          0 :                 ++errors;
     421                 :          0 :                 continue;
     422                 :            :             }
     423                 :            : 
     424         [ #  # ]:          0 :             if (pos != end) {
     425                 :          0 :                 cout << "Extra junk in key" << endl;
     426                 :          0 :                 ++errors;
     427                 :          0 :                 continue;
     428                 :            :             }
     429                 :            : 
     430                 :          0 :             cursor->read_tag();
     431                 :            : 
     432                 :          0 :             pos = cursor->current_tag.data();
     433                 :          0 :             end = pos + cursor->current_tag.size();
     434                 :            : 
     435         [ #  # ]:          0 :             if (pos == end) {
     436                 :            :                 // Empty termlist.
     437                 :          0 :                 continue;
     438                 :            :             }
     439                 :            : 
     440                 :            :             Xapian::termcount doclen, termlist_size;
     441                 :            : 
     442                 :            :             // Read doclen
     443         [ #  # ]:          0 :             if (!F_unpack_uint(&pos, end, &doclen)) {
     444         [ #  # ]:          0 :                 if (pos != 0) {
     445                 :          0 :                     cout << "doclen out of range" << endl;
     446                 :            :                 } else {
     447                 :          0 :                     cout << "Unexpected end of data when reading doclen" << endl;
     448                 :            :                 }
     449                 :          0 :                 ++errors;
     450                 :          0 :                 continue;
     451                 :            :             }
     452                 :            : 
     453                 :            :             // Read termlist_size
     454         [ #  # ]:          0 :             if (!F_unpack_uint(&pos, end, &termlist_size)) {
     455         [ #  # ]:          0 :                 if (pos != 0) {
     456                 :          0 :                     cout << "termlist_size out of range" << endl;
     457                 :            :                 } else {
     458                 :          0 :                     cout << "Unexpected end of data when reading termlist_size" << endl;
     459                 :            :                 }
     460                 :          0 :                 ++errors;
     461                 :          0 :                 continue;
     462                 :            :             }
     463                 :            : 
     464                 :            :             // See comment in FlintTermListTable::set_termlist() in
     465                 :            :             // flint_termlisttable.cc for an explanation of this!
     466 [ #  # ][ #  # ]:          0 :             if (pos != end && *pos == '0') ++pos;
     467                 :            : 
     468                 :          0 :             Xapian::termcount actual_doclen = 0, actual_termlist_size = 0;
     469                 :          0 :             string current_tname;
     470                 :            : 
     471                 :          0 :             bool bad = false;
     472         [ #  # ]:          0 :             while (pos != end) {
     473                 :            :                 // Initialize to silence g++ with -O3
     474                 :          0 :                 Xapian::doccount current_wdf = 0;
     475                 :          0 :                 bool got_wdf = false;
     476                 :            :                 // If there was a previous term, how much to reuse.
     477         [ #  # ]:          0 :                 if (!current_tname.empty()) {
     478                 :          0 :                     string::size_type len = static_cast<unsigned char>(*pos++);
     479         [ #  # ]:          0 :                     if (len > current_tname.length()) {
     480                 :            :                         // The wdf was squeezed into the same byte.
     481                 :          0 :                         current_wdf = len / (current_tname.length() + 1) - 1;
     482                 :          0 :                         len %= (current_tname.length() + 1);
     483                 :          0 :                         got_wdf = true;
     484                 :            :                     }
     485                 :          0 :                     current_tname.resize(len);
     486                 :            :                 }
     487                 :            :                 // What to append (note len must be positive, since just truncating
     488                 :            :                 // always takes us backwards in the sort order)
     489                 :          0 :                 string::size_type len = static_cast<unsigned char>(*pos++);
     490                 :          0 :                 current_tname.append(pos, len);
     491                 :          0 :                 pos += len;
     492                 :            : 
     493         [ #  # ]:          0 :                 if (!got_wdf) {
     494                 :            :                     // Read wdf
     495         [ #  # ]:          0 :                     if (!F_unpack_uint(&pos, end, &current_wdf)) {
     496         [ #  # ]:          0 :                         if (pos == 0) {
     497                 :          0 :                             cout << "Unexpected end of data when reading termlist current_wdf" << endl;
     498                 :            :                         } else {
     499                 :          0 :                             cout << "Size of wdf out of range, in termlist" << endl;
     500                 :            :                         }
     501                 :          0 :                         ++errors;
     502                 :          0 :                         bad = true;
     503                 :          0 :                         break;
     504                 :            :                     }
     505                 :            :                 }
     506                 :            : 
     507                 :          0 :                 ++actual_termlist_size;
     508                 :          0 :                 actual_doclen += current_wdf;
     509                 :            :             }
     510         [ #  # ]:          0 :             if (bad) {
     511                 :          0 :                 continue;
     512                 :            :             }
     513                 :            : 
     514         [ #  # ]:          0 :             if (termlist_size != actual_termlist_size) {
     515                 :          0 :                 cout << "termlist_size != # of entries in termlist" << endl;
     516                 :          0 :                 ++errors;
     517                 :            :             }
     518         [ #  # ]:          0 :             if (doclen != actual_doclen) {
     519                 :          0 :                 cout << "doclen != sum(wdf)" << endl;
     520                 :          0 :                 ++errors;
     521                 :            :             }
     522                 :            : 
     523                 :            :             // + 1 so that did is a valid subscript.
     524         [ #  # ]:          0 :             if (doclens.size() <= did) doclens.resize(did + 1);
     525                 :          0 :             doclens[did] = actual_doclen;
     526                 :            :         }
     527         [ +  - ]:          1 :     } else if (strcmp(tablename, "value") == 0) {
     528                 :            :         // Now check the contents of the value table.
     529         [ -  + ]:          1 :         for ( ; !cursor->after_end(); cursor->next()) {
     530                 :          0 :             string & key = cursor->current_key;
     531                 :            : 
     532                 :            :             // Get docid from key.
     533                 :          0 :             const char * pos = key.data();
     534                 :          0 :             const char * end = pos + key.size();
     535                 :            : 
     536                 :            :             Xapian::docid did;
     537         [ #  # ]:          0 :             if (!F_unpack_uint_preserving_sort(&pos, end, &did)) {
     538                 :          0 :                 cout << "Error unpacking docid from key" << endl;
     539                 :          0 :                 ++errors;
     540         [ #  # ]:          0 :             } else if (pos != end) {
     541                 :          0 :                 cout << "Extra junk in key" << endl;
     542                 :          0 :                 ++errors;
     543                 :            :             }
     544                 :            : 
     545                 :          0 :             cursor->read_tag();
     546                 :            : 
     547                 :          0 :             pos = cursor->current_tag.data();
     548                 :          0 :             end = pos + cursor->current_tag.size();
     549                 :            : 
     550                 :          0 :             bool first = true;
     551                 :          0 :             Xapian::valueno last_value_no = 0;
     552 [ #  # ][ #  # ]:          0 :             while (pos && pos != end) {
         [ #  # ][ #  # ]
     553                 :            :                 Xapian::valueno this_value_no;
     554                 :          0 :                 string this_value;
     555                 :            : 
     556         [ #  # ]:          0 :                 if (!F_unpack_uint(&pos, end, &this_value_no)) {
     557         [ #  # ]:          0 :                     if (pos == 0)
     558                 :          0 :                         cout << "Incomplete item in value table" << endl;
     559                 :            :                     else
     560                 :          0 :                         cout << "Value number in value table is too large" << endl;
     561                 :          0 :                     ++errors;
     562                 :            :                     break;
     563                 :            :                 }
     564                 :            : 
     565         [ #  # ]:          0 :                 if (!F_unpack_string(&pos, end, this_value)) {
     566         [ #  # ]:          0 :                     if (pos == 0)
     567                 :          0 :                         cout << "Incomplete item in value table" << endl;
     568                 :            :                     else
     569                 :          0 :                         cout << "Item in value table is too large" << endl;
     570                 :          0 :                     ++errors;
     571                 :            :                     break;
     572                 :            :                 }
     573                 :            : 
     574         [ #  # ]:          0 :                 if (first) {
     575                 :          0 :                     first = false;
     576         [ #  # ]:          0 :                 } else if (this_value_no <= last_value_no) {
     577                 :          0 :                     cout << "Values not in sorted order - valueno " << last_value_no << " comes before valueno " << this_value_no << endl;
     578                 :          0 :                     ++errors;
     579                 :            :                 }
     580                 :          0 :                 last_value_no = this_value_no;
     581                 :            :             }
     582                 :            :         }
     583         [ #  # ]:          0 :     } else if (strcmp(tablename, "position") == 0) {
     584                 :            :         // Now check the contents of the position table.
     585         [ #  # ]:          0 :         for ( ; !cursor->after_end(); cursor->next()) {
     586                 :          0 :             string & key = cursor->current_key;
     587                 :            : 
     588                 :            :             // Get docid from key.
     589                 :          0 :             const char * pos = key.data();
     590                 :          0 :             const char * end = pos + key.size();
     591                 :            : 
     592                 :            :             Xapian::docid did;
     593         [ #  # ]:          0 :             if (!F_unpack_uint_preserving_sort(&pos, end, &did)) {
     594                 :          0 :                 cout << "Error unpacking docid from key" << endl;
     595                 :          0 :                 ++errors;
     596                 :          0 :                 continue;
     597                 :            :             }
     598         [ #  # ]:          0 :             if (pos == end) {
     599                 :          0 :                 cout << "No termname in key" << endl;
     600                 :          0 :                 ++errors;
     601                 :          0 :                 continue;
     602                 :            :             }
     603                 :            : 
     604                 :          0 :             cursor->read_tag();
     605                 :            : 
     606                 :          0 :             const string & data = cursor->current_tag;
     607                 :          0 :             pos = data.data();
     608                 :          0 :             end = pos + data.size();
     609                 :            : 
     610                 :            :             Xapian::termpos pos_last;
     611         [ #  # ]:          0 :             if (!F_unpack_uint(&pos, end, &pos_last)) {
     612                 :          0 :                 cout << tablename << " table: Position list data corrupt" << endl;
     613                 :          0 :                 ++errors;
     614                 :          0 :                 continue;
     615                 :            :             }
     616         [ #  # ]:          0 :             if (pos == end) {
     617                 :            :                 // Special case for single entry position list.
     618                 :            :             } else {
     619                 :            :                 // Skip the header we just read.
     620                 :          0 :                 BitReader rd(data, pos - data.data());
     621                 :          0 :                 Xapian::termpos pos_first = rd.decode(pos_last);
     622                 :          0 :                 Xapian::termpos pos_size = rd.decode(pos_last - pos_first) + 2;
     623                 :          0 :                 vector<Xapian::termpos> positions;
     624                 :          0 :                 positions.resize(pos_size);
     625                 :          0 :                 positions[0] = pos_first;
     626                 :          0 :                 positions.back() = pos_last;
     627                 :          0 :                 rd.decode_interpolative(positions, 0, pos_size - 1);
     628                 :          0 :                 vector<Xapian::termpos>::const_iterator current_pos = positions.begin();
     629                 :          0 :                 Xapian::termpos lastpos = *current_pos++;
     630         [ #  # ]:          0 :                 while (current_pos != positions.end()) {
     631                 :          0 :                     Xapian::termpos termpos = *current_pos++;
     632         [ #  # ]:          0 :                     if (termpos <= lastpos) {
     633                 :          0 :                         cout << tablename << " table: Positions not strictly monotonically increasing" << endl;
     634                 :          0 :                         ++errors;
     635                 :          0 :                         break;
     636                 :            :                     }
     637                 :          0 :                     lastpos = termpos;
     638                 :          0 :                 }
     639                 :            :             }
     640                 :            :         }
     641                 :            :     } else {
     642                 :          0 :         cout << tablename << " table: Don't know how to check structure\n" << endl;
     643                 :          0 :         return errors;
     644                 :            :     }
     645                 :            : 
     646         [ +  - ]:          4 :     if (!errors)
     647                 :          4 :         cout << tablename << " table structure checked OK\n" << endl;
     648                 :            :     else
     649                 :          0 :         cout << tablename << " table errors found: " << errors << "\n" << endl;
     650                 :            : 
     651                 :          4 :     return errors;
     652 [ +  - ][ +  - ]:         15 : }

Generated by: LCOV version 1.8