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