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