/root/bitcoin/src/leveldb/db/log_writer.cc
Line | Count | Source (jump to first uncovered line) |
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 | 4.84k | static void InitTypeCrc(uint32_t* type_crc) { |
17 | 29.0k | for (int i = 0; i <= kMaxRecordType; i++) { Branch (17:19): [True: 24.2k, False: 4.84k]
|
18 | 24.2k | char t = static_cast<char>(i); |
19 | 24.2k | type_crc[i] = crc32c::Value(&t, 1); |
20 | 24.2k | } |
21 | 4.84k | } |
22 | | |
23 | 4.84k | Writer::Writer(WritableFile* dest) : dest_(dest), block_offset_(0) { |
24 | 4.84k | InitTypeCrc(type_crc_); |
25 | 4.84k | } |
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 | 4.84k | Writer::~Writer() = default; |
33 | | |
34 | 28.3k | Status Writer::AddRecord(const Slice& slice) { |
35 | 28.3k | const char* ptr = slice.data(); |
36 | 28.3k | 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 | 28.3k | Status s; |
42 | 28.3k | bool begin = true; |
43 | 28.3k | do { |
44 | 28.3k | const int leftover = kBlockSize - block_offset_; |
45 | 28.3k | assert(leftover >= 0); |
46 | 28.3k | if (leftover < kHeaderSize) { Branch (46:9): [True: 11, False: 28.3k]
|
47 | | // Switch to a new block |
48 | 11 | if (leftover > 0) { Branch (48:11): [True: 0, False: 11]
|
49 | | // Fill the trailer (literal below relies on kHeaderSize being 7) |
50 | 0 | static_assert(kHeaderSize == 7, ""); |
51 | 0 | dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); |
52 | 0 | } |
53 | 11 | block_offset_ = 0; |
54 | 11 | } |
55 | | |
56 | | // Invariant: we never leave < kHeaderSize bytes in a block. |
57 | 28.3k | assert(kBlockSize - block_offset_ - kHeaderSize >= 0); |
58 | | |
59 | 28.3k | const size_t avail = kBlockSize - block_offset_ - kHeaderSize; |
60 | 28.3k | const size_t fragment_length = (left < avail) ? left : avail; Branch (60:36): [True: 28.3k, False: 11]
|
61 | | |
62 | 28.3k | RecordType type; |
63 | 28.3k | const bool end = (left == fragment_length); |
64 | 28.3k | if (begin && end) { Branch (64:9): [True: 28.3k, False: 11]
Branch (64:18): [True: 28.3k, False: 11]
|
65 | 28.3k | type = kFullType; |
66 | 28.3k | } else if (begin) { Branch (66:16): [True: 11, False: 11]
|
67 | 11 | type = kFirstType; |
68 | 11 | } else if (end) { Branch (68:16): [True: 11, False: 0]
|
69 | 11 | type = kLastType; |
70 | 11 | } else { |
71 | 0 | type = kMiddleType; |
72 | 0 | } |
73 | | |
74 | 28.3k | s = EmitPhysicalRecord(type, ptr, fragment_length); |
75 | 28.3k | ptr += fragment_length; |
76 | 28.3k | left -= fragment_length; |
77 | 28.3k | begin = false; |
78 | 28.3k | } while (s.ok() && left > 0); Branch (78:12): [True: 28.3k, False: 0]
Branch (78:22): [True: 11, False: 28.3k]
|
79 | 28.3k | return s; |
80 | 28.3k | } |
81 | | |
82 | | Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, |
83 | 28.3k | size_t length) { |
84 | 28.3k | assert(length <= 0xffff); // Must fit in two bytes |
85 | 28.3k | assert(block_offset_ + kHeaderSize + length <= kBlockSize); |
86 | | |
87 | | // Format the header |
88 | 28.3k | char buf[kHeaderSize]; |
89 | 28.3k | buf[4] = static_cast<char>(length & 0xff); |
90 | 28.3k | buf[5] = static_cast<char>(length >> 8); |
91 | 28.3k | buf[6] = static_cast<char>(t); |
92 | | |
93 | | // Compute the crc of the record type and the payload. |
94 | 28.3k | uint32_t crc = crc32c::Extend(type_crc_[t], ptr, length); |
95 | 28.3k | crc = crc32c::Mask(crc); // Adjust for storage |
96 | 28.3k | EncodeFixed32(buf, crc); |
97 | | |
98 | | // Write the header and the payload |
99 | 28.3k | Status s = dest_->Append(Slice(buf, kHeaderSize)); |
100 | 28.3k | if (s.ok()) { Branch (100:7): [True: 28.3k, False: 0]
|
101 | 28.3k | s = dest_->Append(Slice(ptr, length)); |
102 | 28.3k | if (s.ok()) { Branch (102:9): [True: 28.3k, False: 0]
|
103 | 28.3k | s = dest_->Flush(); |
104 | 28.3k | } |
105 | 28.3k | } |
106 | 28.3k | block_offset_ += kHeaderSize + length; |
107 | 28.3k | return s; |
108 | 28.3k | } |
109 | | |
110 | | } // namespace log |
111 | | } // namespace leveldb |