作者: 韩晨旭 10225101440 李畅 10225102463
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
11 KiB

  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. #include "db/builder.h"
  27. #include "db/db_impl.h"
  28. #include "db/dbformat.h"
  29. #include "db/filename.h"
  30. #include "db/log_reader.h"
  31. #include "db/log_writer.h"
  32. #include "db/memtable.h"
  33. #include "db/table_cache.h"
  34. #include "db/version_edit.h"
  35. #include "db/write_batch_internal.h"
  36. #include "leveldb/comparator.h"
  37. #include "leveldb/db.h"
  38. #include "leveldb/env.h"
  39. namespace leveldb {
  40. namespace {
  41. class Repairer {
  42. public:
  43. Repairer(const std::string& dbname, const Options& options)
  44. : dbname_(dbname),
  45. env_(options.env),
  46. icmp_(options.comparator),
  47. options_(SanitizeOptions(dbname, &icmp_, options)),
  48. owns_info_log_(options_.info_log != options.info_log),
  49. next_file_number_(1) {
  50. // TableCache can be small since we expect each table to be opened once.
  51. table_cache_ = new TableCache(dbname_, &options_, 10);
  52. }
  53. ~Repairer() {
  54. delete table_cache_;
  55. if (owns_info_log_) {
  56. delete options_.info_log;
  57. }
  58. }
  59. Status Run() {
  60. Status status = FindFiles();
  61. if (status.ok()) {
  62. ConvertLogFilesToTables();
  63. ExtractMetaData();
  64. status = WriteDescriptor();
  65. }
  66. if (status.ok()) {
  67. unsigned long long bytes = 0;
  68. for (size_t i = 0; i < tables_.size(); i++) {
  69. bytes += tables_[i].meta.file_size;
  70. }
  71. Log(env_, options_.info_log,
  72. "**** Repaired leveldb %s; "
  73. "recovered %d files; %llu bytes. "
  74. "Some data may have been lost. "
  75. "****",
  76. dbname_.c_str(),
  77. static_cast<int>(tables_.size()),
  78. bytes);
  79. }
  80. return status;
  81. }
  82. private:
  83. struct TableInfo {
  84. FileMetaData meta;
  85. SequenceNumber max_sequence;
  86. };
  87. std::string const dbname_;
  88. Env* const env_;
  89. InternalKeyComparator const icmp_;
  90. Options const options_;
  91. bool owns_info_log_;
  92. TableCache* table_cache_;
  93. VersionEdit edit_;
  94. std::vector<std::string> manifests_;
  95. std::vector<uint64_t> table_numbers_;
  96. std::vector<uint64_t> logs_;
  97. std::vector<TableInfo> tables_;
  98. uint64_t next_file_number_;
  99. Status FindFiles() {
  100. std::vector<std::string> filenames;
  101. Status status = env_->GetChildren(dbname_, &filenames);
  102. if (!status.ok()) {
  103. return status;
  104. }
  105. if (filenames.empty()) {
  106. return Status::IOError(dbname_, "repair found no files");
  107. }
  108. uint64_t number;
  109. FileType type;
  110. for (size_t i = 0; i < filenames.size(); i++) {
  111. if (ParseFileName(filenames[i], &number, &type)) {
  112. if (type == kDescriptorFile) {
  113. manifests_.push_back(filenames[i]);
  114. } else {
  115. if (number + 1 > next_file_number_) {
  116. next_file_number_ = number + 1;
  117. }
  118. if (type == kLogFile) {
  119. logs_.push_back(number);
  120. } else if (type == kTableFile) {
  121. table_numbers_.push_back(number);
  122. } else {
  123. // Ignore other files
  124. }
  125. }
  126. }
  127. }
  128. return status;
  129. }
  130. void ConvertLogFilesToTables() {
  131. for (size_t i = 0; i < logs_.size(); i++) {
  132. std::string logname = LogFileName(dbname_, logs_[i]);
  133. Status status = ConvertLogToTable(logs_[i]);
  134. if (!status.ok()) {
  135. Log(env_, options_.info_log, "Log #%llu: ignoring conversion error: %s",
  136. (unsigned long long) logs_[i],
  137. status.ToString().c_str());
  138. }
  139. ArchiveFile(logname);
  140. }
  141. }
  142. Status ConvertLogToTable(uint64_t log) {
  143. struct LogReporter : public log::Reader::Reporter {
  144. Env* env;
  145. WritableFile* info_log;
  146. uint64_t lognum;
  147. virtual void Corruption(size_t bytes, const Status& s) {
  148. // We print error messages for corruption, but continue repairing.
  149. Log(env, info_log, "Log #%llu: dropping %d bytes; %s",
  150. (unsigned long long) lognum,
  151. static_cast<int>(bytes),
  152. s.ToString().c_str());
  153. }
  154. };
  155. // Open the log file
  156. std::string logname = LogFileName(dbname_, log);
  157. SequentialFile* lfile;
  158. Status status = env_->NewSequentialFile(logname, &lfile);
  159. if (!status.ok()) {
  160. return status;
  161. }
  162. // Create the log reader.
  163. LogReporter reporter;
  164. reporter.env = env_;
  165. reporter.info_log = options_.info_log;
  166. reporter.lognum = log;
  167. // We intentially make log::Reader do checksumming so that
  168. // corruptions cause entire commits to be skipped instead of
  169. // propagating bad information (like overly large sequence
  170. // numbers).
  171. log::Reader reader(lfile, &reporter, false/*do not checksum*/);
  172. // Read all the records and add to a memtable
  173. std::string scratch;
  174. Slice record;
  175. WriteBatch batch;
  176. MemTable mem(icmp_);
  177. int counter = 0;
  178. while (reader.ReadRecord(&record, &scratch)) {
  179. if (record.size() < 12) {
  180. reporter.Corruption(
  181. record.size(), Status::Corruption("log record too small"));
  182. continue;
  183. }
  184. WriteBatchInternal::SetContents(&batch, record);
  185. status = WriteBatchInternal::InsertInto(&batch, &mem);
  186. if (status.ok()) {
  187. counter += WriteBatchInternal::Count(&batch);
  188. } else {
  189. Log(env_, options_.info_log, "Log #%llu: ignoring %s",
  190. (unsigned long long) log,
  191. status.ToString().c_str());
  192. status = Status::OK(); // Keep going with rest of file
  193. }
  194. }
  195. delete lfile;
  196. // We ignore any version edits generated by the conversion to a Table
  197. // since ExtractMetaData() will also generate edits.
  198. VersionEdit skipped;
  199. FileMetaData meta;
  200. meta.number = next_file_number_++;
  201. Iterator* iter = mem.NewIterator();
  202. status = BuildTable(dbname_, env_, options_, table_cache_, iter,
  203. &meta, &skipped);
  204. delete iter;
  205. if (status.ok()) {
  206. if (meta.file_size > 0) {
  207. table_numbers_.push_back(meta.number);
  208. }
  209. }
  210. Log(env_, options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s",
  211. (unsigned long long) log,
  212. counter,
  213. (unsigned long long) meta.number,
  214. status.ToString().c_str());
  215. return status;
  216. }
  217. void ExtractMetaData() {
  218. std::vector<TableInfo> kept;
  219. for (size_t i = 0; i < table_numbers_.size(); i++) {
  220. TableInfo t;
  221. t.meta.number = table_numbers_[i];
  222. Status status = ScanTable(&t);
  223. if (!status.ok()) {
  224. std::string fname = TableFileName(dbname_, table_numbers_[i]);
  225. Log(env_, options_.info_log, "Table #%llu: ignoring %s",
  226. (unsigned long long) table_numbers_[i],
  227. status.ToString().c_str());
  228. ArchiveFile(fname);
  229. } else {
  230. tables_.push_back(t);
  231. }
  232. }
  233. }
  234. Status ScanTable(TableInfo* t) {
  235. std::string fname = TableFileName(dbname_, t->meta.number);
  236. int counter = 0;
  237. Status status = env_->GetFileSize(fname, &t->meta.file_size);
  238. if (status.ok()) {
  239. Iterator* iter = table_cache_->NewIterator(
  240. ReadOptions(), t->meta.number, t->meta.file_size);
  241. bool empty = true;
  242. ParsedInternalKey parsed;
  243. t->max_sequence = 0;
  244. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  245. Slice key = iter->key();
  246. if (!ParseInternalKey(key, &parsed)) {
  247. Log(env_, options_.info_log, "Table #%llu: unparsable key %s",
  248. (unsigned long long) t->meta.number,
  249. EscapeString(key).c_str());
  250. continue;
  251. }
  252. counter++;
  253. if (empty) {
  254. empty = false;
  255. t->meta.smallest.DecodeFrom(key);
  256. }
  257. t->meta.largest.DecodeFrom(key);
  258. if (parsed.sequence > t->max_sequence) {
  259. t->max_sequence = parsed.sequence;
  260. }
  261. }
  262. if (!iter->status().ok()) {
  263. status = iter->status();
  264. }
  265. delete iter;
  266. }
  267. Log(env_, options_.info_log, "Table #%llu: %d entries %s",
  268. (unsigned long long) t->meta.number,
  269. counter,
  270. status.ToString().c_str());
  271. return status;
  272. }
  273. Status WriteDescriptor() {
  274. std::string tmp = TempFileName(dbname_, 1);
  275. WritableFile* file;
  276. Status status = env_->NewWritableFile(tmp, &file);
  277. if (!status.ok()) {
  278. return status;
  279. }
  280. SequenceNumber max_sequence = 0;
  281. for (size_t i = 0; i < tables_.size(); i++) {
  282. if (max_sequence < tables_[i].max_sequence) {
  283. max_sequence = tables_[i].max_sequence;
  284. }
  285. }
  286. edit_.SetComparatorName(icmp_.user_comparator()->Name());
  287. edit_.SetLogNumber(0);
  288. edit_.SetNextFile(next_file_number_);
  289. edit_.SetLastSequence(max_sequence);
  290. for (size_t i = 0; i < tables_.size(); i++) {
  291. // TODO(opt): separate out into multiple levels
  292. const TableInfo& t = tables_[i];
  293. edit_.AddFile(0, t.meta.number, t.meta.file_size,
  294. t.meta.smallest, t.meta.largest);
  295. }
  296. //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str());
  297. {
  298. log::Writer log(file);
  299. std::string record;
  300. edit_.EncodeTo(&record);
  301. status = log.AddRecord(record);
  302. }
  303. if (status.ok()) {
  304. status = file->Close();
  305. }
  306. delete file;
  307. file = NULL;
  308. if (!status.ok()) {
  309. env_->DeleteFile(tmp);
  310. } else {
  311. // Discard older manifests
  312. for (size_t i = 0; i < manifests_.size(); i++) {
  313. ArchiveFile(dbname_ + "/" + manifests_[i]);
  314. }
  315. // Install new manifest
  316. status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1));
  317. if (status.ok()) {
  318. status = SetCurrentFile(env_, dbname_, 1);
  319. } else {
  320. env_->DeleteFile(tmp);
  321. }
  322. }
  323. return status;
  324. }
  325. void ArchiveFile(const std::string& fname) {
  326. // Move into another directory. E.g., for
  327. // dir/foo
  328. // rename to
  329. // dir/lost/foo
  330. const char* slash = strrchr(fname.c_str(), '/');
  331. std::string new_dir;
  332. if (slash != NULL) {
  333. new_dir.assign(fname.data(), slash - fname.data());
  334. }
  335. new_dir.append("/lost");
  336. env_->CreateDir(new_dir); // Ignore error
  337. std::string new_file = new_dir;
  338. new_file.append("/");
  339. new_file.append((slash == NULL) ? fname.c_str() : slash + 1);
  340. Status s = env_->RenameFile(fname, new_file);
  341. Log(env_, options_.info_log, "Archiving %s: %s\n",
  342. fname.c_str(), s.ToString().c_str());
  343. }
  344. };
  345. }
  346. Status RepairDB(const std::string& dbname, const Options& options) {
  347. Repairer repairer(dbname, options);
  348. return repairer.Run();
  349. }
  350. }