blob: 045c0101eb56f13ff511344875ba93988f608ec7 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef KUDU_CFILE_INDEX_BLOCK_H
#define KUDU_CFILE_INDEX_BLOCK_H
#include <cstddef>
#include <cstdint>
#include <vector>
#include "kudu/cfile/block_pointer.h"
#include "kudu/cfile/cfile.pb.h"
#include "kudu/gutil/macros.h"
#include "kudu/util/faststring.h"
#include "kudu/util/slice.h"
#include "kudu/util/status.h"
namespace kudu {
namespace cfile {
// Forward decl.
class IndexBlockIterator;
struct WriterOptions;
// Index Block Builder for a particular key type.
// This works like the rest of the builders in the cfile package.
// After repeatedly calling Add(), call Finish() to encode it
// into a Slice, then you may Reset to re-use buffers.
class IndexBlockBuilder {
public:
explicit IndexBlockBuilder(const WriterOptions *options,
bool is_leaf);
// Append an entry into the index.
void Add(const Slice &key, const BlockPointer &ptr);
// Finish the current index block.
// Returns a fully encoded Slice including the data
// as well as any necessary footer.
// The Slice is only valid until the next call to
// Reset().
Slice Finish();
// Return the key of the first entry in this index block.
// The pointed-to data is only valid until the next call to this builder.
Status GetFirstKey(Slice *key) const;
// Return the number of entries already added to this index
// block.
size_t count() const {
return entry_offsets_.size();
}
// Return an estimate of the post-encoding size of this
// index block. This estimate should be conservative --
// it will over-estimate rather than under-estimate, and
// should be accurate to within a reasonable threshold,
// but is not exact.
size_t EstimateEncodedSize() const;
void Reset();
private:
DISALLOW_COPY_AND_ASSIGN(IndexBlockBuilder);
#ifdef __clang__
__attribute__((__unused__))
#endif
const WriterOptions *options_;
// Is the builder currently between Finish() and Reset()
bool finished_;
// Is this a leaf block?
bool is_leaf_;
faststring buffer_;
std::vector<uint32_t> entry_offsets_;
};
class IndexBlockReader {
public:
IndexBlockReader();
void Reset();
// Parse the given index block.
//
// This function may be called repeatedly to "reset" the reader to process
// a new block.
//
// Note: this does not copy the data, so the slice must
// remain valid for the lifetime of the reader (or until the next Parse call).
Status Parse(const Slice &data);
size_t Count() const;
IndexBlockIterator *NewIterator() const;
bool IsLeaf();
private:
friend class IndexBlockIterator;
int CompareKey(int idx_in_block, const Slice &search_key) const;
Status ReadEntry(size_t idx, Slice *key, BlockPointer *block_ptr) const;
// Set *ptr to the beginning of the index data for the given index
// entry.
// Set *limit to the 'limit' pointer for that entry (i.e a pointer
// beyond which the data no longer is part of that entry).
// - *limit can be used to prevent overrunning in the case of a
// corrupted length varint or length prefix
void GetKeyPointer(int idx_in_block, const uint8_t **ptr, const uint8_t **limit) const;
static const int kMaxTrailerSize = 64*1024;
Slice data_;
IndexBlockTrailerPB trailer_;
const uint8_t *key_offsets_;
bool parsed_;
DISALLOW_COPY_AND_ASSIGN(IndexBlockReader);
};
class IndexBlockIterator {
public:
explicit IndexBlockIterator(const IndexBlockReader *reader);
// Reset the state of this iterator. This should be used
// after the associated 'reader' object parses a different block.
void Reset();
// Find the highest block pointer in this index
// block which has a value <= the given key.
// If such a block is found, returns OK status.
// If no such block is found (i.e the smallest key in the
// index is still larger than the provided key), then
// Status::NotFound is returned.
//
// If this function returns an error, then the state of this
// iterator is undefined (i.e it may or may not have moved
// since the previous call)
Status SeekAtOrBefore(const Slice &search_key);
Status SeekToIndex(size_t idx);
bool HasNext() const;
Status Next();
const BlockPointer &GetCurrentBlockPointer() const;
const Slice GetCurrentKey() const;
private:
const IndexBlockReader *reader_;
size_t cur_idx_;
Slice cur_key_;
BlockPointer cur_ptr_;
bool seeked_;
DISALLOW_COPY_AND_ASSIGN(IndexBlockIterator);
};
} // namespace cfile
} // namespace kudu
#endif