10225501448 李度 10225101546 陈胤遒 10215501422 高宇菲
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

103 lignes
2.8 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_writer.h"
  5. #include <stdint.h>
  6. #include "leveldb/env.h"
  7. #include "util/coding.h"
  8. #include "util/crc32c.h"
  9. namespace leveldb {
  10. namespace log {
  11. Writer::Writer(WritableFile* dest)
  12. : dest_(dest),
  13. block_offset_(0) {
  14. for (int i = 0; i <= kMaxRecordType; i++) {
  15. char t = static_cast<char>(i);
  16. type_crc_[i] = crc32c::Value(&t, 1);
  17. }
  18. }
  19. Writer::~Writer() {
  20. }
  21. Status Writer::AddRecord(const Slice& slice) {
  22. const char* ptr = slice.data();
  23. size_t left = slice.size();
  24. // Fragment the record if necessary and emit it. Note that if slice
  25. // is empty, we still want to iterate once to emit a single
  26. // zero-length record
  27. Status s;
  28. bool begin = true;
  29. do {
  30. const int leftover = kBlockSize - block_offset_;
  31. assert(leftover >= 0);
  32. if (leftover < kHeaderSize) {
  33. // Switch to a new block
  34. if (leftover > 0) {
  35. // Fill the trailer (literal below relies on kHeaderSize being 7)
  36. assert(kHeaderSize == 7);
  37. dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover));
  38. }
  39. block_offset_ = 0;
  40. }
  41. // Invariant: we never leave < kHeaderSize bytes in a block.
  42. assert(kBlockSize - block_offset_ - kHeaderSize >= 0);
  43. const size_t avail = kBlockSize - block_offset_ - kHeaderSize;
  44. const size_t fragment_length = (left < avail) ? left : avail;
  45. RecordType type;
  46. const bool end = (left == fragment_length);
  47. if (begin && end) {
  48. type = kFullType;
  49. } else if (begin) {
  50. type = kFirstType;
  51. } else if (end) {
  52. type = kLastType;
  53. } else {
  54. type = kMiddleType;
  55. }
  56. s = EmitPhysicalRecord(type, ptr, fragment_length);
  57. ptr += fragment_length;
  58. left -= fragment_length;
  59. begin = false;
  60. } while (s.ok() && left > 0);
  61. return s;
  62. }
  63. Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) {
  64. assert(n <= 0xffff); // Must fit in two bytes
  65. assert(block_offset_ + kHeaderSize + n <= kBlockSize);
  66. // Format the header
  67. char buf[kHeaderSize];
  68. buf[4] = static_cast<char>(n & 0xff);
  69. buf[5] = static_cast<char>(n >> 8);
  70. buf[6] = static_cast<char>(t);
  71. // Compute the crc of the record type and the payload.
  72. uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n);
  73. crc = crc32c::Mask(crc); // Adjust for storage
  74. EncodeFixed32(buf, crc);
  75. // Write the header and the payload
  76. Status s = dest_->Append(Slice(buf, kHeaderSize));
  77. if (s.ok()) {
  78. s = dest_->Append(Slice(ptr, n));
  79. if (s.ok()) {
  80. s = dest_->Flush();
  81. }
  82. }
  83. block_offset_ += kHeaderSize + n;
  84. return s;
  85. }
  86. } // namespace log
  87. } // namespace leveldb