LCOV - code coverage report
Current view: top level - api - compactor.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 170 226 75.2 %
Date: 2011-08-21 Functions: 14 22 63.6 %
Branches: 98 154 63.6 %

           Branch data     Line data    Source code
       1                 :            : /** @file compactor.cc
       2                 :            :  * @brief Compact a database, or merge and compact several.
       3                 :            :  */
       4                 :            : /* Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010,2011 Olly Betts
       5                 :            :  * Copyright (C) 2008 Lemur Consulting Ltd
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      20                 :            :  * USA
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : 
      25                 :            : #include <xapian/compactor.h>
      26                 :            : 
      27                 :            : #include "safeerrno.h"
      28                 :            : 
      29                 :            : #include <algorithm>
      30                 :            : #include <fstream>
      31                 :            : 
      32                 :            : #include <cstdio> // for rename()
      33                 :            : #include <cstdlib>
      34                 :            : #include <cstring>
      35                 :            : #include <ctime>
      36                 :            : #include "safesysstat.h"
      37                 :            : #include <sys/types.h>
      38                 :            : 
      39                 :            : #include "safeunistd.h"
      40                 :            : #include "safefcntl.h"
      41                 :            : 
      42                 :            : #include "noreturn.h"
      43                 :            : #include "omassert.h"
      44                 :            : #include "fileutils.h"
      45                 :            : #ifdef __WIN32__
      46                 :            : # include "msvc_posix_wrapper.h"
      47                 :            : #endif
      48                 :            : #include "stringutils.h"
      49                 :            : #include "str.h"
      50                 :            : #include "utils.h"
      51                 :            : 
      52                 :            : #include "backends/brass/brass_compact.h"
      53                 :            : #include "backends/brass/brass_version.h"
      54                 :            : #include "backends/chert/chert_compact.h"
      55                 :            : #include "backends/chert/chert_version.h"
      56                 :            : #include "backends/flint/flint_compact.h"
      57                 :            : #include "backends/flint/flint_version.h"
      58                 :            : 
      59                 :            : #include <xapian.h>
      60                 :            : 
      61                 :            : using namespace std;
      62                 :            : 
      63                 :            : class CmpByFirstUsed {
      64                 :            :     const vector<pair<Xapian::docid, Xapian::docid> > & used_ranges;
      65                 :            : 
      66                 :            :   public:
      67                 :         24 :     CmpByFirstUsed(const vector<pair<Xapian::docid, Xapian::docid> > & ur)
      68                 :         24 :         : used_ranges(ur) { }
      69                 :            : 
      70                 :         63 :     bool operator()(size_t a, size_t b) {
      71                 :         63 :         return used_ranges[a].first < used_ranges[b].first;
      72                 :            :     }
      73                 :            : };
      74                 :            : 
      75                 :            : static const char * backend_names[] = {
      76                 :            :     NULL,
      77                 :            :     "brass",
      78                 :            :     "chert",
      79                 :            :     "flint"
      80                 :            : };
      81                 :            : 
      82                 :            : enum { STUB_NO, STUB_FILE, STUB_DIR };
      83                 :            : 
      84                 :            : namespace Xapian {
      85                 :            : 
      86                 :         48 : class Compactor::Internal : public Xapian::Internal::RefCntBase {
      87                 :            :     friend class Compactor;
      88                 :            : 
      89                 :            :     string destdir;
      90                 :            :     bool renumber;
      91                 :            :     bool multipass;
      92                 :            :     int compact_to_stub;
      93                 :            :     size_t block_size;
      94                 :            :     compaction_level compaction;
      95                 :            : 
      96                 :            :     Xapian::docid tot_off;
      97                 :            :     Xapian::docid last_docid;
      98                 :            : 
      99                 :            :     enum { UNKNOWN, BRASS, CHERT, FLINT } backend;
     100                 :            : 
     101                 :            :     struct stat sb;
     102                 :            : 
     103                 :            :     string first_source;
     104                 :            : 
     105                 :            :     vector<string> sources;
     106                 :            :     vector<Xapian::docid> offset;
     107                 :            :     vector<pair<Xapian::docid, Xapian::docid> > used_ranges;
     108                 :            :   public:
     109                 :         48 :     Internal()
     110                 :            :         : renumber(true), multipass(false),
     111                 :            :           block_size(8192), compaction(FULL), tot_off(0),
     112                 :         48 :           last_docid(0), backend(UNKNOWN)
     113                 :            :     {
     114                 :         48 :     }
     115                 :            : 
     116                 :            :     void set_destdir(const string & destdir_);
     117                 :            : 
     118                 :            :     void add_source(const string & srcdir);
     119                 :            : 
     120                 :            :     void compact(Xapian::Compactor & compactor);
     121                 :            : };
     122                 :            : 
     123                 :         48 : Compactor::Compactor() : internal(new Compactor::Internal()) { }
     124                 :            : 
     125 [ #  # ][ -  + ]:         48 : Compactor::~Compactor() { }
                 [ #  # ]
     126                 :            : 
     127                 :            : void
     128                 :          0 : Compactor::set_block_size(size_t block_size)
     129                 :            : {
     130                 :          0 :     internal->block_size = block_size;
     131                 :          0 : }
     132                 :            : 
     133                 :            : void
     134                 :         27 : Compactor::set_renumber(bool renumber)
     135                 :            : {
     136                 :         27 :     internal->renumber = renumber;
     137                 :         27 : }
     138                 :            : 
     139                 :            : void
     140                 :          0 : Compactor::set_multipass(bool multipass)
     141                 :            : {
     142                 :          0 :     internal->multipass = multipass;
     143                 :          0 : }
     144                 :            : 
     145                 :            : void
     146                 :          0 : Compactor::set_compaction_level(compaction_level compaction)
     147                 :            : {
     148                 :          0 :     internal->compaction = compaction;
     149                 :          0 : }
     150                 :            : 
     151                 :            : void
     152                 :         48 : Compactor::set_destdir(const string & destdir)
     153                 :            : {
     154                 :         48 :     internal->set_destdir(destdir);
     155                 :         48 : }
     156                 :            : 
     157                 :            : void
     158                 :         93 : Compactor::add_source(const string & srcdir)
     159                 :            : {
     160                 :         93 :     internal->add_source(srcdir);
     161                 :         93 : }
     162                 :            : 
     163                 :            : void
     164                 :         48 : Compactor::compact()
     165                 :            : {
     166                 :         48 :     internal->compact(*this);
     167                 :         33 : }
     168                 :            : 
     169                 :            : void
     170                 :        418 : Compactor::set_status(const string & table, const string & status)
     171                 :            : {
     172                 :            :     (void)table;
     173                 :            :     (void)status;
     174                 :        418 : }
     175                 :            : 
     176                 :            : string
     177                 :          0 : Compactor::resolve_duplicate_metadata(const string & key,
     178                 :            :                                       size_t num_tags, const std::string tags[])
     179                 :            : {
     180                 :            :     (void)key;
     181                 :            :     (void)num_tags;
     182                 :          0 :     return tags[0];
     183                 :            : }
     184                 :            : 
     185                 :            : }
     186                 :            : 
     187                 :            : XAPIAN_NORETURN(
     188                 :            :     static void
     189                 :            :     backend_mismatch(const string &dbpath1, int backend1,
     190                 :            :                      const string &dbpath2, int backend2)
     191                 :            : );
     192                 :            : static void
     193                 :          0 : backend_mismatch(const string &dbpath1, int backend1,
     194                 :            :                  const string &dbpath2, int backend2)
     195                 :            : {
     196                 :          0 :     string msg = "All databases must be the same type ('";
     197                 :          0 :     msg += dbpath1;
     198                 :          0 :     msg += "' is ";
     199                 :          0 :     msg += backend_names[backend1];
     200                 :          0 :     msg += ", but '";
     201                 :          0 :     msg += dbpath2;
     202                 :          0 :     msg += "' is ";
     203                 :          0 :     msg += backend_names[backend2];
     204                 :          0 :     msg += ')';
     205                 :          0 :     throw Xapian::InvalidArgumentError(msg);
     206                 :            : }
     207                 :            : 
     208                 :            : namespace Xapian {
     209                 :            : 
     210                 :            : void
     211                 :         48 : Compactor::Internal::set_destdir(const string & destdir_) {
     212                 :         48 :     destdir = destdir_;
     213                 :         48 :     compact_to_stub = STUB_NO;
     214   [ +  +  +  + ]:         48 :     if (stat(destdir, &sb) == 0 && S_ISREG(sb.st_mode)) {
                 [ +  + ]
     215                 :            :         // Stub file.
     216                 :          3 :         compact_to_stub = STUB_FILE;
     217 [ +  + ][ +  - ]:         45 :     } else if (stat(destdir + "/XAPIANDB", &sb) == 0 && S_ISREG(sb.st_mode)) {
         [ +  - ][ #  # ]
                 [ +  + ]
     218                 :            :         // Stub directory.
     219                 :          3 :         compact_to_stub = STUB_DIR;
     220                 :            :     }
     221                 :         48 : }
     222                 :            : 
     223                 :            : void
     224                 :        117 : Compactor::Internal::add_source(const string & srcdir)
     225                 :            : {
     226                 :            :     // Check destdir isn't the same as any source directory, unless it is a
     227                 :            :     // stub database.
     228 [ +  + ][ -  + ]:        117 :     if (!compact_to_stub && srcdir == destdir) {
                 [ -  + ]
     229                 :          0 :         throw Xapian::InvalidArgumentError("destination may not be the same as any source directory, unless it is a stub database");
     230                 :            :     }
     231                 :            : 
     232         [ +  - ]:        117 :     if (stat(srcdir, &sb) == 0) {
     233                 :        117 :         bool is_stub = false;
     234                 :        117 :         string file = srcdir;
     235         [ +  + ]:        117 :         if (S_ISREG(sb.st_mode)) {
     236                 :            :             // Stub database file.
     237                 :          6 :             is_stub = true;
     238         [ +  - ]:        111 :         } else if (S_ISDIR(sb.st_mode)) {
     239                 :        111 :             file += "/XAPIANDB";
     240   [ +  +  +  - ]:        111 :             if (stat(file.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)) {
                 [ +  + ]
     241                 :            :                 // Stub database directory.
     242                 :          6 :                 is_stub = true;
     243                 :            :             }
     244                 :            :         }
     245         [ +  + ]:        117 :         if (is_stub) {
     246                 :         12 :             ifstream stub(file.c_str());
     247                 :         12 :             string line;
     248                 :         12 :             unsigned int line_no = 0;
     249         [ +  + ]:         36 :             while (getline(stub, line)) {
     250                 :         24 :                 ++line_no;
     251 [ +  - ][ -  + ]:         24 :                 if (line.empty() || line[0] == '#')
                 [ -  + ]
     252                 :          0 :                     continue;
     253                 :         24 :                 string::size_type space = line.find(' ');
     254         [ -  + ]:         24 :                 if (space == string::npos) space = line.size();
     255                 :            : 
     256                 :         24 :                 string type(line, 0, space);
     257                 :         24 :                 line.erase(0, space + 1);
     258                 :            : 
     259   [ -  +  #  # ]:         24 :                 if (type == "auto" || type == "chert" || type == "flint" ||
         [ #  # ][ #  # ]
                 [ +  - ]
     260                 :            :                     type == "brass") {
     261                 :         24 :                     resolve_relative_path(line, file);
     262                 :         24 :                     add_source(line);
     263                 :         24 :                     continue;
     264                 :            :                 }
     265                 :            : 
     266 [ #  # ][ #  # ]:          0 :                 if (type == "remote" || type == "inmemory") {
                 [ #  # ]
     267                 :          0 :                     string msg = "Can't compact stub entry of type '";
     268                 :          0 :                     msg += type;
     269                 :          0 :                     msg += '\'';
     270                 :          0 :                     throw Xapian::InvalidOperationError(msg);
     271                 :            :                 }
     272                 :            : 
     273                 :          0 :                 throw Xapian::DatabaseError("Bad line in stub file");
     274                 :            :             }
     275                 :        117 :             return;
     276         [ +  + ]:        117 :         }
     277                 :            :     }
     278                 :            : 
     279         [ +  + ]:        105 :     if (stat(string(srcdir) + "/iamflint", &sb) == 0) {
     280         [ +  + ]:         35 :         if (backend == UNKNOWN) {
     281                 :         16 :             backend = FLINT;
     282         [ -  + ]:         19 :         } else if (backend != FLINT) {
     283                 :          0 :             backend_mismatch(first_source, backend, srcdir, FLINT);
     284                 :            :         }
     285         [ +  + ]:         70 :     } else if (stat(string(srcdir) + "/iamchert", &sb) == 0) {
     286         [ +  + ]:         35 :         if (backend == UNKNOWN) {
     287                 :         16 :             backend = CHERT;
     288         [ -  + ]:         19 :         } else if (backend != CHERT) {
     289                 :          0 :             backend_mismatch(first_source, backend, srcdir, CHERT);
     290                 :            :         }
     291         [ +  - ]:         35 :     } else if (stat(string(srcdir) + "/iambrass", &sb) == 0) {
     292         [ +  + ]:         35 :         if (backend == UNKNOWN) {
     293                 :         16 :             backend = BRASS;
     294         [ -  + ]:         19 :         } else if (backend != BRASS) {
     295                 :          0 :             backend_mismatch(first_source, backend, srcdir, BRASS);
     296                 :            :         }
     297                 :            :     } else {
     298                 :          0 :         string msg = srcdir;
     299                 :          0 :         msg += ": not a flint, chert or brass database";
     300                 :          0 :         throw Xapian::InvalidArgumentError(msg);
     301                 :            :     }
     302                 :            : 
     303         [ +  + ]:        105 :     if (first_source.empty())
     304                 :         48 :         first_source = srcdir;
     305                 :            : 
     306                 :        105 :     Xapian::Database db(srcdir);
     307                 :        105 :     Xapian::docid first = 0, last = 0;
     308                 :            : 
     309                 :            :     // "Empty" databases might have spelling or synonym data so can't
     310                 :            :     // just be completely ignored.
     311                 :        105 :     Xapian::doccount num_docs = db.get_doccount();
     312         [ +  - ]:        105 :     if (num_docs != 0) {
     313                 :        105 :         Xapian::PostingIterator it = db.postlist_begin(string());
     314                 :            :         // This test should never fail, since db.get_doccount() is
     315                 :            :         // non-zero!
     316                 :            :         Assert(it != db.postlist_end(string()));
     317                 :        105 :         first = *it;
     318                 :            : 
     319   [ +  +  +  - ]:        105 :         if (renumber && first) {
     320                 :            :             // Prune any unused docids off the start of this source
     321                 :            :             // database.
     322                 :            :             //
     323                 :            :             // tot_off could wrap here, but it's unsigned, so that's
     324                 :            :             // OK.
     325                 :         39 :             tot_off -= (first - 1);
     326                 :            :         }
     327                 :            : 
     328                 :            :         // There may be unused documents at the end of the range.
     329                 :            :         // Binary chop using skip_to to find the last actually used
     330                 :            :         // document id.
     331                 :        105 :         last = db.get_lastdocid();
     332                 :        105 :         Xapian::docid last_lbound = first + num_docs - 1;
     333         [ +  + ]:        714 :         while (last_lbound < last) {
     334                 :            :             Xapian::docid mid;
     335                 :        609 :             mid = last_lbound + (last - last_lbound + 1) / 2;
     336                 :        609 :             it.skip_to(mid);
     337         [ +  + ]:        609 :             if (it == db.postlist_end(string())) {
     338                 :        528 :                 last = mid - 1;
     339                 :        528 :                 it = db.postlist_begin(string());
     340                 :        528 :                 continue;
     341                 :            :             }
     342                 :         81 :             last_lbound = *it;
     343                 :        105 :         }
     344                 :            :     }
     345                 :        105 :     offset.push_back(tot_off);
     346         [ +  + ]:        105 :     if (renumber)
     347                 :         39 :         tot_off += last;
     348         [ +  + ]:         66 :     else if (last_docid < db.get_lastdocid())
     349                 :         45 :         last_docid = db.get_lastdocid();
     350                 :        105 :     used_ranges.push_back(make_pair(first, last));
     351                 :            : 
     352                 :        117 :     sources.push_back(string(srcdir) + '/');
     353                 :            : }
     354                 :            : 
     355                 :            : void
     356                 :         48 : Compactor::Internal::compact(Xapian::Compactor & compactor)
     357                 :            : {
     358         [ +  + ]:         48 :     if (renumber)
     359                 :         21 :         last_docid = tot_off;
     360                 :            : 
     361 [ +  + ][ +  + ]:         48 :     if (!renumber && sources.size() > 1) {
                 [ +  + ]
     362                 :            :         // We want to process the sources in ascending order of first
     363                 :            :         // docid.  So we create a vector "order" with ascending integers
     364                 :            :         // and then sort so the indirected order is right.  Then we reorder
     365                 :            :         // the vectors into that order and check the ranges are disjoint.
     366                 :         24 :         vector<size_t> order;
     367                 :         24 :         order.reserve(sources.size());
     368         [ +  + ]:         87 :         for (size_t i = 0; i < sources.size(); ++i)
     369                 :         63 :             order.push_back(i);
     370                 :            : 
     371                 :         24 :         sort(order.begin(), order.end(), CmpByFirstUsed(used_ranges));
     372                 :            : 
     373                 :            :         // Reorder the vectors to be in ascending of first docid, and
     374                 :            :         // set all the offsets to 0.
     375                 :         24 :         vector<string> sources_(sources.size());
     376                 :         24 :         vector<pair<Xapian::docid, Xapian::docid> > used_ranges_;
     377                 :         24 :         used_ranges_.reserve(sources.size());
     378                 :            : 
     379                 :         24 :         Xapian::docid last_start = 0, last_end = 0;
     380         [ +  + ]:         63 :         for (size_t j = 0; j != order.size(); ++j) {
     381                 :         54 :             size_t n = order[j];
     382                 :            : 
     383                 :         54 :             swap(sources_[j], sources[n]);
     384                 :         54 :             used_ranges_.push_back(used_ranges[n]);
     385                 :            : 
     386                 :         54 :             const pair<Xapian::docid, Xapian::docid> p = used_ranges[n];
     387                 :            :             // Skip empty databases.
     388   [ -  +  #  # ]:         54 :             if (p.first == 0 && p.second == 0)
     389                 :          0 :                 continue;
     390                 :            :             // Check for overlap with the previous database's range.
     391         [ +  + ]:         54 :             if (p.first <= last_end) {
     392                 :         15 :                 string msg = "when merging databases, --no-renumber is only currently supported if the databases have disjoint ranges of used document ids: ";
     393                 :         15 :                 msg += sources[order[j - 1]];
     394                 :         15 :                 msg += " has range ";
     395                 :         15 :                 msg += str(last_start);
     396                 :         15 :                 msg += '-';
     397                 :         15 :                 msg += str(last_end);
     398                 :         15 :                 msg += ", ";
     399                 :         15 :                 msg += sources[n];
     400                 :         15 :                 msg += " has range ";
     401                 :         15 :                 msg += str(p.first);
     402                 :         15 :                 msg += '-';
     403                 :         15 :                 msg += str(p.second);
     404                 :         30 :                 throw Xapian::InvalidOperationError(msg);
     405                 :            :             }
     406                 :         39 :             last_start = p.first;
     407                 :         39 :             last_end = p.second;
     408                 :            :         }
     409                 :            : 
     410                 :          9 :         swap(sources, sources_);
     411                 :         54 :         swap(used_ranges, used_ranges_);
     412                 :            :     }
     413                 :            : 
     414                 :         33 :     string stub_file;
     415         [ +  + ]:         33 :     if (compact_to_stub) {
     416                 :          6 :         stub_file = destdir;
     417         [ +  + ]:          6 :         if (compact_to_stub == STUB_DIR) {
     418                 :          3 :             stub_file += "/XAPIANDB";
     419                 :          3 :             destdir += '/';
     420                 :            :         } else {
     421                 :          3 :             destdir += '_';
     422                 :            :         }
     423                 :          6 :         size_t sfx = destdir.size();
     424                 :          6 :         time_t now = time(NULL);
     425                 :          0 :         while (true) {
     426                 :          6 :             destdir.resize(sfx);
     427                 :          6 :             destdir += str(now++);
     428         [ -  + ]:          6 :             if (mkdir(destdir, 0755) == 0)
     429                 :            :                 break;
     430         [ #  # ]:          0 :             if (errno != EEXIST) {
     431                 :          0 :                 string msg = destdir;
     432                 :          0 :                 msg += ": mkdir failed";
     433                 :          0 :                 throw Xapian::DatabaseError(msg, errno);
     434                 :            :             }
     435                 :            :         }
     436                 :            :     } else {
     437                 :            :         // If the destination database directory doesn't exist, create it.
     438         [ -  + ]:         27 :         if (mkdir(destdir, 0755) < 0) {
     439                 :            :             // Check why mkdir failed.  It's ok if the directory already
     440                 :            :             // exists, but we also get EEXIST if there's an existing file with
     441                 :            :             // that name.
     442         [ #  # ]:          0 :             if (errno == EEXIST) {
     443 [ #  # ][ #  # ]:          0 :                 if (stat(destdir, &sb) == 0 && S_ISDIR(sb.st_mode))
                 [ #  # ]
     444                 :          0 :                     errno = 0;
     445                 :            :                 else
     446                 :          0 :                     errno = EEXIST; // stat might have changed it
     447                 :            :             }
     448         [ #  # ]:          0 :             if (errno) {
     449                 :          0 :                 string msg = destdir;
     450                 :          0 :                 msg +=  ": cannot create directory";
     451                 :          0 :                 throw Xapian::DatabaseError(msg, errno);
     452                 :            :             }
     453                 :            :         }
     454                 :            :     }
     455                 :            : 
     456         [ +  + ]:         33 :     if (backend == CHERT) {
     457                 :            : #ifdef XAPIAN_HAS_CHERT_BACKEND
     458                 :            :         compact_chert(compactor, destdir.c_str(), sources, offset, block_size,
     459                 :         11 :                       compaction, multipass, last_docid);
     460                 :            : #else
     461                 :            :         throw Xapian::FeatureUnavailableError("Chert backend disabled at build time");
     462                 :            : #endif
     463         [ +  + ]:         22 :     } else if (backend == BRASS) {
     464                 :            : #ifdef XAPIAN_HAS_BRASS_BACKEND
     465                 :            :         compact_brass(compactor, destdir.c_str(), sources, offset, block_size,
     466                 :         11 :                       compaction, multipass, last_docid);
     467                 :            : #else
     468                 :            :         throw Xapian::FeatureUnavailableError("Brass backend disabled at build time");
     469                 :            : #endif
     470                 :            :     } else {
     471                 :            : #ifdef XAPIAN_HAS_FLINT_BACKEND
     472                 :            :         compact_flint(compactor, destdir.c_str(), sources, offset, block_size,
     473                 :         11 :                       compaction, multipass, last_docid);
     474                 :            : #else
     475                 :            :         throw Xapian::FeatureUnavailableError("Flint backend disabled at build time");
     476                 :            : #endif
     477                 :            :     }
     478                 :            : 
     479                 :            :     // Create the version file ("iamchert", etc).
     480                 :            :     //
     481                 :            :     // This file contains a UUID, and we want the copy to have a fresh
     482                 :            :     // UUID since its revision counter is reset to 1.
     483         [ +  + ]:         33 :     if (backend == CHERT) {
     484                 :            : #ifdef XAPIAN_HAS_CHERT_BACKEND
     485                 :         11 :         ChertVersion(destdir).create();
     486                 :            : #else
     487                 :            :         // Handled above.
     488                 :            :         exit(1);
     489                 :            : #endif
     490         [ +  + ]:         22 :     } else if (backend == BRASS) {
     491                 :            : #ifdef XAPIAN_HAS_BRASS_BACKEND
     492                 :         11 :         BrassVersion(destdir).create();
     493                 :            : #else
     494                 :            :         // Handled above.
     495                 :            :         exit(1);
     496                 :            : #endif
     497                 :            :     } else {
     498                 :            : #ifdef XAPIAN_HAS_FLINT_BACKEND
     499                 :         11 :         FlintVersion(destdir).create();
     500                 :            : #else
     501                 :            :         // Handled above.
     502                 :            :         exit(1);
     503                 :            : #endif
     504                 :            :     }
     505                 :            : 
     506         [ +  + ]:         33 :     if (compact_to_stub) {
     507                 :          6 :         string new_stub_file = destdir;
     508                 :          6 :         new_stub_file += "/new_stub.tmp";
     509                 :            :         {
     510                 :          6 :             ofstream new_stub(new_stub_file.c_str());
     511                 :            : #ifndef __WIN32__
     512                 :          6 :             size_t slash = destdir.find_last_of('/');
     513                 :            : #else
     514                 :            :             size_t slash = destdir.find_last_of("/\\");
     515                 :            : #endif
     516                 :          6 :             new_stub << "auto " << destdir.substr(slash + 1) << '\n';
     517                 :            :         }
     518                 :            : #ifndef __WIN32__
     519         [ -  + ]:          6 :         if (rename(new_stub_file.c_str(), stub_file.c_str()) < 0) {
     520                 :            : #else
     521                 :            :         if (msvc_posix_rename(new_stub_file.c_str(), stub_file.c_str()) < 0) {
     522                 :            : #endif
     523                 :            :             // FIXME: try to clean up?
     524                 :          0 :             string msg = "Cannot rename '";
     525                 :          0 :             msg += new_stub_file;
     526                 :          0 :             msg += "' to '";
     527                 :          0 :             msg += stub_file;
     528                 :          0 :             msg += '\'';
     529                 :          0 :             throw Xapian::DatabaseError(msg, errno);
     530                 :          6 :         }
     531                 :         33 :     }
     532                 :         33 : }
     533                 :            : 
     534                 :            : }
     535                 :            : 

Generated by: LCOV version 1.8