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