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