LCOV - code coverage report
Current view: top level - src/leveldb/db - repair.cc (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 253 0
Test Date: 2026-02-04 04:43:42 Functions: 0.0 % 14 0
Branches: 0.0 % 426 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
       2                 :             : // Use of this source code is governed by a BSD-style license that can be
       3                 :             : // found in the LICENSE file. See the AUTHORS file for names of contributors.
       4                 :             : //
       5                 :             : // We recover the contents of the descriptor from the other files we find.
       6                 :             : // (1) Any log files are first converted to tables
       7                 :             : // (2) We scan every table to compute
       8                 :             : //     (a) smallest/largest for the table
       9                 :             : //     (b) largest sequence number in the table
      10                 :             : // (3) We generate descriptor contents:
      11                 :             : //      - log number is set to zero
      12                 :             : //      - next-file-number is set to 1 + largest file number we found
      13                 :             : //      - last-sequence-number is set to largest sequence# found across
      14                 :             : //        all tables (see 2c)
      15                 :             : //      - compaction pointers are cleared
      16                 :             : //      - every table file is added at level 0
      17                 :             : //
      18                 :             : // Possible optimization 1:
      19                 :             : //   (a) Compute total size and use to pick appropriate max-level M
      20                 :             : //   (b) Sort tables by largest sequence# in the table
      21                 :             : //   (c) For each table: if it overlaps earlier table, place in level-0,
      22                 :             : //       else place in level-M.
      23                 :             : // Possible optimization 2:
      24                 :             : //   Store per-table metadata (smallest, largest, largest-seq#, ...)
      25                 :             : //   in the table's meta section to speed up ScanTable.
      26                 :             : 
      27                 :             : #include "db/builder.h"
      28                 :             : #include "db/db_impl.h"
      29                 :             : #include "db/dbformat.h"
      30                 :             : #include "db/filename.h"
      31                 :             : #include "db/log_reader.h"
      32                 :             : #include "db/log_writer.h"
      33                 :             : #include "db/memtable.h"
      34                 :             : #include "db/table_cache.h"
      35                 :             : #include "db/version_edit.h"
      36                 :             : #include "db/write_batch_internal.h"
      37                 :             : #include "leveldb/comparator.h"
      38                 :             : #include "leveldb/db.h"
      39                 :             : #include "leveldb/env.h"
      40                 :             : 
      41                 :             : namespace leveldb {
      42                 :             : 
      43                 :             : namespace {
      44                 :             : 
      45                 :             : class Repairer {
      46                 :             :  public:
      47                 :           0 :   Repairer(const std::string& dbname, const Options& options)
      48         [ #  # ]:           0 :       : dbname_(dbname),
      49                 :           0 :         env_(options.env),
      50         [ #  # ]:           0 :         icmp_(options.comparator),
      51         [ #  # ]:           0 :         ipolicy_(options.filter_policy),
      52         [ #  # ]:           0 :         options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)),
      53                 :           0 :         owns_info_log_(options_.info_log != options.info_log),
      54                 :           0 :         owns_cache_(options_.block_cache != options.block_cache),
      55   [ #  #  #  # ]:           0 :         next_file_number_(1) {
      56                 :             :     // TableCache can be small since we expect each table to be opened once.
      57   [ #  #  #  # ]:           0 :     table_cache_ = new TableCache(dbname_, options_, 10);
      58                 :           0 :   }
      59                 :             : 
      60                 :           0 :   ~Repairer() {
      61         [ #  # ]:           0 :     delete table_cache_;
      62         [ #  # ]:           0 :     if (owns_info_log_) {
      63         [ #  # ]:           0 :       delete options_.info_log;
      64                 :             :     }
      65         [ #  # ]:           0 :     if (owns_cache_) {
      66         [ #  # ]:           0 :       delete options_.block_cache;
      67                 :             :     }
      68                 :           0 :   }
      69                 :             : 
      70                 :           0 :   Status Run() {
      71                 :           0 :     Status status = FindFiles();
      72         [ #  # ]:           0 :     if (status.ok()) {
      73         [ #  # ]:           0 :       ConvertLogFilesToTables();
      74         [ #  # ]:           0 :       ExtractMetaData();
      75   [ #  #  #  # ]:           0 :       status = WriteDescriptor();
      76                 :             :     }
      77         [ #  # ]:           0 :     if (status.ok()) {
      78                 :             :       unsigned long long bytes = 0;
      79   [ #  #  #  # ]:           0 :       for (size_t i = 0; i < tables_.size(); i++) {
      80                 :           0 :         bytes += tables_[i].meta.file_size;
      81                 :             :       }
      82                 :           0 :       Log(options_.info_log,
      83                 :             :           "**** Repaired leveldb %s; "
      84                 :             :           "recovered %d files; %llu bytes. "
      85                 :             :           "Some data may have been lost. "
      86                 :             :           "****",
      87         [ #  # ]:           0 :           dbname_.c_str(), static_cast<int>(tables_.size()), bytes);
      88                 :             :     }
      89                 :           0 :     return status;
      90                 :           0 :   }
      91                 :             : 
      92                 :             :  private:
      93         [ #  # ]:           0 :   struct TableInfo {
      94                 :             :     FileMetaData meta;
      95                 :             :     SequenceNumber max_sequence;
      96                 :             :   };
      97                 :             : 
      98                 :           0 :   Status FindFiles() {
      99                 :           0 :     std::vector<std::string> filenames;
     100         [ #  # ]:           0 :     Status status = env_->GetChildren(dbname_, &filenames);
     101         [ #  # ]:           0 :     if (!status.ok()) {
     102                 :           0 :       return status;
     103                 :             :     }
     104         [ #  # ]:           0 :     if (filenames.empty()) {
     105   [ #  #  #  #  :           0 :       return Status::IOError(dbname_, "repair found no files");
                   #  # ]
     106                 :             :     }
     107                 :             : 
     108                 :             :     uint64_t number;
     109                 :             :     FileType type;
     110   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < filenames.size(); i++) {
     111   [ #  #  #  # ]:           0 :       if (ParseFileName(filenames[i], &number, &type)) {
     112         [ #  # ]:           0 :         if (type == kDescriptorFile) {
     113         [ #  # ]:           0 :           manifests_.push_back(filenames[i]);
     114                 :             :         } else {
     115         [ #  # ]:           0 :           if (number + 1 > next_file_number_) {
     116                 :           0 :             next_file_number_ = number + 1;
     117                 :             :           }
     118         [ #  # ]:           0 :           if (type == kLogFile) {
     119         [ #  # ]:           0 :             logs_.push_back(number);
     120         [ #  # ]:           0 :           } else if (type == kTableFile) {
     121         [ #  # ]:           0 :             table_numbers_.push_back(number);
     122                 :             :           } else {
     123                 :             :             // Ignore other files
     124                 :             :           }
     125                 :             :         }
     126                 :             :       }
     127                 :             :     }
     128                 :           0 :     return status;
     129                 :           0 :   }
     130                 :             : 
     131                 :           0 :   void ConvertLogFilesToTables() {
     132   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < logs_.size(); i++) {
     133                 :           0 :       std::string logname = LogFileName(dbname_, logs_[i]);
     134         [ #  # ]:           0 :       Status status = ConvertLogToTable(logs_[i]);
     135         [ #  # ]:           0 :       if (!status.ok()) {
     136                 :           0 :         Log(options_.info_log, "Log #%llu: ignoring conversion error: %s",
     137   [ #  #  #  # ]:           0 :             (unsigned long long)logs_[i], status.ToString().c_str());
     138                 :             :       }
     139         [ #  # ]:           0 :       ArchiveFile(logname);
     140                 :           0 :     }
     141                 :           0 :   }
     142                 :             : 
     143                 :           0 :   Status ConvertLogToTable(uint64_t log) {
     144                 :           0 :     struct LogReporter : public log::Reader::Reporter {
     145                 :             :       Env* env;
     146                 :             :       Logger* info_log;
     147                 :             :       uint64_t lognum;
     148                 :           0 :       void Corruption(size_t bytes, const Status& s) override {
     149                 :             :         // We print error messages for corruption, but continue repairing.
     150                 :           0 :         Log(info_log, "Log #%llu: dropping %d bytes; %s",
     151         [ #  # ]:           0 :             (unsigned long long)lognum, static_cast<int>(bytes),
     152         [ #  # ]:           0 :             s.ToString().c_str());
     153                 :           0 :       }
     154                 :             :     };
     155                 :             : 
     156                 :             :     // Open the log file
     157                 :           0 :     std::string logname = LogFileName(dbname_, log);
     158                 :           0 :     SequentialFile* lfile;
     159         [ #  # ]:           0 :     Status status = env_->NewSequentialFile(logname, &lfile);
     160         [ #  # ]:           0 :     if (!status.ok()) {
     161                 :             :       return status;
     162                 :             :     }
     163                 :             : 
     164                 :             :     // Create the log reader.
     165         [ #  # ]:           0 :     LogReporter reporter;
     166                 :           0 :     reporter.env = env_;
     167                 :           0 :     reporter.info_log = options_.info_log;
     168                 :           0 :     reporter.lognum = log;
     169                 :             :     // We intentionally make log::Reader do checksumming so that
     170                 :             :     // corruptions cause entire commits to be skipped instead of
     171                 :             :     // propagating bad information (like overly large sequence
     172                 :             :     // numbers).
     173                 :           0 :     log::Reader reader(lfile, &reporter, false /*do not checksum*/,
     174         [ #  # ]:           0 :                        0 /*initial_offset*/);
     175                 :             : 
     176                 :             :     // Read all the records and add to a memtable
     177         [ #  # ]:           0 :     std::string scratch;
     178         [ #  # ]:           0 :     Slice record;
     179         [ #  # ]:           0 :     WriteBatch batch;
     180   [ #  #  #  # ]:           0 :     MemTable* mem = new MemTable(icmp_);
     181                 :           0 :     mem->Ref();
     182                 :           0 :     int counter = 0;
     183   [ #  #  #  # ]:           0 :     while (reader.ReadRecord(&record, &scratch)) {
     184         [ #  # ]:           0 :       if (record.size() < 12) {
     185   [ #  #  #  # ]:           0 :         reporter.Corruption(record.size(),
     186   [ #  #  #  # ]:           0 :                             Status::Corruption("log record too small", logname));
     187                 :           0 :         continue;
     188                 :             :       }
     189         [ #  # ]:           0 :       WriteBatchInternal::SetContents(&batch, record);
     190   [ #  #  #  # ]:           0 :       status = WriteBatchInternal::InsertInto(&batch, mem);
     191         [ #  # ]:           0 :       if (status.ok()) {
     192         [ #  # ]:           0 :         counter += WriteBatchInternal::Count(&batch);
     193                 :             :       } else {
     194         [ #  # ]:           0 :         Log(options_.info_log, "Log #%llu: ignoring %s",
     195         [ #  # ]:           0 :             (unsigned long long)log, status.ToString().c_str());
     196         [ #  # ]:           0 :         status = Status::OK();  // Keep going with rest of file
     197                 :             :       }
     198                 :             :     }
     199         [ #  # ]:           0 :     delete lfile;
     200                 :             : 
     201                 :             :     // Do not record a version edit for this conversion to a Table
     202                 :             :     // since ExtractMetaData() will also generate edits.
     203         [ #  # ]:           0 :     FileMetaData meta;
     204                 :           0 :     meta.number = next_file_number_++;
     205         [ #  # ]:           0 :     Iterator* iter = mem->NewIterator();
     206   [ #  #  #  # ]:           0 :     status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);
     207         [ #  # ]:           0 :     delete iter;
     208                 :           0 :     mem->Unref();
     209                 :           0 :     mem = nullptr;
     210         [ #  # ]:           0 :     if (status.ok()) {
     211         [ #  # ]:           0 :       if (meta.file_size > 0) {
     212         [ #  # ]:           0 :         table_numbers_.push_back(meta.number);
     213                 :             :       }
     214                 :             :     }
     215                 :           0 :     Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s",
     216         [ #  # ]:           0 :         (unsigned long long)log, counter, (unsigned long long)meta.number,
     217         [ #  # ]:           0 :         status.ToString().c_str());
     218                 :           0 :     return status;
     219                 :           0 :   }
     220                 :             : 
     221                 :           0 :   void ExtractMetaData() {
     222   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < table_numbers_.size(); i++) {
     223                 :           0 :       ScanTable(table_numbers_[i]);
     224                 :             :     }
     225                 :           0 :   }
     226                 :             : 
     227                 :           0 :   Iterator* NewTableIterator(const FileMetaData& meta) {
     228                 :             :     // Same as compaction iterators: if paranoid_checks are on, turn
     229                 :             :     // on checksum verification.
     230                 :           0 :     ReadOptions r;
     231                 :           0 :     r.verify_checksums = options_.paranoid_checks;
     232                 :           0 :     return table_cache_->NewIterator(r, meta.number, meta.file_size);
     233                 :             :   }
     234                 :             : 
     235                 :           0 :   void ScanTable(uint64_t number) {
     236         [ #  # ]:           0 :     TableInfo t;
     237                 :           0 :     t.meta.number = number;
     238         [ #  # ]:           0 :     std::string fname = TableFileName(dbname_, number);
     239         [ #  # ]:           0 :     Status status = env_->GetFileSize(fname, &t.meta.file_size);
     240         [ #  # ]:           0 :     if (!status.ok()) {
     241                 :             :       // Try alternate file name.
     242         [ #  # ]:           0 :       fname = SSTTableFileName(dbname_, number);
     243         [ #  # ]:           0 :       Status s2 = env_->GetFileSize(fname, &t.meta.file_size);
     244         [ #  # ]:           0 :       if (s2.ok()) {
     245         [ #  # ]:           0 :         status = Status::OK();
     246                 :             :       }
     247                 :           0 :     }
     248         [ #  # ]:           0 :     if (!status.ok()) {
     249   [ #  #  #  # ]:           0 :       ArchiveFile(TableFileName(dbname_, number));
     250   [ #  #  #  # ]:           0 :       ArchiveFile(SSTTableFileName(dbname_, number));
     251                 :           0 :       Log(options_.info_log, "Table #%llu: dropped: %s",
     252   [ #  #  #  # ]:           0 :           (unsigned long long)t.meta.number, status.ToString().c_str());
     253         [ #  # ]:           0 :       return;
     254                 :             :     }
     255                 :             : 
     256                 :             :     // Extract metadata by scanning through table.
     257                 :           0 :     int counter = 0;
     258         [ #  # ]:           0 :     Iterator* iter = NewTableIterator(t.meta);
     259                 :           0 :     bool empty = true;
     260         [ #  # ]:           0 :     ParsedInternalKey parsed;
     261                 :           0 :     t.max_sequence = 0;
     262   [ #  #  #  #  :           0 :     for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
             #  #  #  # ]
     263         [ #  # ]:           0 :       Slice key = iter->key();
     264         [ #  # ]:           0 :       if (!ParseInternalKey(key, &parsed)) {
     265                 :           0 :         Log(options_.info_log, "Table #%llu: unparsable key %s",
     266   [ #  #  #  # ]:           0 :             (unsigned long long)t.meta.number, EscapeString(key).c_str());
     267                 :           0 :         continue;
     268                 :             :       }
     269                 :             : 
     270                 :           0 :       counter++;
     271         [ #  # ]:           0 :       if (empty) {
     272                 :           0 :         empty = false;
     273         [ #  # ]:           0 :         t.meta.smallest.DecodeFrom(key);
     274                 :             :       }
     275         [ #  # ]:           0 :       t.meta.largest.DecodeFrom(key);
     276         [ #  # ]:           0 :       if (parsed.sequence > t.max_sequence) {
     277                 :           0 :         t.max_sequence = parsed.sequence;
     278                 :             :       }
     279                 :             :     }
     280   [ #  #  #  #  :           0 :     if (!iter->status().ok()) {
                   #  # ]
     281   [ #  #  #  # ]:           0 :       status = iter->status();
     282                 :             :     }
     283         [ #  # ]:           0 :     delete iter;
     284                 :           0 :     Log(options_.info_log, "Table #%llu: %d entries %s",
     285   [ #  #  #  # ]:           0 :         (unsigned long long)t.meta.number, counter, status.ToString().c_str());
     286                 :             : 
     287         [ #  # ]:           0 :     if (status.ok()) {
     288         [ #  # ]:           0 :       tables_.push_back(t);
     289                 :             :     } else {
     290   [ #  #  #  # ]:           0 :       RepairTable(fname, t);  // RepairTable archives input file.
     291                 :             :     }
     292                 :           0 :   }
     293                 :             : 
     294                 :           0 :   void RepairTable(const std::string& src, TableInfo t) {
     295                 :             :     // We will copy src contents to a new table and then rename the
     296                 :             :     // new table over the source.
     297                 :             : 
     298                 :             :     // Create builder.
     299                 :           0 :     std::string copy = TableFileName(dbname_, next_file_number_++);
     300                 :           0 :     WritableFile* file;
     301         [ #  # ]:           0 :     Status s = env_->NewWritableFile(copy, &file);
     302         [ #  # ]:           0 :     if (!s.ok()) {
     303                 :           0 :       return;
     304                 :             :     }
     305   [ #  #  #  # ]:           0 :     TableBuilder* builder = new TableBuilder(options_, file);
     306                 :             : 
     307                 :             :     // Copy data.
     308         [ #  # ]:           0 :     Iterator* iter = NewTableIterator(t.meta);
     309                 :           0 :     int counter = 0;
     310   [ #  #  #  #  :           0 :     for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
                   #  # ]
     311   [ #  #  #  #  :           0 :       builder->Add(iter->key(), iter->value());
                   #  # ]
     312         [ #  # ]:           0 :       counter++;
     313                 :             :     }
     314         [ #  # ]:           0 :     delete iter;
     315                 :             : 
     316         [ #  # ]:           0 :     ArchiveFile(src);
     317         [ #  # ]:           0 :     if (counter == 0) {
     318         [ #  # ]:           0 :       builder->Abandon();  // Nothing to save
     319                 :             :     } else {
     320   [ #  #  #  # ]:           0 :       s = builder->Finish();
     321         [ #  # ]:           0 :       if (s.ok()) {
     322         [ #  # ]:           0 :         t.meta.file_size = builder->FileSize();
     323                 :             :       }
     324                 :             :     }
     325         [ #  # ]:           0 :     delete builder;
     326                 :           0 :     builder = nullptr;
     327                 :             : 
     328         [ #  # ]:           0 :     if (s.ok()) {
     329   [ #  #  #  # ]:           0 :       s = file->Close();
     330                 :             :     }
     331         [ #  # ]:           0 :     delete file;
     332                 :           0 :     file = nullptr;
     333                 :             : 
     334   [ #  #  #  # ]:           0 :     if (counter > 0 && s.ok()) {
     335         [ #  # ]:           0 :       std::string orig = TableFileName(dbname_, t.meta.number);
     336   [ #  #  #  # ]:           0 :       s = env_->RenameFile(copy, orig);
     337         [ #  # ]:           0 :       if (s.ok()) {
     338                 :           0 :         Log(options_.info_log, "Table #%llu: %d entries repaired",
     339         [ #  # ]:           0 :             (unsigned long long)t.meta.number, counter);
     340         [ #  # ]:           0 :         tables_.push_back(t);
     341                 :             :       }
     342                 :           0 :     }
     343         [ #  # ]:           0 :     if (!s.ok()) {
     344         [ #  # ]:           0 :       env_->DeleteFile(copy);
     345                 :             :     }
     346                 :           0 :   }
     347                 :             : 
     348                 :           0 :   Status WriteDescriptor() {
     349                 :           0 :     std::string tmp = TempFileName(dbname_, 1);
     350                 :           0 :     WritableFile* file;
     351         [ #  # ]:           0 :     Status status = env_->NewWritableFile(tmp, &file);
     352         [ #  # ]:           0 :     if (!status.ok()) {
     353                 :             :       return status;
     354                 :             :     }
     355                 :             : 
     356                 :             :     SequenceNumber max_sequence = 0;
     357   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < tables_.size(); i++) {
     358         [ #  # ]:           0 :       if (max_sequence < tables_[i].max_sequence) {
     359                 :           0 :         max_sequence = tables_[i].max_sequence;
     360                 :             :       }
     361                 :             :     }
     362                 :             : 
     363   [ #  #  #  # ]:           0 :     edit_.SetComparatorName(icmp_.user_comparator()->Name());
     364                 :           0 :     edit_.SetLogNumber(0);
     365                 :           0 :     edit_.SetNextFile(next_file_number_);
     366                 :           0 :     edit_.SetLastSequence(max_sequence);
     367                 :             : 
     368   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < tables_.size(); i++) {
     369                 :             :       // TODO(opt): separate out into multiple levels
     370         [ #  # ]:           0 :       const TableInfo& t = tables_[i];
     371                 :           0 :       edit_.AddFile(0, t.meta.number, t.meta.file_size, t.meta.smallest,
     372         [ #  # ]:           0 :                     t.meta.largest);
     373                 :             :     }
     374                 :             : 
     375                 :             :     // fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str());
     376                 :           0 :     {
     377         [ #  # ]:           0 :       log::Writer log(file);
     378         [ #  # ]:           0 :       std::string record;
     379         [ #  # ]:           0 :       edit_.EncodeTo(&record);
     380   [ #  #  #  #  :           0 :       status = log.AddRecord(record);
                   #  # ]
     381                 :           0 :     }
     382         [ #  # ]:           0 :     if (status.ok()) {
     383   [ #  #  #  # ]:           0 :       status = file->Close();
     384                 :             :     }
     385         [ #  # ]:           0 :     delete file;
     386                 :           0 :     file = nullptr;
     387                 :             : 
     388         [ #  # ]:           0 :     if (!status.ok()) {
     389         [ #  # ]:           0 :       env_->DeleteFile(tmp);
     390                 :             :     } else {
     391                 :             :       // Discard older manifests
     392   [ #  #  #  # ]:           0 :       for (size_t i = 0; i < manifests_.size(); i++) {
     393   [ #  #  #  #  :           0 :         ArchiveFile(dbname_ + "/" + manifests_[i]);
                   #  # ]
     394                 :             :       }
     395                 :             : 
     396                 :             :       // Install new manifest
     397   [ #  #  #  #  :           0 :       status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1));
                   #  # ]
     398         [ #  # ]:           0 :       if (status.ok()) {
     399   [ #  #  #  # ]:           0 :         status = SetCurrentFile(env_, dbname_, 1);
     400                 :             :       } else {
     401         [ #  # ]:           0 :         env_->DeleteFile(tmp);
     402                 :             :       }
     403                 :             :     }
     404                 :             :     return status;
     405                 :           0 :   }
     406                 :             : 
     407                 :           0 :   void ArchiveFile(const std::string& fname) {
     408                 :             :     // Move into another directory.  E.g., for
     409                 :             :     //    dir/foo
     410                 :             :     // rename to
     411                 :             :     //    dir/lost/foo
     412         [ #  # ]:           0 :     const char* slash = strrchr(fname.c_str(), '/');
     413         [ #  # ]:           0 :     std::string new_dir;
     414         [ #  # ]:           0 :     if (slash != nullptr) {
     415         [ #  # ]:           0 :       new_dir.assign(fname.data(), slash - fname.data());
     416                 :             :     }
     417         [ #  # ]:           0 :     new_dir.append("/lost");
     418         [ #  # ]:           0 :     env_->CreateDir(new_dir);  // Ignore error
     419         [ #  # ]:           0 :     std::string new_file = new_dir;
     420         [ #  # ]:           0 :     new_file.append("/");
     421   [ #  #  #  # ]:           0 :     new_file.append((slash == nullptr) ? fname.c_str() : slash + 1);
     422         [ #  # ]:           0 :     Status s = env_->RenameFile(fname, new_file);
     423         [ #  # ]:           0 :     Log(options_.info_log, "Archiving %s: %s\n", fname.c_str(),
     424   [ #  #  #  # ]:           0 :         s.ToString().c_str());
     425                 :           0 :   }
     426                 :             : 
     427                 :             :   const std::string dbname_;
     428                 :             :   Env* const env_;
     429                 :             :   InternalKeyComparator const icmp_;
     430                 :             :   InternalFilterPolicy const ipolicy_;
     431                 :             :   const Options options_;
     432                 :             :   bool owns_info_log_;
     433                 :             :   bool owns_cache_;
     434                 :             :   TableCache* table_cache_;
     435                 :             :   VersionEdit edit_;
     436                 :             : 
     437                 :             :   std::vector<std::string> manifests_;
     438                 :             :   std::vector<uint64_t> table_numbers_;
     439                 :             :   std::vector<uint64_t> logs_;
     440                 :             :   std::vector<TableInfo> tables_;
     441                 :             :   uint64_t next_file_number_;
     442                 :             : };
     443                 :             : }  // namespace
     444                 :             : 
     445                 :           0 : Status RepairDB(const std::string& dbname, const Options& options) {
     446                 :           0 :   Repairer repairer(dbname, options);
     447         [ #  # ]:           0 :   return repairer.Run();
     448                 :           0 : }
     449                 :             : 
     450                 :             : }  // namespace leveldb
        

Generated by: LCOV version 2.0-1