blob: 4da3f53530d88ec5e8b2bcf7f4dab781744324cb [file]
// 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.
#pragma once
#include <gen_cpp/segment_v2.pb.h>
#include <vector>
#include "common/logging.h"
#include "common/status.h"
#include "io/cache/block_file_cache.h"
#include "io/io_common.h"
#include "storage/segment/page_pointer.h"
#include "util/slice.h"
namespace doris {
class BlockCompressionCodec;
struct OlapReaderStatistics;
namespace io {
class FileWriter;
class FileReader;
} // namespace io
namespace segment_v2 {
class EncodingInfo;
class PageHandle;
io::UInt128Wrapper file_cache_key_from_path(const std::string& seg_path);
std::string file_cache_key_str(const std::string& seg_path);
struct PageReadOptions {
// whether to verify page checksum
bool verify_checksum = true;
// whether to use page cache in read path
bool use_page_cache = false;
// if true, use DURABLE CachePriority in page cache
// currently used for in memory olap table
bool kept_in_memory = false;
// index_page should not be pre-decoded
bool pre_decode = true;
// for page cache allocation
// page types are divided into DATA_PAGE & INDEX_PAGE
// INDEX_PAGE including index_page, dict_page and short_key_page
PageTypePB type;
// block to read page
io::FileReader* file_reader = nullptr;
// location of the page
PagePointer page_pointer;
// decompressor for page body (null means page body is not compressed)
BlockCompressionCodec* codec = nullptr;
// used to collect IO metrics
OlapReaderStatistics* stats = nullptr;
const EncodingInfo* encoding_info = nullptr;
const io::IOContext io_ctx;
void sanity_check() const {
CHECK_NOTNULL(file_reader);
CHECK_NOTNULL(stats);
}
PageReadOptions(const io::IOContext& ioctx) : io_ctx(ioctx) {}
PageReadOptions(const PageReadOptions& old) : io_ctx(old.io_ctx) {
file_reader = old.file_reader;
page_pointer = old.page_pointer;
codec = old.codec;
stats = old.stats;
verify_checksum = old.verify_checksum;
use_page_cache = old.use_page_cache;
kept_in_memory = old.kept_in_memory;
type = old.type;
encoding_info = old.encoding_info;
pre_decode = old.pre_decode;
}
};
struct InjectionContext {
uint32_t* crc;
PageReadOptions* opts;
};
inline std::ostream& operator<<(std::ostream& os, const PageReadOptions& opt) {
return os << "PageReadOptions { verify_checksum=" << opt.verify_checksum
<< " use_page_cache=" << opt.use_page_cache
<< " kept_in_memory=" << opt.kept_in_memory << " pre_decode=" << opt.pre_decode
<< " type=" << opt.type << " page_pointer=" << opt.page_pointer
<< " has_codec=" << (opt.codec != nullptr)
<< " has_encoding_info=" << (opt.encoding_info != nullptr) << " }";
}
// Utility class for read and write page. All types of page share the same general layout:
// Page := PageBody, PageFooter, FooterSize(4), Checksum(4)
// - PageBody is defined by page type and may be compressed
// - PageFooter is serialized PageFooterPB. It contains page_type, uncompressed_body_size,
// and other custom metadata. PageBody is not compressed when its size is equal to
// uncompressed_body_size
// - FooterSize stores the size of PageFooter
// - Checksum is the crc32c checksum of all previous part
class PageIO {
public:
// Compress `body' using `codec' into `compressed_body'.
// The size of returned `compressed_body' is 0 when the body is not compressed, this
// could happen when `codec' is null or space saving is less than `min_space_saving'.
static Status compress_page_body(BlockCompressionCodec* codec, double min_space_saving,
const std::vector<Slice>& body, OwnedSlice* compressed_body);
// Encode page from `body' and `footer' and write to `file'.
// `body' could be either uncompressed or compressed.
// On success, the file pointer to the written page is stored in `result'.
static Status write_page(io::FileWriter* writer, const std::vector<Slice>& body,
const PageFooterPB& footer, PagePointer* result);
// Convenient function to compress page body and write page in one go.
static Status compress_and_write_page(BlockCompressionCodec* codec, double min_space_saving,
io::FileWriter* writer, const std::vector<Slice>& body,
const PageFooterPB& footer, PagePointer* result) {
DCHECK_EQ(footer.uncompressed_size(), Slice::compute_total_size(body));
OwnedSlice compressed_body;
RETURN_IF_ERROR(compress_page_body(codec, min_space_saving, body, &compressed_body));
if (compressed_body.slice().empty()) { // uncompressed
return write_page(writer, body, footer, result);
}
return write_page(writer, {compressed_body.slice()}, footer, result);
}
// Read and parse a page according to `opts'.
// On success
// `handle' holds the memory of page data,
// `body' points to page body,
// `footer' stores the page footer.
// This method is exception safe, it will failed when allocate memory failed.
// deal with CORRUPTION when using file cache, retry from remote
static Status read_and_decompress_page(const PageReadOptions& opts, PageHandle* handle,
Slice* body, PageFooterPB* footer);
private:
static Status do_read_and_decompress_page(const PageReadOptions& opts, PageHandle* handle,
Slice* body, PageFooterPB* footer) {
RETURN_IF_CATCH_EXCEPTION(
{ return read_and_decompress_page_(opts, handle, body, footer); });
}
// An internal method that not deal with exception.
static Status read_and_decompress_page_(const PageReadOptions& opts, PageHandle* handle,
Slice* body, PageFooterPB* footer);
};
} // namespace segment_v2
} // namespace doris