作者: 谢瑞阳 10225101483 徐翔宇 10225101535
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.

254 lines
7.6 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. #include "db/log_reader.h"
  5. #include "leveldb/env.h"
  6. #include "util/coding.h"
  7. #include "util/crc32c.h"
  8. namespace leveldb {
  9. namespace log {
  10. Reader::Reporter::~Reporter() {
  11. }
  12. Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum,
  13. uint64_t initial_offset)
  14. : file_(file),
  15. reporter_(reporter),
  16. checksum_(checksum),
  17. backing_store_(new char[kBlockSize]),
  18. buffer_(),
  19. eof_(false),
  20. last_record_offset_(0),
  21. end_of_buffer_offset_(0),
  22. initial_offset_(initial_offset) {
  23. }
  24. Reader::~Reader() {
  25. delete[] backing_store_;
  26. }
  27. bool Reader::SkipToInitialBlock() {
  28. size_t offset_in_block = initial_offset_ % kBlockSize;
  29. uint64_t block_start_location = initial_offset_ - offset_in_block;
  30. // Don't search a block if we'd be in the trailer
  31. if (offset_in_block > kBlockSize - 6) {
  32. offset_in_block = 0;
  33. block_start_location += kBlockSize;
  34. }
  35. end_of_buffer_offset_ = block_start_location;
  36. // Skip to start of first block that can contain the initial record
  37. if (block_start_location > 0) {
  38. Status skip_status = file_->Skip(block_start_location);
  39. if (!skip_status.ok()) {
  40. ReportDrop(block_start_location, skip_status);
  41. return false;
  42. }
  43. }
  44. return true;
  45. }
  46. bool Reader::ReadRecord(Slice* record, std::string* scratch) {
  47. if (last_record_offset_ < initial_offset_) {
  48. if (!SkipToInitialBlock()) {
  49. return false;
  50. }
  51. }
  52. scratch->clear();
  53. record->clear();
  54. bool in_fragmented_record = false;
  55. // Record offset of the logical record that we're reading
  56. // 0 is a dummy value to make compilers happy
  57. uint64_t prospective_record_offset = 0;
  58. Slice fragment;
  59. while (true) {
  60. uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size();
  61. switch (ReadPhysicalRecord(&fragment)) {
  62. case kFullType:
  63. if (in_fragmented_record) {
  64. // Handle bug in earlier versions of log::Writer where
  65. // it could emit an empty kFirstType record at the tail end
  66. // of a block followed by a kFullType or kFirstType record
  67. // at the beginning of the next block.
  68. if (scratch->empty()) {
  69. in_fragmented_record = false;
  70. } else {
  71. ReportCorruption(scratch->size(), "partial record without end(1)");
  72. }
  73. }
  74. prospective_record_offset = physical_record_offset;
  75. scratch->clear();
  76. *record = fragment;
  77. last_record_offset_ = prospective_record_offset;
  78. return true;
  79. case kFirstType:
  80. if (in_fragmented_record) {
  81. // Handle bug in earlier versions of log::Writer where
  82. // it could emit an empty kFirstType record at the tail end
  83. // of a block followed by a kFullType or kFirstType record
  84. // at the beginning of the next block.
  85. if (scratch->empty()) {
  86. in_fragmented_record = false;
  87. } else {
  88. ReportCorruption(scratch->size(), "partial record without end(2)");
  89. }
  90. }
  91. prospective_record_offset = physical_record_offset;
  92. scratch->assign(fragment.data(), fragment.size());
  93. in_fragmented_record = true;
  94. break;
  95. case kMiddleType:
  96. if (!in_fragmented_record) {
  97. ReportCorruption(fragment.size(),
  98. "missing start of fragmented record(1)");
  99. } else {
  100. scratch->append(fragment.data(), fragment.size());
  101. }
  102. break;
  103. case kLastType:
  104. if (!in_fragmented_record) {
  105. ReportCorruption(fragment.size(),
  106. "missing start of fragmented record(2)");
  107. } else {
  108. scratch->append(fragment.data(), fragment.size());
  109. *record = Slice(*scratch);
  110. last_record_offset_ = prospective_record_offset;
  111. return true;
  112. }
  113. break;
  114. case kEof:
  115. if (in_fragmented_record) {
  116. ReportCorruption(scratch->size(), "partial record without end(3)");
  117. scratch->clear();
  118. }
  119. return false;
  120. case kBadRecord:
  121. if (in_fragmented_record) {
  122. ReportCorruption(scratch->size(), "error in middle of record");
  123. in_fragmented_record = false;
  124. scratch->clear();
  125. }
  126. break;
  127. default:
  128. ReportCorruption(
  129. (fragment.size() + (in_fragmented_record ? scratch->size() : 0)),
  130. "unknown record type");
  131. in_fragmented_record = false;
  132. scratch->clear();
  133. break;
  134. }
  135. }
  136. return false;
  137. }
  138. uint64_t Reader::LastRecordOffset() {
  139. return last_record_offset_;
  140. }
  141. void Reader::ReportCorruption(size_t bytes, const char* reason) {
  142. ReportDrop(bytes, Status::Corruption(reason));
  143. }
  144. void Reader::ReportDrop(size_t bytes, const Status& reason) {
  145. if (reporter_ != NULL &&
  146. end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) {
  147. reporter_->Corruption(bytes, reason);
  148. }
  149. }
  150. unsigned int Reader::ReadPhysicalRecord(Slice* result) {
  151. while (true) {
  152. if (buffer_.size() < kHeaderSize) {
  153. if (!eof_) {
  154. // Last read was a full read, so this is a trailer to skip
  155. buffer_.clear();
  156. Status status = file_->Read(kBlockSize, &buffer_, backing_store_);
  157. end_of_buffer_offset_ += buffer_.size();
  158. if (!status.ok()) {
  159. buffer_.clear();
  160. ReportDrop(kBlockSize, status);
  161. eof_ = true;
  162. return kEof;
  163. } else if (buffer_.size() < kBlockSize) {
  164. eof_ = true;
  165. }
  166. continue;
  167. } else if (buffer_.size() == 0) {
  168. // End of file
  169. return kEof;
  170. } else {
  171. size_t drop_size = buffer_.size();
  172. buffer_.clear();
  173. ReportCorruption(drop_size, "truncated record at end of file");
  174. return kEof;
  175. }
  176. }
  177. // Parse the header
  178. const char* header = buffer_.data();
  179. const uint32_t a = static_cast<uint32_t>(header[4]) & 0xff;
  180. const uint32_t b = static_cast<uint32_t>(header[5]) & 0xff;
  181. const unsigned int type = header[6];
  182. const uint32_t length = a | (b << 8);
  183. if (kHeaderSize + length > buffer_.size()) {
  184. size_t drop_size = buffer_.size();
  185. buffer_.clear();
  186. ReportCorruption(drop_size, "bad record length");
  187. return kBadRecord;
  188. }
  189. // Check crc
  190. if (checksum_) {
  191. if (type == kZeroType && length == 0) {
  192. // Skip zero length record without reporting any drops since
  193. // such records are produced by the mmap based writing code in
  194. // env_posix.cc that preallocates file regions.
  195. buffer_.clear();
  196. return kBadRecord;
  197. }
  198. uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header));
  199. uint32_t actual_crc = crc32c::Value(header + 6, 1 + length);
  200. if (actual_crc != expected_crc) {
  201. // Drop the rest of the buffer since "length" itself may have
  202. // been corrupted and if we trust it, we could find some
  203. // fragment of a real log record that just happens to look
  204. // like a valid log record.
  205. size_t drop_size = buffer_.size();
  206. buffer_.clear();
  207. ReportCorruption(drop_size, "checksum mismatch");
  208. return kBadRecord;
  209. }
  210. }
  211. buffer_.remove_prefix(kHeaderSize + length);
  212. // Skip physical record that started before initial_offset_
  213. if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length <
  214. initial_offset_) {
  215. result->clear();
  216. return kBadRecord;
  217. }
  218. *result = Slice(header + kHeaderSize, length);
  219. return type;
  220. }
  221. }
  222. }
  223. }