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