Home | History | Annotate | Download | only in table
      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