Skip to content

Commit 1eae4ea

Browse files
committed
fix
1 parent 0aff1c7 commit 1eae4ea

7 files changed

Lines changed: 63 additions & 67 deletions

‎include/paimon/reader/prefetch_file_batch_reader.h‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,19 @@ class PAIMON_EXPORT PrefetchFileBatchReader : public FileBatchReader {
137137
return std::vector<std::pair<uint64_t, uint64_t>>{};
138138
}
139139

140-
/// Sink a reader reports byte ranges to when they only become known after reading has
140+
/// Callback a reader reports byte ranges through when they only become known after reading has
141141
/// started, so the prefetch layer can register them with its shared read-ahead cache.
142142
///
143143
/// PreBufferRange() covers what is known up front; a reader whose ranges depend on data it
144144
/// has already read - the late-materialization payload pass only knows which pages hold the
145-
/// matched rows once the probe pass has run - reports them here instead.
146-
using PreBufferSink = std::function<void(std::vector<std::pair<uint64_t, uint64_t>>&&)>;
145+
/// matched rows once the probe pass has run - reports them through this callback instead.
146+
using PreBufferRangeCallback =
147+
std::function<void(std::vector<std::pair<uint64_t, uint64_t>>&&)>;
147148

148-
/// Installs the sink above, or clears it when `sink` is empty. By default a reader has no
149-
/// late byte ranges to report and ignores the sink.
150-
/// @param sink The sink to report late byte ranges to.
151-
virtual void SetPreBufferSink(PreBufferSink sink) {}
149+
/// Installs the callback above, or clears it when `callback` is empty. By default a reader has
150+
/// no late byte ranges to report and ignores the callback.
151+
/// @param callback The callback to report late byte ranges through.
152+
virtual void SetPreBufferRangeCallback(PreBufferRangeCallback callback) {}
152153
};
153154

154155
} // namespace paimon

‎src/paimon/common/reader/late_materializing_file_batch_reader.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ Status LateMaterializingFileBatchReader::ReportPayloadPreBufferRanges() {
268268
// reader's target row groups down to the pages holding the matched rows. Reporting them
269269
// here lets the shared read-ahead cache fetch them while this pass is still assembling
270270
// its first batch, instead of every payload read waiting for its own IO.
271-
if (!pre_buffer_sink_ || prefetch_inner_ == nullptr) {
271+
if (!pre_buffer_range_callback_ || prefetch_inner_ == nullptr) {
272272
return Status::OK();
273273
}
274274
// The error is propagated rather than swallowed: the ranges come from the file metadata, so a
@@ -278,7 +278,7 @@ Status LateMaterializingFileBatchReader::ReportPayloadPreBufferRanges() {
278278
if (ranges.empty()) {
279279
return Status::OK();
280280
}
281-
pre_buffer_sink_(std::move(ranges));
281+
pre_buffer_range_callback_(std::move(ranges));
282282
return Status::OK();
283283
}
284284

‎src/paimon/common/reader/late_materializing_file_batch_reader.h‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,18 @@ class LateMaterializingFileBatchReader : public PrefetchFileBatchReader {
9595
Result<std::vector<std::pair<uint64_t, uint64_t>>> PreBufferRange() override {
9696
// Deliberately only the probe ranges: this is asked once before any read, when the payload
9797
// pass still has no idea which pages hold the matched rows. The payload ranges are
98-
// reported through pre_buffer_sink_ once the probe pass has run, see
98+
// reported through pre_buffer_range_callback_ once the probe pass has run, see
9999
// ReportPayloadPreBufferRanges().
100100
if (prefetch_inner_ == nullptr) {
101101
return std::vector<std::pair<uint64_t, uint64_t>>{};
102102
}
103103
return prefetch_inner_->PreBufferRange();
104104
}
105105

106-
void SetPreBufferSink(PreBufferSink sink) override {
106+
void SetPreBufferRangeCallback(PreBufferRangeCallback callback) override {
107107
// Not forwarded to prefetch_inner_: a format reader has no late ranges of its own, and
108108
// forwarding would report the same ranges twice.
109-
pre_buffer_sink_ = std::move(sink);
109+
pre_buffer_range_callback_ = std::move(callback);
110110
}
111111

112112
private:
@@ -149,9 +149,9 @@ class LateMaterializingFileBatchReader : public PrefetchFileBatchReader {
149149
const std::shared_ptr<Predicate>& predicate,
150150
const std::optional<RoaringBitmap32>& selection);
151151

152-
/// Report the byte ranges the payload pass is about to read to pre_buffer_sink_, so that the
153-
/// prefetch layer can fetch them ahead of the pass. A no-op without a sink or without a
154-
/// prefetch-capable inner reader.
152+
/// Report the byte ranges the payload pass is about to read to pre_buffer_range_callback_, so
153+
/// that the prefetch layer can fetch them ahead of the pass. A no-op without a callback or
154+
/// without a prefetch-capable inner reader.
155155
Status ReportPayloadPreBufferRanges();
156156

157157
/// Returns the inner reader's prefetch interface, or an error when the format reader does not
@@ -178,7 +178,7 @@ class LateMaterializingFileBatchReader : public PrefetchFileBatchReader {
178178
std::shared_ptr<arrow::MemoryPool> arrow_pool_;
179179
/// Where the payload byte ranges are reported. Part of how this reader is wired into the
180180
/// prefetch layer rather than of a read generation, so Reset() leaves it alone.
181-
PreBufferSink pre_buffer_sink_;
181+
PreBufferRangeCallback pre_buffer_range_callback_;
182182
LatMatState state_ = kInit;
183183
std::shared_ptr<arrow::Schema> full_schema_;
184184
// projection holding only the predicate fields; nullptr when probing is not applicable

‎src/paimon/common/reader/late_materializing_file_batch_reader_test.cpp‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -766,9 +766,9 @@ TEST_F(LateMaterializingFileBatchReaderTest, FailsOnPredicateTypeMismatch) {
766766
}
767767

768768
// The payload byte ranges are only known once the probe pass has run, so they are reported through
769-
// the sink rather than through PreBufferRange(), and early enough to still be prefetched: before
770-
// the first payload batch leaves the reader.
771-
TEST_F(LateMaterializingFileBatchReaderTest, PayloadPreBufferRangesReportedToSink) {
769+
// the callback rather than through PreBufferRange(), and early enough to still be prefetched:
770+
// before the first payload batch leaves the reader.
771+
TEST_F(LateMaterializingFileBatchReaderTest, PayloadPreBufferRangesReportedToCallback) {
772772
auto data = BuildData({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
773773
auto mock = std::make_unique<MockFileBatchReader>(data, full_type_, /*batch_size=*/3);
774774
// Aliased because a type carrying a comma cannot be passed to the ASSERT_OK_AND_ASSIGN macro.
@@ -781,7 +781,7 @@ TEST_F(LateMaterializingFileBatchReaderTest, PayloadPreBufferRangesReportedToSin
781781
int32_t batches = 0;
782782
std::vector<ByteRanges> reported;
783783
std::vector<int32_t> batches_when_reported;
784-
reader->SetPreBufferSink([&](ByteRanges&& ranges) {
784+
reader->SetPreBufferRangeCallback([&](ByteRanges&& ranges) {
785785
reported.push_back(std::move(ranges));
786786
batches_when_reported.push_back(batches);
787787
});
@@ -811,14 +811,15 @@ TEST_F(LateMaterializingFileBatchReaderTest, PayloadPreBufferRangesReportedToSin
811811
}
812812

813813
// Without a predicate there is no payload pass, so there is no late range to report.
814-
TEST_F(LateMaterializingFileBatchReaderTest, NoSinkReportWithoutLateMaterialization) {
814+
TEST_F(LateMaterializingFileBatchReaderTest, NoCallbackReportWithoutLateMaterialization) {
815815
auto data = BuildData({0, 1, 2, 3, 4});
816816
auto mock = std::make_unique<MockFileBatchReader>(data, full_type_, /*batch_size=*/2);
817817
mock->SetPreBufferRangesPerSchema({{{0, 1024}}, {{100000, 2048}}});
818818
ASSERT_OK_AND_ASSIGN(auto reader, LateMaterializingFileBatchReader::Create(
819819
std::move(mock), GetArrowPool(pool_)));
820820
int32_t calls = 0;
821-
reader->SetPreBufferSink([&calls](std::vector<std::pair<uint64_t, uint64_t>>&&) { calls++; });
821+
reader->SetPreBufferRangeCallback(
822+
[&calls](std::vector<std::pair<uint64_t, uint64_t>>&&) { calls++; });
822823
ASSERT_OK(SetReadSchema(reader.get(), arrow::schema(full_fields_), /*predicate=*/nullptr,
823824
std::nullopt));
824825

@@ -835,7 +836,8 @@ TEST_F(LateMaterializingFileBatchReaderTest, EmptyMatchDoesNotReportPayloadRange
835836
ASSERT_OK_AND_ASSIGN(auto reader, LateMaterializingFileBatchReader::Create(
836837
std::move(mock), GetArrowPool(pool_)));
837838
int32_t calls = 0;
838-
reader->SetPreBufferSink([&calls](std::vector<std::pair<uint64_t, uint64_t>>&&) { calls++; });
839+
reader->SetPreBufferRangeCallback(
840+
[&calls](std::vector<std::pair<uint64_t, uint64_t>>&&) { calls++; });
839841
auto predicate =
840842
PredicateBuilder::GreaterThan(/*field_index=*/0, "k", FieldType::BIGINT, Literal(100l));
841843
ASSERT_OK(SetReadSchema(reader.get(), arrow::schema(full_fields_), predicate, std::nullopt));
@@ -854,7 +856,8 @@ TEST_F(LateMaterializingFileBatchReaderTest, PayloadPreBufferRangeErrorFailsRead
854856
ASSERT_OK_AND_ASSIGN(auto reader, LateMaterializingFileBatchReader::Create(
855857
std::move(mock), GetArrowPool(pool_)));
856858
int32_t calls = 0;
857-
reader->SetPreBufferSink([&calls](std::vector<std::pair<uint64_t, uint64_t>>&&) { calls++; });
859+
reader->SetPreBufferRangeCallback(
860+
[&calls](std::vector<std::pair<uint64_t, uint64_t>>&&) { calls++; });
858861
auto predicate =
859862
PredicateBuilder::GreaterOrEqual(/*field_index=*/0, "k", FieldType::BIGINT, Literal(2l));
860863
ASSERT_OK(SetReadSchema(reader.get(), arrow::schema(full_fields_), predicate, std::nullopt));

‎src/paimon/common/reader/prefetch_file_batch_reader_impl.cpp‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ Result<std::unique_ptr<PrefetchFileBatchReaderImpl>> PrefetchFileBatchReaderImpl
327327
// late-materialization payload pass) report them here instead of through PreBufferRange(),
328328
// which is asked once per read-range generation before any read. Capturing the impl raw is
329329
// safe: it owns readers_, and CleanUp() joins the background thread before it goes away.
330-
sub_reader->SetPreBufferSink(
330+
sub_reader->SetPreBufferRangeCallback(
331331
[impl = reader.get()](std::vector<std::pair<uint64_t, uint64_t>>&& ranges) {
332332
impl->RegisterLatePreBufferRanges(std::move(ranges));
333333
});
@@ -366,7 +366,7 @@ PrefetchFileBatchReaderImpl::PrefetchFileBatchReaderImpl(
366366

367367
PrefetchFileBatchReaderImpl::~PrefetchFileBatchReaderImpl() {
368368
(void)CleanUp();
369-
ClearPreBufferSinks();
369+
ClearPreBufferRangeCallbacks();
370370
}
371371

372372
Status PrefetchFileBatchReaderImpl::SetReadSchema(
@@ -834,11 +834,11 @@ void PrefetchFileBatchReaderImpl::RegisterLatePreBufferRanges(
834834
cache_->Warmup(first_added.value().value());
835835
}
836836

837-
void PrefetchFileBatchReaderImpl::ClearPreBufferSinks() {
838-
// Belt and braces: the sinks capture this, and by now CleanUp() has joined the background
837+
void PrefetchFileBatchReaderImpl::ClearPreBufferRangeCallbacks() {
838+
// Belt and braces: the callbacks capture this, and by now CleanUp() has joined the background
839839
// thread, so no sub-reader can report a range any more.
840840
for (const auto& sub_reader : readers_) {
841-
sub_reader->SetPreBufferSink(nullptr);
841+
sub_reader->SetPreBufferRangeCallback(nullptr);
842842
}
843843
}
844844

@@ -1082,7 +1082,7 @@ void PrefetchFileBatchReaderImpl::Close() {
10821082
for (const auto& reader : readers_) {
10831083
reader->Close();
10841084
}
1085-
ClearPreBufferSinks();
1085+
ClearPreBufferRangeCallbacks();
10861086
}
10871087

10881088
} // namespace paimon

‎src/paimon/common/reader/prefetch_file_batch_reader_impl.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ class PrefetchFileBatchReaderImpl : public PrefetchFileBatchReader {
151151
/// as in WarmCacheOnce().
152152
void RegisterLatePreBufferRanges(std::vector<std::pair<uint64_t, uint64_t>>&& read_ranges);
153153

154-
/// Detaches the sinks installed on the sub-readers, so that a sub-reader outliving this reader
155-
/// cannot call back into it. Called once the background thread has been joined.
156-
void ClearPreBufferSinks();
154+
/// Detaches the callbacks installed on the sub-readers, so that a sub-reader outliving this
155+
/// reader cannot call back into it. Called once the background thread has been joined.
156+
void ClearPreBufferRangeCallbacks();
157157
void SetReadStatus(const Status& status);
158158
Status GetReadStatus() const;
159159
Result<bool> IsEofRange(const std::pair<uint64_t, uint64_t>& read_range) const;

‎src/paimon/common/utils/read_ahead_cache.h‎

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,10 @@ struct RangeCacheEntry {
132132
}
133133
};
134134

135-
/// A read cache designed to hide IO latencies when reading.
136-
/// Prefetching strategy: When a range is read, the cache will prefetch up to
137-
/// `pre_buffer_range_count` additional adjacent ranges ahead of the requested offset. This helps
138-
/// hide I/O latency for sequential access. Example: If you read range [0, 100), and
139-
/// pre_buffer_range_count=2, the next two configured ranges will also be prefetched.
135+
/// A read cache designed to hide IO latency when reading.
136+
/// Prefetching strategy: a Read() (or Warmup()) at an offset publishes and fetches the registered
137+
/// ranges from that offset forward until their cumulative size exceeds `pre_buffer_limit`, so a
138+
/// sequential read runs ahead of the caller instead of fetching one range at a time.
140139
///
141140
/// The cache never evicts: every published range stays cached until
142141
/// ReleaseBuffers() or Reset(). It is meant to hold the prefetched ranges of
@@ -163,19 +162,15 @@ class PAIMON_EXPORT ReadAheadCache {
163162

164163
/// Register byte ranges to prefetch, merging them into the ranges already registered.
165164
///
166-
/// This is the cache's only registration entry point, and it may be called repeatedly and
167-
/// concurrently with Read(): the ranges known up front - a read plan's whole extent - are
168-
/// registered before any Read(), and the ranges that only become known WHILE reading - a
169-
/// late-materialization payload pass learns which pages it needs only after the probe pass has
170-
/// evaluated the predicate - are registered as they are discovered. Read() finds its covering
171-
/// entries by walking a disjoint, offset-ordered list, so of a new range only the part no
172-
/// registered range covers is added; the overlapping part is dropped, as those bytes are
173-
/// already being fetched. A registration is cut into ranges of at most `range_size_limit`
174-
/// bytes, one prefetch IO each, so a large pass is fetched concurrently instead of in one long
175-
/// request.
176-
///
177-
/// Deciding WHICH ranges to register - and in particular not reporting the ranges of a read
178-
/// that has already ended - is the caller's concern; the cache registers whatever it is given.
165+
/// The cache's only registration entry point; safe to call repeatedly and concurrently with
166+
/// Read(). Ranges known up front are registered before any Read(); ranges that only become
167+
/// known while reading (a late-materialization payload pass learns its pages after the probe
168+
/// pass) are registered as they are discovered. The list stays disjoint and offset-ordered, so
169+
/// only the part of a new range that no registered range covers is added - the overlap is
170+
/// dropped, as those bytes are already being fetched - and each registration is cut into ranges
171+
/// of at most `range_size_limit` bytes (one prefetch IO each) so a large pass is fetched
172+
/// concurrently. Which ranges to register, and not reporting those of an ended read, is the
173+
/// caller's concern.
179174
///
180175
/// @param ranges The byte ranges to register.
181176
/// @return The offset of the first newly registered range, or nullopt when nothing was added.
@@ -195,36 +190,33 @@ class PAIMON_EXPORT ReadAheadCache {
195190
/// filled; false on cache miss (`dest` is left untouched).
196191
Result<bool> Read(const ByteRange& range, char* dest);
197192

198-
/// Start fetching the first batch of pending ranges immediately.
199-
/// AddRanges() only registers the ranges; without Warmup() the first fetch starts
200-
/// when the first Read() arrives, racing the caller's own miss fetch.
193+
/// Start fetching from the first registered range forward immediately. AddRanges() only
194+
/// registers the ranges; without Warmup() the first fetch starts when the first Read() arrives,
195+
/// racing the caller's own miss fetch.
201196
void Warmup();
202197

203198
/// Start fetching the registered ranges from `from_offset` forward, bounded by the
204199
/// pre-buffer limit. Warmup() is this call made from the first registered range.
205200
/// @param from_offset The offset to start fetching from, typically one AddRanges() returned.
206201
void Warmup(uint64_t from_offset);
207202

208-
/// Collect the counters of the Read() calls, of the block cache, of the IOs
209-
/// and of the late registrations into the given metrics as counters named
210-
/// after `ReadAheadCacheMetrics`. Only reads issued through Read() are
211-
/// counted as hits, block hits or misses; the fetches the cache dispatches
212-
/// are counted in the io counters instead.
203+
/// Collect the counters of the Read() calls, of the block cache and of the IOs into the given
204+
/// metrics as counters named after `ReadAheadCacheMetrics`. Only reads issued through Read()
205+
/// are counted as hits, block hits or misses; the fetches the cache dispatches are counted in
206+
/// the io counters instead.
213207
/// @param metrics The metrics to write the counters into. A null
214208
/// pointer or a null shared pointer is a no-op.
215209
void CollectMetrics(std::shared_ptr<Metrics>* metrics) const;
216210

217-
/// Reset the cache to its initial state, clearing all cached data and configuration.
218-
///
219-
/// This method waits for all ongoing asynchronous read operations to complete,
220-
/// clears all cached entries, and resets the internal state so a fresh set of ranges can be
221-
/// registered again with AddRanges().
211+
/// Drop the prefetched entries and zero all counters, so a fresh set of ranges can be
212+
/// registered with AddRanges(). Waits for the in-flight fetches before their buffers go away.
222213
///
223-
/// The block cache is kept: it caches the file rather than the registered
224-
/// ranges, and a reader reusing the cache reads the same file again.
214+
/// The block cache is kept - it caches the file rather than the registered ranges, and a reader
215+
/// reusing the cache reads the same file again - but its counters are zeroed too. Unlike
216+
/// ReleaseBuffers(), the counters do not survive.
225217
void Reset();
226218

227-
/// Release all cached buffers and pending ranges while keeping the hit/miss
219+
/// Release all cached buffers and registered ranges while keeping the hit/miss
228220
/// counters intact.
229221
///
230222
/// Unlike Reset(), the counters recorded by Read() remain readable through

0 commit comments

Comments
 (0)