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