/bitcoin/src/leveldb/table/format.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 "table/format.h" |
6 | | |
7 | | #include "leveldb/env.h" |
8 | | #include "port/port.h" |
9 | | #include "table/block.h" |
10 | | #include "util/coding.h" |
11 | | #include "util/crc32c.h" |
12 | | |
13 | | namespace leveldb { |
14 | | |
15 | 697 | void BlockHandle::EncodeTo(std::string* dst) const { |
16 | | // Sanity check that all fields have been set |
17 | 697 | assert(offset_ != ~static_cast<uint64_t>(0)); Branch (17:3): [True: 697, False: 0]
|
18 | 697 | assert(size_ != ~static_cast<uint64_t>(0)); Branch (18:3): [True: 697, False: 0]
|
19 | 697 | PutVarint64(dst, offset_); |
20 | 697 | PutVarint64(dst, size_); |
21 | 697 | } |
22 | | |
23 | 89 | Status BlockHandle::DecodeFrom(Slice* input) { |
24 | 89 | if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) { Branch (24:7): [True: 89, False: 0]
Branch (24:39): [True: 89, False: 0]
|
25 | 89 | return Status::OK(); |
26 | 89 | } else { |
27 | 0 | return Status::Corruption("bad block handle"); |
28 | 0 | } |
29 | 89 | } |
30 | | |
31 | 24 | void Footer::EncodeTo(std::string* dst) const { |
32 | 24 | const size_t original_size = dst->size(); |
33 | 24 | metaindex_handle_.EncodeTo(dst); |
34 | 24 | index_handle_.EncodeTo(dst); |
35 | 24 | dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding |
36 | 24 | PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu)); |
37 | 24 | PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32)); |
38 | 24 | assert(dst->size() == original_size + kEncodedLength); Branch (38:3): [True: 24, False: 0]
|
39 | 24 | (void)original_size; // Disable unused variable warning. |
40 | 24 | } |
41 | | |
42 | 24 | Status Footer::DecodeFrom(Slice* input) { |
43 | 24 | const char* magic_ptr = input->data() + kEncodedLength - 8; |
44 | 24 | const uint32_t magic_lo = DecodeFixed32(magic_ptr); |
45 | 24 | const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); |
46 | 24 | const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) | |
47 | 24 | (static_cast<uint64_t>(magic_lo))); |
48 | 24 | if (magic != kTableMagicNumber) { Branch (48:7): [True: 0, False: 24]
|
49 | 0 | return Status::Corruption("not an sstable (bad magic number)"); |
50 | 0 | } |
51 | | |
52 | 24 | Status result = metaindex_handle_.DecodeFrom(input); |
53 | 24 | if (result.ok()) { Branch (53:7): [True: 24, False: 0]
|
54 | 24 | result = index_handle_.DecodeFrom(input); |
55 | 24 | } |
56 | 24 | if (result.ok()) { Branch (56:7): [True: 24, False: 0]
|
57 | | // We skip over any leftover data (just padding for now) in "input" |
58 | 24 | const char* end = magic_ptr + 8; |
59 | 24 | *input = Slice(end, input->data() + input->size() - end); |
60 | 24 | } |
61 | 24 | return result; |
62 | 24 | } |
63 | | |
64 | | Status ReadBlock(RandomAccessFile* file, const ReadOptions& options, |
65 | 84 | const BlockHandle& handle, BlockContents* result) { |
66 | 84 | result->data = Slice(); |
67 | 84 | result->cachable = false; |
68 | 84 | result->heap_allocated = false; |
69 | | |
70 | | // Read the block contents as well as the type/crc footer. |
71 | | // See table_builder.cc for the code that built this structure. |
72 | 84 | size_t n = static_cast<size_t>(handle.size()); |
73 | 84 | char* buf = new char[n + kBlockTrailerSize]; |
74 | 84 | Slice contents; |
75 | 84 | Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); |
76 | 84 | if (!s.ok()) { Branch (76:7): [True: 0, False: 84]
|
77 | 0 | delete[] buf; |
78 | 0 | return s; |
79 | 0 | } |
80 | 84 | if (contents.size() != n + kBlockTrailerSize) { Branch (80:7): [True: 0, False: 84]
|
81 | 0 | delete[] buf; |
82 | 0 | return Status::Corruption("truncated block read", file->GetName()); |
83 | 0 | } |
84 | | |
85 | | // Check the crc of the type and the block contents |
86 | 84 | const char* data = contents.data(); // Pointer to where Read put the data |
87 | 84 | if (options.verify_checksums) { Branch (87:7): [True: 84, False: 0]
|
88 | 84 | const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); |
89 | 84 | const uint32_t actual = crc32c::Value(data, n + 1); |
90 | 84 | if (actual != crc) { Branch (90:9): [True: 0, False: 84]
|
91 | 0 | delete[] buf; |
92 | 0 | s = Status::Corruption("block checksum mismatch", file->GetName()); |
93 | 0 | return s; |
94 | 0 | } |
95 | 84 | } |
96 | | |
97 | 84 | switch (data[n]) { |
98 | 84 | case kNoCompression: Branch (98:5): [True: 84, False: 0]
|
99 | 84 | if (data != buf) { Branch (99:11): [True: 84, False: 0]
|
100 | | // File implementation gave us pointer to some other data. |
101 | | // Use it directly under the assumption that it will be live |
102 | | // while the file is open. |
103 | 84 | delete[] buf; |
104 | 84 | result->data = Slice(data, n); |
105 | 84 | result->heap_allocated = false; |
106 | 84 | result->cachable = false; // Do not double-cache |
107 | 84 | } else { |
108 | 0 | result->data = Slice(buf, n); |
109 | 0 | result->heap_allocated = true; |
110 | 0 | result->cachable = true; |
111 | 0 | } |
112 | | |
113 | | // Ok |
114 | 84 | break; |
115 | 0 | case kSnappyCompression: { Branch (115:5): [True: 0, False: 84]
|
116 | 0 | size_t ulength = 0; |
117 | 0 | if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { Branch (117:11): [True: 0, False: 0]
|
118 | 0 | delete[] buf; |
119 | 0 | return Status::Corruption("corrupted compressed block contents", file->GetName()); |
120 | 0 | } |
121 | 0 | char* ubuf = new char[ulength]; |
122 | 0 | if (!port::Snappy_Uncompress(data, n, ubuf)) { Branch (122:11): [True: 0, False: 0]
|
123 | 0 | delete[] buf; |
124 | 0 | delete[] ubuf; |
125 | 0 | return Status::Corruption("corrupted compressed block contents", file->GetName()); |
126 | 0 | } |
127 | 0 | delete[] buf; |
128 | 0 | result->data = Slice(ubuf, ulength); |
129 | 0 | result->heap_allocated = true; |
130 | 0 | result->cachable = true; |
131 | 0 | break; |
132 | 0 | } |
133 | 0 | default: Branch (133:5): [True: 0, False: 84]
|
134 | 0 | delete[] buf; |
135 | 0 | return Status::Corruption("bad block type", file->GetName()); |
136 | 84 | } |
137 | | |
138 | 84 | return Status::OK(); |
139 | 84 | } |
140 | | |
141 | | } // namespace leveldb |