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