blob: 10a82f1f8fe27fdf28c33d0967ec3c6387d32311 [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.
*/
// Adapted from Apache ORC
// https://github.com/apache/orc/blob/main/c%2B%2B/src/io/Cache.hh
#pragma once
#include <cstdint>
#include "paimon/visibility.h"
namespace paimon {
/// Configuration parameters for the read-ahead cache behavior.
///
/// This struct controls various limits and prefetching strategies used by
/// ReadAheadCache to balance memory usage, I/O efficiency, and latency hiding.
class PAIMON_EXPORT CacheConfig {
public:
/// Returns the maximum allowed size (in bytes) for a single cached range, both for the ranges
/// registered up front and, as the cap, for the ones registered mid-read.
/// Defaults to 8 MiB.
uint64_t GetRangeSizeLimit() const {
return range_size_limit_;
}
/// Sets the maximum allowed size (in bytes) for a single cached range.
void SetRangeSizeLimit(uint64_t range_size_limit) {
range_size_limit_ = range_size_limit;
}
/// Returns the maximum gap size (in bytes) considered mergeable between
/// adjacent ranges. Defaults to 512 KiB.
uint64_t GetHoleSizeLimit() const {
return hole_size_limit_;
}
/// Sets the maximum gap size (in bytes) considered mergeable between adjacent ranges.
void SetHoleSizeLimit(uint64_t hole_size_limit) {
hole_size_limit_ = hole_size_limit;
}
/// Returns the maximum size to pre-buffer ahead of the current read
/// position. Defaults to 256 MiB.
uint64_t GetPreBufferLimit() const {
return pre_buffer_limit_;
}
/// Sets the maximum size to pre-buffer ahead of the current read position.
void SetPreBufferLimit(uint64_t pre_buffer_limit) {
pre_buffer_limit_ = pre_buffer_limit;
}
/// Returns the granularity (in bytes) of the block cache entries serving the
/// small reads that the prefetched ranges do not cover. Defaults to 64 KiB.
uint64_t GetBlockSize() const {
return block_size_;
}
/// Sets the granularity (in bytes) of the block cache entries.
void SetBlockSize(uint64_t block_size) {
block_size_ = block_size;
}
/// Returns the maximum total size (in bytes) of the block cache entries of
/// one file. Zero disables the block cache. Defaults to 1 MiB.
uint64_t GetBlockCacheLimit() const {
return block_cache_limit_;
}
/// Sets the maximum total size (in bytes) of the block cache entries of one
/// file. Zero disables the block cache.
void SetBlockCacheLimit(uint64_t block_cache_limit) {
block_cache_limit_ = block_cache_limit;
}
private:
// The defaults are aligned with the reader's request granularity and with
// realistic data file sizes:
// - range_size_limit bounds a single coalesced cached range, both for the
// ranges registered up front at Init and for the ones registered mid-read.
// One range is one prefetch IO, so a smaller limit spreads a large pass
// over several concurrent requests instead of one long serial one; a read
// spanning several adjacent ranges is still served as one hit, as they are
// contiguous. 8 MiB keeps a just-in-time mid-read pass concurrent while
// staying large enough to amortize each request's round trip.
// - pre_buffer_limit must exceed the LARGEST single read a reader issues
// (coalesced column-chunk reads of ~128 MiB were observed): fetches are
// only dispatched up to this window, so a request reaching past it can
// never be served and falls back to a second fetch of the same bytes.
// - hole_size_limit trades bytes against requests: coalescing across a gap
// reads the gap too, but saves a request, and on remote storage a request
// costs a round trip whatever its size. The limit is therefore well above
// the page-sized gaps a filtered read leaves between the pages it keeps,
// which would otherwise each cost a request of their own.
uint64_t range_size_limit_ = 8 * 1024 * 1024;
uint64_t hole_size_limit_ = 512 * 1024;
uint64_t pre_buffer_limit_ = 256 * 1024 * 1024;
// Blocks are aligned to the END of the file, so a block never reaches past
// EOF. 64 KiB is the granularity the reads no prefetched range covers are
// shared at: small enough that a metadata read at the tail of a file is
// served by one block instead of straddling two, large enough that a block
// fetch does not pull in much more than the reads ask for.
uint64_t block_size_ = 64 * 1024;
// One block is enough for the metadata tail of a file; the limit only
// bounds the pathological case, as blocks are never evicted.
uint64_t block_cache_limit_ = 1024 * 1024;
};
/// Controls how far a reader prepares the next file before that file is actually read.
///
/// Warmup overlaps remote-storage latency with the read of the current file. Each level takes the
/// next file one step further along the read pipeline: `RAW` covers the remote fetch, `DECODED`
/// adds the decode on top of it. Higher levels hide more latency, but commit more memory and
/// background I/O to files that a query may end up never reading (for example when a LIMIT stops
/// the scan early). Callers can trade latency against memory by picking a level.
enum class PAIMON_EXPORT WarmupLevel {
/// Do not warm up. The next file's I/O starts only when it is actually read. This is the
/// behavior from before warmup existed and uses no extra memory or background threads.
NONE,
/// Fetch only the next file's raw, still-compressed bytes into memory, and leave the decoder
/// alone. Overlaps the remote fetch while keeping memory lower than `DECODED`, because no
/// decoded batches are materialized ahead of the read. It fetches through the read-ahead
/// cache, so it falls back to `NONE` when that cache is disabled. This is the default, as it
/// hides the remote fetch without committing memory to decoded batches.
RAW,
/// Fetch the raw bytes and start the background decode loop as well, so decoded batches are
/// ready before the file is read. Hides the most latency but uses the most memory.
DECODED,
};
} // namespace paimon