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