|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "rocksdb/slice.h"
|
|
|
|
#include "rocksdb/status.h"
|
|
|
|
#include "rocksdb/options.h"
|
|
|
|
#include "rocksdb/table.h"
|
|
|
|
|
|
|
|
namespace rocksdb {
|
|
|
|
|
|
|
|
class Block;
|
|
|
|
class RandomAccessFile;
|
|
|
|
struct ReadOptions;
|
|
|
|
|
|
|
|
// the length of the magic number in bytes.
|
|
|
|
const int kMagicNumberLengthByte = 8;
|
|
|
|
|
|
|
|
// BlockHandle is a pointer to the extent of a file that stores a data
|
|
|
|
// block or a meta block.
|
|
|
|
class BlockHandle {
|
|
|
|
public:
|
|
|
|
BlockHandle();
|
|
|
|
BlockHandle(uint64_t offset, uint64_t size);
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Maximum encoding length of a BlockHandle
|
|
|
|
enum { kMaxEncodedLength = 10 + 10 };
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint64_t offset_ = 0;
|
|
|
|
uint64_t size_ = 0;
|
|
|
|
|
|
|
|
static const BlockHandle kNullBlockHandle;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Footer encapsulates the fixed information stored at the tail
|
|
|
|
// end of every table file.
|
|
|
|
class Footer {
|
|
|
|
public:
|
|
|
|
// 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) {}
|
|
|
|
|
|
|
|
// @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.
|
|
|
|
explicit Footer(uint64_t table_magic_number)
|
|
|
|
: table_magic_number_(table_magic_number) {}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
const BlockHandle& index_handle() const {
|
|
|
|
return index_handle_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_index_handle(const BlockHandle& h) {
|
|
|
|
index_handle_ = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t table_magic_number() const { return table_magic_number_; }
|
|
|
|
|
|
|
|
void EncodeTo(std::string* dst) const;
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
Status DecodeFrom(Slice* input);
|
|
|
|
|
|
|
|
// Encoded length of a Footer. Note that the serialization of a
|
|
|
|
// Footer will always occupy exactly this many bytes. It consists
|
|
|
|
// of two block handles and a magic number.
|
|
|
|
enum {
|
|
|
|
kEncodedLength = 2 * BlockHandle::kMaxEncodedLength + 8
|
|
|
|
};
|
|
|
|
|
|
|
|
const uint64_t kInvalidTableMagicNumber = 0;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Set the table_magic_number only when it was not previously
|
|
|
|
// initialized. Return true on success.
|
|
|
|
bool set_table_magic_number(uint64_t magic_number) {
|
|
|
|
if (HasInitializedTableMagicNumber()) {
|
|
|
|
table_magic_number_ = magic_number;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return true if @table_magic_number_ is set to a value different
|
|
|
|
// from @kInvalidTableMagicNumber.
|
|
|
|
bool HasInitializedTableMagicNumber() const {
|
|
|
|
return (table_magic_number_ != kInvalidTableMagicNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
BlockHandle metaindex_handle_;
|
|
|
|
BlockHandle index_handle_;
|
|
|
|
uint64_t table_magic_number_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Read the footer from file
|
|
|
|
Status ReadFooterFromFile(RandomAccessFile* file,
|
|
|
|
uint64_t file_size,
|
|
|
|
Footer* footer);
|
|
|
|
|
|
|
|
// 1-byte type + 32-bit crc
|
|
|
|
static const size_t kBlockTrailerSize = 5;
|
|
|
|
|
|
|
|
struct BlockContents {
|
|
|
|
Slice data; // Actual contents of data
|
|
|
|
bool cachable; // True iff data can be cached
|
|
|
|
bool heap_allocated; // True iff caller should delete[] data.data()
|
|
|
|
CompressionType compression_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Read the block identified by "handle" from "file". On failure
|
|
|
|
// return non-OK. On success fill *result and return OK.
|
|
|
|
extern Status ReadBlockContents(RandomAccessFile* file,
|
|
|
|
const ReadOptions& options,
|
|
|
|
const BlockHandle& handle,
|
[RocksDB] Added nano second stopwatch and new perf counters to track block read cost
Summary: The pupose of this diff is to expose per user-call level precise timing of block read, so that we can answer questions like: a Get() costs me 100ms, is that somehow related to loading blocks from file system, or sth else? We will answer that with EXACTLY how many blocks have been read, how much time was spent on transfering the bytes from os, how much time was spent on checksum verification and how much time was spent on block decompression, just for that one Get. A nano second stopwatch was introduced to track time with higher precision. The cost/precision of the stopwatch is also measured in unit-test. On my dev box, retrieving one time instance costs about 30ns, on average. The deviation of timing results is good enough to track 100ns-1us level events. And the overhead could be safely ignored for 100us level events (10000 instances/s), for example, a viewstate thrift call.
Test Plan: perf_context_test, also testing with viewstate shadow traffic.
Reviewers: dhruba
Reviewed By: dhruba
CC: leveldb, xjin
Differential Revision: https://reviews.facebook.net/D12351
12 years ago
|
|
|
BlockContents* result,
|
|
|
|
Env* env,
|
|
|
|
bool do_uncompress);
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
extern Status UncompressBlockContents(const char* data,
|
|
|
|
size_t n,
|
|
|
|
BlockContents* result);
|
|
|
|
|
|
|
|
// Implementation details follow. Clients should ignore,
|
|
|
|
|
|
|
|
inline BlockHandle::BlockHandle()
|
|
|
|
: BlockHandle(~static_cast<uint64_t>(0),
|
|
|
|
~static_cast<uint64_t>(0)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
inline BlockHandle::BlockHandle(uint64_t offset, uint64_t size)
|
|
|
|
: offset_(offset),
|
|
|
|
size_(size) {
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace rocksdb
|