Skip to content

Commit 83d7bae

Browse files
committed
feat(metrics): expose scan and prefetch metrics
1 parent 33d5eef commit 83d7bae

22 files changed

Lines changed: 1094 additions & 28 deletions

‎docs/source/user_guide.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ User Guide
3838
user_guide/commit
3939
user_guide/compaction
4040
user_guide/read
41+
user_guide/metrics
4142
user_guide/clean
4243
user_guide/prefetch
4344
user_guide/arrow

‎docs/source/user_guide/metrics.rst‎

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
.. Licensed to the Apache Software Foundation (ASF) under one
2+
.. or more contributor license agreements. See the NOTICE file
3+
.. distributed with this work for additional information
4+
.. regarding copyright ownership. The ASF licenses this file
5+
.. to you under the Apache License, Version 2.0 (the
6+
.. "License"); you may not use this file except in compliance
7+
.. with the License. You may obtain a copy of the License at
8+
9+
.. http://www.apache.org/licenses/LICENSE-2.0
10+
11+
.. Unless required by applicable law or agreed to in writing,
12+
.. software distributed under the License is distributed on an
13+
.. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
.. KIND, either express or implied. See the License for the
15+
.. specific language governing permissions and limitations
16+
.. under the License.
17+
18+
Metrics reference
19+
=================
20+
21+
``Metrics`` contains counters, gauges, and histogram snapshots. A counter is a non-negative
22+
integer, a gauge represents current state, and a histogram records a distribution of observed
23+
values. The scan, prefetch-reader, and read-ahead-cache metrics described below are returned as
24+
point-in-time snapshots. Modifying a returned snapshot does not modify the component that produced
25+
it.
26+
27+
Scan planning
28+
-------------
29+
30+
The names below are declared by ``ScanMetrics``. ``last*`` counters are replaced after each
31+
successful ``CreatePlan()`` call. Histograms and the cache hit/miss counters accumulate for the
32+
lifetime of the scan. They are unrelated to ``SetReadSchema()`` and ``ReadAheadCache::Reset()``.
33+
34+
.. csv-table::
35+
:header: "Name", "Type", "Unit", "Meaning"
36+
:widths: 34, 12, 12, 52
37+
38+
"lastScanDuration", "counter", "milliseconds", "Duration of the last successful plan"
39+
"scanDuration", "histogram", "milliseconds", "Distribution of successful plan durations"
40+
"lastScannedSnapshotId", "counter", "snapshot ID", "Snapshot used by the last plan, or 0"
41+
"lastScannedManifests", "counter", "files", "Manifest files selected by the last plan"
42+
"lastScanSkippedTableFiles", "counter", "files", "Table files skipped by the last plan"
43+
"lastScanResultedTableFiles", "counter", "files", "Table files returned by the last plan"
44+
"lastManifestReadDuration", "counter", "milliseconds", "Manifest-list and entry read time for the last plan"
45+
"manifestReadDuration", "histogram", "milliseconds", "Distribution of manifest read times"
46+
"lastSnapshotCacheEnabled", "counter", "boolean", "Whether snapshot manifest-entry cache was eligible"
47+
"lastSnapshotCacheHit", "counter", "boolean", "Whether the last eligible lookup hit"
48+
"snapshotCacheHits", "counter", "lookups", "Cumulative exact-snapshot cache hits"
49+
"snapshotCacheMisses", "counter", "lookups", "Cumulative eligible cache misses"
50+
"lastSnapshotCacheLoadDuration", "counter", "milliseconds", "Cache load time for the last plan"
51+
"snapshotCacheLoadDuration", "histogram", "milliseconds", "Distribution of cache load times"
52+
"lastSnapshotCacheStoreDuration", "counter", "milliseconds", "Cache store time for the last plan; 0 when not stored"
53+
"snapshotCacheStoreDuration", "histogram", "milliseconds", "Distribution of cache store times"
54+
"lastLazyDecodeScannedRows", "counter", "manifest rows", "Candidate manifest rows inspected by the last plan"
55+
"lastLazyDecodeMaterializedRows", "counter", "manifest rows", "Manifest rows retained after lazy filtering"
56+
57+
Prefetch reader
58+
---------------
59+
60+
The names below are declared by ``PrefetchMetrics``. Counters and histograms accumulate for the
61+
lifetime of the prefetch reader, including across ``SetReadSchema()``. ``enabled`` and
62+
``parallelism`` describe the most recently initialized schema. ``queue-depth`` is reset by
63+
``SetReadSchema()`` and ``Close()``; ``queue-depth.max`` remains the lifetime maximum.
64+
65+
.. csv-table::
66+
:header: "Name", "Type", "Unit", "Meaning"
67+
:widths: 38, 12, 12, 48
68+
69+
"prefetch.enabled", "gauge", "boolean", "Whether the most recently initialized schema selected prefetch"
70+
"prefetch.parallelism", "gauge", "readers", "Effective reader parallelism"
71+
"prefetch.read-ranges.total", "counter", "ranges", "Generated ranges before bitmap filtering"
72+
"prefetch.read-ranges.after-bitmap", "counter", "ranges", "Ranges retained after bitmap filtering"
73+
"prefetch.seek.count", "counter", "operations", "Underlying reader seek operations"
74+
"prefetch.produced-batches", "counter", "batches", "Data batches placed into prefetch queues"
75+
"prefetch.consumed-batches", "counter", "batches", "Data batches returned to the consumer"
76+
"prefetch.discarded-batches", "counter", "batches", "Data batches released without consumption, plus EOF entries released during cleanup"
77+
"prefetch.errors", "counter", "errors", "Errors recorded by the background prefetch loop"
78+
"prefetch.adaptive-disabled-count", "counter", "decisions", "Times adaptive strategy disabled prefetch"
79+
"prefetch.queue-full-count", "counter", "events", "Times production found a full queue"
80+
"prefetch.queue-depth", "gauge", "queue entries", "Current queued entries, including retained EOF markers"
81+
"prefetch.queue-depth.max", "gauge", "queue entries", "Maximum queued entries in the reader lifetime"
82+
"prefetch.reader-read-latency-us", "histogram", "microseconds", "Underlying reader batch latency"
83+
"prefetch.consumer-wait-latency-us", "histogram", "microseconds", "Consumer wait latency per returned batch or EOF"
84+
85+
Prefetch I/O
86+
------------
87+
88+
``PrefetchIoMetrics`` describes only I/O that passes through the prefetch reader's instrumented
89+
input streams. It is not a whole-query or whole-table I/O total. All counters and histograms
90+
accumulate for the reader lifetime and are retained across ``SetReadSchema()`` and cache reset.
91+
``io.async.pending`` is current state and returns to zero when all callbacks complete.
92+
93+
.. csv-table::
94+
:header: "Name", "Type", "Unit", "Meaning"
95+
:widths: 34, 12, 12, 52
96+
97+
"io.read.requests", "counter", "requests", "Synchronous read requests"
98+
"io.read.requested-bytes", "counter", "bytes", "Bytes requested by synchronous reads"
99+
"io.read.physical-bytes", "counter", "bytes", "Bytes returned by successful synchronous reads"
100+
"io.read.failed", "counter", "requests", "Failed synchronous reads"
101+
"io.read.latency-us", "histogram", "microseconds", "Synchronous read latency"
102+
"io.async.requests", "counter", "requests", "Asynchronous read requests"
103+
"io.async.requested-bytes", "counter", "bytes", "Bytes requested by asynchronous reads"
104+
"io.async.physical-bytes", "counter", "bytes", "Bytes attributed to successful asynchronous reads"
105+
"io.async.completed", "counter", "requests", "Successful asynchronous reads"
106+
"io.async.failed", "counter", "requests", "Failed asynchronous reads"
107+
"io.async.pending", "gauge", "requests", "Asynchronous callbacks not yet completed"
108+
"io.async.latency-us", "histogram", "microseconds", "Asynchronous callback latency"
109+
110+
Read-ahead cache
111+
----------------
112+
113+
The names below are declared by ``ReadAheadCacheMetrics``. Request, byte, completion, failure,
114+
eviction, and latency metrics accumulate for the cache lifetime. ``Reset()`` clears cached and
115+
pending ranges but retains those cumulative metrics. The three gauges describe current state and
116+
``cached-ranges`` and ``cached-bytes`` become zero after reset. ``pending-requests`` is not forcibly
117+
reset; it continues to track asynchronous callbacks until they complete.
118+
119+
.. csv-table::
120+
:header: "Name", "Type", "Unit", "Meaning"
121+
:widths: 44, 12, 12, 42
122+
123+
"read-ahead-cache.lookup-requests", "counter", "requests", "Cache lookup requests"
124+
"read-ahead-cache.lookup-bytes", "counter", "bytes", "Bytes requested by lookups"
125+
"read-ahead-cache.served-requests", "counter", "requests", "Lookups served from cache"
126+
"read-ahead-cache.served-bytes", "counter", "bytes", "Bytes served from cache"
127+
"read-ahead-cache.miss-requests", "counter", "requests", "Cache misses"
128+
"read-ahead-cache.miss-bytes", "counter", "bytes", "Bytes requested by misses"
129+
"read-ahead-cache.wait-requests", "counter", "requests", "Lookups that waited for prefetch"
130+
"read-ahead-cache.wait-bytes", "counter", "bytes", "Bytes requested by waiting lookups"
131+
"read-ahead-cache.prefetch-requests", "counter", "requests", "Asynchronous cache fills"
132+
"read-ahead-cache.prefetch-bytes", "counter", "bytes", "Bytes requested by cache fills"
133+
"read-ahead-cache.prefetch-completed", "counter", "requests", "Successful cache fills"
134+
"read-ahead-cache.prefetch-failed", "counter", "requests", "Failed cache fills"
135+
"read-ahead-cache.evicted-ranges", "counter", "ranges", "Ranges evicted by the size limit"
136+
"read-ahead-cache.evicted-bytes", "counter", "bytes", "Bytes evicted by the size limit"
137+
"read-ahead-cache.cached-ranges", "gauge", "ranges", "Ranges currently held in cache"
138+
"read-ahead-cache.cached-bytes", "gauge", "bytes", "Bytes currently held in cache"
139+
"read-ahead-cache.pending-requests", "gauge", "requests", "Cache fills awaiting callbacks"
140+
"read-ahead-cache.wait-latency-us", "histogram", "microseconds", "Time lookups wait for cache fills"
141+
"read-ahead-cache.prefetch-io-latency-us", "histogram", "microseconds", "Cache-fill I/O latency"

‎include/paimon/reader/prefetch_file_batch_reader.h‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,43 @@
2727

2828
namespace paimon {
2929

30+
class PAIMON_EXPORT PrefetchMetrics {
31+
public:
32+
static constexpr char ENABLED[] = "prefetch.enabled";
33+
static constexpr char PARALLELISM[] = "prefetch.parallelism";
34+
static constexpr char READ_RANGES_TOTAL[] = "prefetch.read-ranges.total";
35+
static constexpr char READ_RANGES_AFTER_BITMAP[] = "prefetch.read-ranges.after-bitmap";
36+
static constexpr char SEEK_COUNT[] = "prefetch.seek.count";
37+
static constexpr char PRODUCED_BATCHES[] = "prefetch.produced-batches";
38+
static constexpr char CONSUMED_BATCHES[] = "prefetch.consumed-batches";
39+
static constexpr char DISCARDED_BATCHES[] = "prefetch.discarded-batches";
40+
static constexpr char ERRORS[] = "prefetch.errors";
41+
static constexpr char ADAPTIVE_DISABLED_COUNT[] = "prefetch.adaptive-disabled-count";
42+
static constexpr char QUEUE_FULL_COUNT[] = "prefetch.queue-full-count";
43+
static constexpr char QUEUE_DEPTH[] = "prefetch.queue-depth";
44+
static constexpr char QUEUE_DEPTH_MAX[] = "prefetch.queue-depth.max";
45+
static constexpr char READER_READ_LATENCY_US[] = "prefetch.reader-read-latency-us";
46+
static constexpr char CONSUMER_WAIT_LATENCY_US[] = "prefetch.consumer-wait-latency-us";
47+
};
48+
49+
/// Metric names for I/O observed by the prefetch reader's instrumented input streams.
50+
/// These metrics do not represent whole-query or whole-table I/O.
51+
class PAIMON_EXPORT PrefetchIoMetrics {
52+
public:
53+
static constexpr char READ_REQUESTS[] = "io.read.requests";
54+
static constexpr char READ_REQUESTED_BYTES[] = "io.read.requested-bytes";
55+
static constexpr char READ_PHYSICAL_BYTES[] = "io.read.physical-bytes";
56+
static constexpr char READ_FAILED[] = "io.read.failed";
57+
static constexpr char READ_LATENCY_US[] = "io.read.latency-us";
58+
static constexpr char ASYNC_REQUESTS[] = "io.async.requests";
59+
static constexpr char ASYNC_REQUESTED_BYTES[] = "io.async.requested-bytes";
60+
static constexpr char ASYNC_PHYSICAL_BYTES[] = "io.async.physical-bytes";
61+
static constexpr char ASYNC_COMPLETED[] = "io.async.completed";
62+
static constexpr char ASYNC_FAILED[] = "io.async.failed";
63+
static constexpr char ASYNC_PENDING[] = "io.async.pending";
64+
static constexpr char ASYNC_LATENCY_US[] = "io.async.latency-us";
65+
};
66+
3067
/// The prefetch file batch reader extends the basic FileBatchReader interface for prefetch read,
3168
/// if a format implementation inherits from this class, it will automatically support the C++
3269
/// Paimon prefetch capability and integrate with the Paimon prefetch framework.

src/paimon/core/operation/metrics/scan_metrics.h renamed to include/paimon/table/source/scan_metrics.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818

1919
#pragma once
2020

21+
#include "paimon/visibility.h"
22+
2123
namespace paimon {
2224

23-
/// Metrics to measure scan operation.
24-
class ScanMetrics {
25+
/// Metric names for scan planning operations.
26+
class PAIMON_EXPORT ScanMetrics {
2527
public:
2628
static constexpr char LAST_SCAN_DURATION[] = "lastScanDuration";
2729
// Histogram metric for scan plan duration (milliseconds).
@@ -30,6 +32,21 @@ class ScanMetrics {
3032
static constexpr char LAST_SCANNED_MANIFESTS[] = "lastScannedManifests";
3133
static constexpr char LAST_SCAN_SKIPPED_TABLE_FILES[] = "lastScanSkippedTableFiles";
3234
static constexpr char LAST_SCAN_RESULTED_TABLE_FILES[] = "lastScanResultedTableFiles";
35+
static constexpr char LAST_MANIFEST_READ_DURATION[] = "lastManifestReadDuration";
36+
// Histogram metric for manifest-list and manifest-entry read duration (milliseconds).
37+
static constexpr char MANIFEST_READ_DURATION[] = "manifestReadDuration";
38+
static constexpr char LAST_SNAPSHOT_CACHE_ENABLED[] = "lastSnapshotCacheEnabled";
39+
static constexpr char LAST_SNAPSHOT_CACHE_HIT[] = "lastSnapshotCacheHit";
40+
static constexpr char SNAPSHOT_CACHE_HITS[] = "snapshotCacheHits";
41+
static constexpr char SNAPSHOT_CACHE_MISSES[] = "snapshotCacheMisses";
42+
static constexpr char LAST_SNAPSHOT_CACHE_LOAD_DURATION[] = "lastSnapshotCacheLoadDuration";
43+
static constexpr char SNAPSHOT_CACHE_LOAD_DURATION[] = "snapshotCacheLoadDuration";
44+
static constexpr char LAST_SNAPSHOT_CACHE_STORE_DURATION[] = "lastSnapshotCacheStoreDuration";
45+
static constexpr char SNAPSHOT_CACHE_STORE_DURATION[] = "snapshotCacheStoreDuration";
46+
// Candidate manifest-entry rows inspected by lazy scan filtering.
47+
static constexpr char LAST_LAZY_DECODE_SCANNED_ROWS[] = "lastLazyDecodeScannedRows";
48+
// Full manifest entries retained after lazy scan filtering.
49+
static constexpr char LAST_LAZY_DECODE_MATERIALIZED_ROWS[] = "lastLazyDecodeMaterializedRows";
3350
};
3451

3552
} // namespace paimon

‎include/paimon/table/source/table_scan.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include "paimon/result.h"
2525
#include "paimon/table/source/plan.h"
26+
#include "paimon/table/source/scan_metrics.h"
2627
#include "paimon/type_fwd.h"
2728
#include "paimon/visibility.h"
2829

@@ -44,5 +45,11 @@ class PAIMON_EXPORT TableScan {
4445
///
4546
/// @return A Result containing a shared pointer to the created `Plan` or an error status.
4647
virtual Result<std::shared_ptr<Plan>> CreatePlan() = 0;
48+
49+
/// Retrieve metrics related to scan planning operations.
50+
///
51+
/// @return A point-in-time snapshot of scan metrics. Mutating the returned object does not
52+
/// affect metrics collected by this scan.
53+
virtual std::shared_ptr<Metrics> GetMetrics() const;
4754
};
4855
} // namespace paimon

‎include/paimon/utils/read_ahead_cache.h‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@
3535

3636
namespace paimon {
3737

38+
class Metrics;
39+
40+
class PAIMON_EXPORT ReadAheadCacheMetrics {
41+
public:
42+
static constexpr char LOOKUP_REQUESTS[] = "read-ahead-cache.lookup-requests";
43+
static constexpr char LOOKUP_BYTES[] = "read-ahead-cache.lookup-bytes";
44+
static constexpr char SERVED_REQUESTS[] = "read-ahead-cache.served-requests";
45+
static constexpr char SERVED_BYTES[] = "read-ahead-cache.served-bytes";
46+
static constexpr char MISS_REQUESTS[] = "read-ahead-cache.miss-requests";
47+
static constexpr char MISS_BYTES[] = "read-ahead-cache.miss-bytes";
48+
static constexpr char WAIT_REQUESTS[] = "read-ahead-cache.wait-requests";
49+
static constexpr char WAIT_BYTES[] = "read-ahead-cache.wait-bytes";
50+
static constexpr char PREFETCH_REQUESTS[] = "read-ahead-cache.prefetch-requests";
51+
static constexpr char PREFETCH_BYTES[] = "read-ahead-cache.prefetch-bytes";
52+
static constexpr char PREFETCH_COMPLETED[] = "read-ahead-cache.prefetch-completed";
53+
static constexpr char PREFETCH_FAILED[] = "read-ahead-cache.prefetch-failed";
54+
static constexpr char EVICTED_RANGES[] = "read-ahead-cache.evicted-ranges";
55+
static constexpr char EVICTED_BYTES[] = "read-ahead-cache.evicted-bytes";
56+
static constexpr char CACHED_RANGES[] = "read-ahead-cache.cached-ranges";
57+
static constexpr char CACHED_BYTES[] = "read-ahead-cache.cached-bytes";
58+
static constexpr char PENDING_REQUESTS[] = "read-ahead-cache.pending-requests";
59+
static constexpr char WAIT_LATENCY_US[] = "read-ahead-cache.wait-latency-us";
60+
static constexpr char PREFETCH_IO_LATENCY_US[] = "read-ahead-cache.prefetch-io-latency-us";
61+
};
62+
3863
/// PrefetchCacheMode
3964
/// Cache prefetch switch modes.
4065
/// Controls whether to enable cache prefetching under different circumstances, such as queries with
@@ -175,6 +200,9 @@ class PAIMON_EXPORT ReadAheadCache {
175200
/// After calling Reset, the cache can be safely re-initialized with new ranges.
176201
void Reset();
177202

203+
/// Return a point-in-time snapshot of cumulative cache metrics.
204+
std::shared_ptr<Metrics> GetMetrics() const;
205+
178206
private:
179207
class Impl;
180208
std::unique_ptr<Impl> impl_;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class DelegatingPrefetchReader : public FileBatchReader {
4545
}
4646

4747
std::shared_ptr<Metrics> GetReaderMetrics() const override {
48-
return GetReader()->GetReaderMetrics();
48+
return prefetch_reader_->GetReaderMetrics();
4949
}
5050

5151
Result<std::unique_ptr<::ArrowSchema>> GetFileSchema() const override {

0 commit comments

Comments
 (0)