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.
5 #include "table/format.h"
7 #include "leveldb/env.h"
9 #include "table/block.h"
10 #include "util/coding.h"
11 #include "util/crc32c.h"
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_
);
23 Status
BlockHandle::DecodeFrom(Slice
* input
) {
24 if (GetVarint64(input
, &offset_
) &&
25 GetVarint64(input
, &size_
)) {
28 return Status::Corruption("bad block handle");
32 void Footer::EncodeTo(std::string
* dst
) const {
34 const size_t original_size
= dst
->size();
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
);
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::Corruption("not an sstable (bad magic number)");
54 Status result
= metaindex_handle_
.DecodeFrom(input
);
56 result
= index_handle_
.DecodeFrom(input
);
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
);
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;
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
];
79 Status s
= file
->Read(handle
.offset(), n
+ kBlockTrailerSize
, &contents
, buf
);
84 if (contents
.size() != n
+ kBlockTrailerSize
) {
86 return Status::Corruption("truncated block read");
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);
96 s
= Status::Corruption("block checksum mismatch");
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.
108 result
->data
= Slice(data
, n
);
109 result
->heap_allocated
= false;
110 result
->cachable
= false; // Do not double-cache
112 result
->data
= Slice(buf
, n
);
113 result
->heap_allocated
= true;
114 result
->cachable
= true;
119 case kSnappyCompression
: {
121 if (!port::Snappy_GetUncompressedLength(data
, n
, &ulength
)) {
123 return Status::Corruption("corrupted compressed block contents");
125 char* ubuf
= new char[ulength
];
126 if (!port::Snappy_Uncompress(data
, n
, ubuf
)) {
129 return Status::Corruption("corrupted compressed block contents");
132 result
->data
= Slice(ubuf
, ulength
);
133 result
->heap_allocated
= true;
134 result
->cachable
= true;
139 return Status::Corruption("bad block type");
145 } // namespace leveldb