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.

178 lines
5.0 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 <stdint.h>
  6. #include "include/env.h"
  7. #include "util/coding.h"
  8. #include "util/crc32c.h"
  9. namespace leveldb {
  10. namespace log {
  11. Reader::Reporter::~Reporter() {
  12. }
  13. Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum)
  14. : file_(file),
  15. reporter_(reporter),
  16. checksum_(checksum),
  17. backing_store_(new char[kBlockSize]),
  18. buffer_(),
  19. eof_(false) {
  20. }
  21. Reader::~Reader() {
  22. delete[] backing_store_;
  23. }
  24. bool Reader::ReadRecord(Slice* record, std::string* scratch) {
  25. scratch->clear();
  26. record->clear();
  27. bool in_fragmented_record = false;
  28. Slice fragment;
  29. while (true) {
  30. switch (ReadPhysicalRecord(&fragment)) {
  31. case kFullType:
  32. if (in_fragmented_record) {
  33. ReportDrop(scratch->size(), "partial record without end");
  34. }
  35. scratch->clear();
  36. *record = fragment;
  37. return true;
  38. case kFirstType:
  39. if (in_fragmented_record) {
  40. ReportDrop(scratch->size(), "partial record without end");
  41. }
  42. scratch->assign(fragment.data(), fragment.size());
  43. in_fragmented_record = true;
  44. break;
  45. case kMiddleType:
  46. if (!in_fragmented_record) {
  47. ReportDrop(fragment.size(), "missing start of fragmented record");
  48. } else {
  49. scratch->append(fragment.data(), fragment.size());
  50. }
  51. break;
  52. case kLastType:
  53. if (!in_fragmented_record) {
  54. ReportDrop(fragment.size(), "missing start of fragmented record");
  55. } else {
  56. scratch->append(fragment.data(), fragment.size());
  57. *record = Slice(*scratch);
  58. return true;
  59. }
  60. break;
  61. case kEof:
  62. if (in_fragmented_record) {
  63. ReportDrop(scratch->size(), "partial record without end");
  64. scratch->clear();
  65. }
  66. return false;
  67. case kBadRecord:
  68. if (in_fragmented_record) {
  69. ReportDrop(scratch->size(), "error in middle of record");
  70. in_fragmented_record = false;
  71. scratch->clear();
  72. }
  73. break;
  74. default:
  75. ReportDrop(
  76. (fragment.size() + (in_fragmented_record ? scratch->size() : 0)),
  77. "unknown record type");
  78. in_fragmented_record = false;
  79. scratch->clear();
  80. break;
  81. }
  82. }
  83. return false;
  84. }
  85. void Reader::ReportDrop(size_t bytes, const char* reason) {
  86. if (reporter_ != NULL) {
  87. reporter_->Corruption(bytes, Status::Corruption(reason));
  88. }
  89. }
  90. unsigned int Reader::ReadPhysicalRecord(Slice* result) {
  91. while (true) {
  92. if (buffer_.size() <= kHeaderSize) {
  93. if (!eof_) {
  94. // Last read was a full read, so this is a trailer to skip
  95. buffer_.clear();
  96. Status status = file_->Read(kBlockSize, &buffer_, backing_store_);
  97. if (!status.ok()) {
  98. if (reporter_ != NULL) {
  99. reporter_->Corruption(kBlockSize, status);
  100. }
  101. buffer_.clear();
  102. eof_ = true;
  103. return kEof;
  104. } else if (buffer_.size() < kBlockSize) {
  105. eof_ = true;
  106. }
  107. continue;
  108. } else if (buffer_.size() == 0) {
  109. // End of file
  110. return kEof;
  111. } else if (buffer_.size() < kHeaderSize) {
  112. ReportDrop(buffer_.size(), "truncated record at end of file");
  113. buffer_.clear();
  114. return kEof;
  115. } else {
  116. // We have a trailing zero-length record. Fall through and check it.
  117. }
  118. }
  119. // Parse the header
  120. const char* header = buffer_.data();
  121. const uint32_t a = static_cast<uint32_t>(header[4]) & 0xff;
  122. const uint32_t b = static_cast<uint32_t>(header[5]) & 0xff;
  123. const unsigned int type = header[6];
  124. const uint32_t length = a | (b << 8);
  125. if (kHeaderSize + length > buffer_.size()) {
  126. ReportDrop(buffer_.size(), "bad record length");
  127. buffer_.clear();
  128. return kBadRecord;
  129. }
  130. // Check crc
  131. if (checksum_) {
  132. if (type == kZeroType && length == 0) {
  133. // Skip zero length record without reporting any drops since
  134. // such records are produced by the mmap based writing code in
  135. // env_posix.cc that preallocates file regions.
  136. buffer_.clear();
  137. return kBadRecord;
  138. }
  139. uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header));
  140. uint32_t actual_crc = crc32c::Value(header + 6, 1 + length);
  141. if (actual_crc != expected_crc) {
  142. // Drop the rest of the buffer since "length" itself may have
  143. // been corrupted and if we trust it, we could find some
  144. // fragment of a real log record that just happens to look
  145. // like a valid log record.
  146. ReportDrop(buffer_.size(), "checksum mismatch");
  147. buffer_.clear();
  148. return kBadRecord;
  149. }
  150. }
  151. buffer_.remove_prefix(kHeaderSize + length);
  152. *result = Slice(header + kHeaderSize, length);
  153. return type;
  154. }
  155. }
  156. }
  157. }