2013-10-16 21:59:46 +00:00
|
|
|
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
|
|
|
// This source code is licensed under the BSD-style license found in the
|
|
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
//
|
2011-03-18 22:37:00 +00:00
|
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
|
|
|
2013-10-05 05:32:05 +00:00
|
|
|
#pragma once
|
2011-03-18 22:37:00 +00:00
|
|
|
#include <string>
|
|
|
|
#include <stdint.h>
|
2013-08-23 15:38:13 +00:00
|
|
|
#include "rocksdb/slice.h"
|
|
|
|
#include "rocksdb/status.h"
|
2013-09-02 06:23:40 +00:00
|
|
|
#include "rocksdb/options.h"
|
2013-10-29 00:54:09 +00:00
|
|
|
#include "rocksdb/table.h"
|
2011-03-18 22:37:00 +00:00
|
|
|
|
2013-10-04 04:49:15 +00:00
|
|
|
namespace rocksdb {
|
2011-03-18 22:37:00 +00:00
|
|
|
|
|
|
|
class Block;
|
|
|
|
class RandomAccessFile;
|
|
|
|
struct ReadOptions;
|
|
|
|
|
2014-02-05 00:21:47 +00:00
|
|
|
// the length of the magic number in bytes.
|
|
|
|
const int kMagicNumberLengthByte = 8;
|
|
|
|
|
2011-03-18 22:37:00 +00:00
|
|
|
// BlockHandle is a pointer to the extent of a file that stores a data
|
|
|
|
// block or a meta block.
|
|
|
|
class BlockHandle {
|
|
|
|
public:
|
|
|
|
BlockHandle();
|
2013-12-04 23:43:09 +00:00
|
|
|
BlockHandle(uint64_t offset, uint64_t size);
|
2011-03-18 22:37:00 +00:00
|
|
|
|
|
|
|
// The offset of the block in the file.
|
|
|
|
uint64_t offset() const { return offset_; }
|
|
|
|
void set_offset(uint64_t offset) { offset_ = offset; }
|
|
|
|
|
|
|
|
// The size of the stored block
|
|
|
|
uint64_t size() const { return size_; }
|
|
|
|
void set_size(uint64_t size) { size_ = size; }
|
|
|
|
|
|
|
|
void EncodeTo(std::string* dst) const;
|
|
|
|
Status DecodeFrom(Slice* input);
|
|
|
|
|
2013-12-04 23:43:09 +00:00
|
|
|
// if the block handle's offset and size are both "0", we will view it
|
|
|
|
// as a null block handle that points to no where.
|
|
|
|
bool IsNull() const {
|
|
|
|
return offset_ == 0 && size_ == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const BlockHandle& NullBlockHandle() {
|
|
|
|
return kNullBlockHandle;
|
|
|
|
}
|
|
|
|
|
2011-03-18 22:37:00 +00:00
|
|
|
// Maximum encoding length of a BlockHandle
|
|
|
|
enum { kMaxEncodedLength = 10 + 10 };
|
|
|
|
|
|
|
|
private:
|
2013-12-04 23:43:09 +00:00
|
|
|
uint64_t offset_ = 0;
|
|
|
|
uint64_t size_ = 0;
|
|
|
|
|
|
|
|
static const BlockHandle kNullBlockHandle;
|
2011-03-18 22:37:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Footer encapsulates the fixed information stored at the tail
|
|
|
|
// end of every table file.
|
|
|
|
class Footer {
|
|
|
|
public:
|
2014-02-05 00:21:47 +00:00
|
|
|
// Constructs a footer without specifying its table magic number.
|
|
|
|
// In such case, the table magic number of such footer should be
|
|
|
|
// initialized via @ReadFooterFromFile().
|
|
|
|
Footer() : Footer(kInvalidTableMagicNumber) {}
|
|
|
|
|
2013-12-04 23:09:41 +00:00
|
|
|
// @table_magic_number serves two purposes:
|
|
|
|
// 1. Identify different types of the tables.
|
|
|
|
// 2. Help us to identify if a given file is a valid sst.
|
2014-05-01 18:09:32 +00:00
|
|
|
explicit Footer(uint64_t table_magic_number);
|
|
|
|
|
|
|
|
// The version of the footer in this file
|
|
|
|
uint32_t version() const { return version_; }
|
|
|
|
|
|
|
|
// The checksum type used in this file
|
|
|
|
ChecksumType checksum() const { return checksum_; }
|
|
|
|
void set_checksum(const ChecksumType c) { checksum_ = c; }
|
2011-03-18 22:37:00 +00:00
|
|
|
|
|
|
|
// The block handle for the metaindex block of the table
|
|
|
|
const BlockHandle& metaindex_handle() const { return metaindex_handle_; }
|
|
|
|
void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; }
|
|
|
|
|
|
|
|
// The block handle for the index block of the table
|
2014-05-01 18:09:32 +00:00
|
|
|
const BlockHandle& index_handle() const { return index_handle_; }
|
2014-02-05 00:21:47 +00:00
|
|
|
|
2014-05-01 18:09:32 +00:00
|
|
|
void set_index_handle(const BlockHandle& h) { index_handle_ = h; }
|
2011-03-18 22:37:00 +00:00
|
|
|
|
2014-02-05 00:21:47 +00:00
|
|
|
uint64_t table_magic_number() const { return table_magic_number_; }
|
|
|
|
|
2014-05-01 18:09:32 +00:00
|
|
|
// The version of Footer we encode
|
|
|
|
enum {
|
|
|
|
kLegacyFooter = 0,
|
|
|
|
kFooterVersion = 1,
|
|
|
|
};
|
|
|
|
|
2011-03-18 22:37:00 +00:00
|
|
|
void EncodeTo(std::string* dst) const;
|
2014-02-05 00:21:47 +00:00
|
|
|
|
|
|
|
// Set the current footer based on the input slice. If table_magic_number_
|
|
|
|
// is not set (i.e., HasInitializedTableMagicNumber() is true), then this
|
|
|
|
// function will also initialize table_magic_number_. Otherwise, this
|
|
|
|
// function will verify whether the magic number specified in the input
|
|
|
|
// slice matches table_magic_number_ and update the current footer only
|
|
|
|
// when the test passes.
|
2011-03-18 22:37:00 +00:00
|
|
|
Status DecodeFrom(Slice* input);
|
|
|
|
|
2014-05-01 18:09:32 +00:00
|
|
|
// Encoded length of a Footer. Note that the serialization of a Footer will
|
|
|
|
// always occupy at least kMinEncodedLength bytes. If fields are changed
|
|
|
|
// the version number should be incremented and kMaxEncodedLength should be
|
|
|
|
// increased accordingly.
|
2011-03-18 22:37:00 +00:00
|
|
|
enum {
|
2014-05-01 18:09:32 +00:00
|
|
|
// Footer version 0 (legacy) will always occupy exactly this many bytes.
|
|
|
|
// It consists of two block handles, padding, and a magic number.
|
|
|
|
kVersion0EncodedLength = 2 * BlockHandle::kMaxEncodedLength + 8,
|
|
|
|
// Footer version 1 will always occupy exactly this many bytes.
|
|
|
|
// It consists of the checksum type, two block handles, padding,
|
|
|
|
// a version number, and a magic number
|
|
|
|
kVersion1EncodedLength = 1 + 2 * BlockHandle::kMaxEncodedLength + 4 + 8,
|
|
|
|
|
|
|
|
kMinEncodedLength = kVersion0EncodedLength,
|
|
|
|
kMaxEncodedLength = kVersion1EncodedLength
|
2011-03-18 22:37:00 +00:00
|
|
|
};
|
|
|
|
|
2014-02-11 22:12:58 +00:00
|
|
|
static const uint64_t kInvalidTableMagicNumber = 0;
|
2014-02-05 00:21:47 +00:00
|
|
|
|
2011-03-18 22:37:00 +00:00
|
|
|
private:
|
2014-03-19 23:04:51 +00:00
|
|
|
// REQUIRES: magic number wasn't initialized.
|
|
|
|
void set_table_magic_number(uint64_t magic_number) {
|
|
|
|
assert(!HasInitializedTableMagicNumber());
|
|
|
|
table_magic_number_ = magic_number;
|
2014-02-05 00:21:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// return true if @table_magic_number_ is set to a value different
|
|
|
|
// from @kInvalidTableMagicNumber.
|
|
|
|
bool HasInitializedTableMagicNumber() const {
|
|
|
|
return (table_magic_number_ != kInvalidTableMagicNumber);
|
|
|
|
}
|
|
|
|
|
2014-05-01 18:09:32 +00:00
|
|
|
uint32_t version_;
|
|
|
|
ChecksumType checksum_;
|
2011-03-18 22:37:00 +00:00
|
|
|
BlockHandle metaindex_handle_;
|
|
|
|
BlockHandle index_handle_;
|
2014-03-19 23:04:51 +00:00
|
|
|
uint64_t table_magic_number_ = 0;
|
2011-03-18 22:37:00 +00:00
|
|
|
};
|
|
|
|
|
2013-12-05 00:35:48 +00:00
|
|
|
// Read the footer from file
|
|
|
|
Status ReadFooterFromFile(RandomAccessFile* file,
|
|
|
|
uint64_t file_size,
|
|
|
|
Footer* footer);
|
|
|
|
|
2011-03-18 22:37:00 +00:00
|
|
|
// 1-byte type + 32-bit crc
|
|
|
|
static const size_t kBlockTrailerSize = 5;
|
|
|
|
|
2012-04-17 15:36:46 +00:00
|
|
|
struct BlockContents {
|
|
|
|
Slice data; // Actual contents of data
|
|
|
|
bool cachable; // True iff data can be cached
|
2013-09-02 06:23:40 +00:00
|
|
|
CompressionType compression_type;
|
2014-08-15 22:05:09 +00:00
|
|
|
std::unique_ptr<char[]> allocation;
|
|
|
|
|
2014-09-17 22:08:19 +00:00
|
|
|
BlockContents() : cachable(false), compression_type(kNoCompression) {}
|
|
|
|
|
|
|
|
BlockContents(const Slice& _data, bool _cachable,
|
|
|
|
CompressionType _compression_type)
|
|
|
|
: data(_data), cachable(_cachable), compression_type(_compression_type) {}
|
|
|
|
|
|
|
|
BlockContents(std::unique_ptr<char[]>&& _data, size_t _size, bool _cachable,
|
|
|
|
CompressionType _compression_type)
|
|
|
|
: data(_data.get(), _size),
|
|
|
|
cachable(_cachable),
|
|
|
|
compression_type(_compression_type),
|
|
|
|
allocation(std::move(_data)) {}
|
2012-04-17 15:36:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Read the block identified by "handle" from "file". On failure
|
|
|
|
// return non-OK. On success fill *result and return OK.
|
2014-08-15 22:05:09 +00:00
|
|
|
extern Status ReadBlockContents(RandomAccessFile* file, const Footer& footer,
|
2013-04-23 06:47:56 +00:00
|
|
|
const ReadOptions& options,
|
2014-09-17 22:08:19 +00:00
|
|
|
const BlockHandle& handle,
|
|
|
|
BlockContents* contents, Env* env,
|
|
|
|
bool do_uncompress);
|
2013-09-02 06:23:40 +00:00
|
|
|
|
|
|
|
// The 'data' points to the raw block contents read in from file.
|
|
|
|
// This method allocates a new heap buffer and the raw block
|
|
|
|
// contents are uncompresed into this buffer. This buffer is
|
|
|
|
// returned via 'result' and it is upto the caller to
|
|
|
|
// free this buffer.
|
2014-08-15 22:05:09 +00:00
|
|
|
extern Status UncompressBlockContents(const char* data, size_t n,
|
|
|
|
BlockContents* contents);
|
2011-03-18 22:37:00 +00:00
|
|
|
|
|
|
|
// Implementation details follow. Clients should ignore,
|
|
|
|
|
|
|
|
inline BlockHandle::BlockHandle()
|
2013-12-04 23:43:09 +00:00
|
|
|
: BlockHandle(~static_cast<uint64_t>(0),
|
|
|
|
~static_cast<uint64_t>(0)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
inline BlockHandle::BlockHandle(uint64_t offset, uint64_t size)
|
|
|
|
: offset_(offset),
|
|
|
|
size_(size) {
|
2011-03-18 22:37:00 +00:00
|
|
|
}
|
|
|
|
|
2013-10-04 04:49:15 +00:00
|
|
|
} // namespace rocksdb
|