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