Skip to content

MINOR: De-duplicate Metered*WithHeaders read-only-record iterators - #22975

Open
Jess668 wants to merge 5 commits into
apache:trunkfrom
Jess668:dedup-metered-withheaders-readonly-iterators
Open

MINOR: De-duplicate Metered*WithHeaders read-only-record iterators#22975
Jess668 wants to merge 5 commits into
apache:trunkfrom
Jess668:dedup-metered-withheaders-readonly-iterators

Conversation

@Jess668

@Jess668 Jess668 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

The read-only-record iterators backing the headers-aware IQv2 query types (MeteredSessionStoreWithHeaders, MeteredTimestampedWindowStoreWithHeaders, MeteredTimestampedKeyValueStoreWithHeaders) each hand-rolled the same metering lifecycle: stamping the open time, registering in numOpenIterators/openIterators, and recording the operation and iterator-duration sensors on close. Only next() genuinely differs per store.

Extract that lifecycle into a shared AbstractMeteredReadOnlyRecordIterator<RawKey, K, V>. Each store's iterator now extends it and implements only next().

Reviewers: Alieh Saeedi asaeedi@confluent.io

@github-actions github-actions Bot added triage PRs from the community streams labels Jul 28, 2026
@github-actions github-actions Bot removed the triage PRs from the community label Aug 5, 2026
…path tests

Broaden the de-duplication per review: rework the shared base into a
lifecycle-only AbstractMeteredIterator<RawKey> implements MeteredIterator
(no longer binds K/V or a result interface), delete the duplicate inner
AbstractMeteredIterator in MeteredTimestampedKeyValueStoreWithHeaders, and
have all seven Metered*WithHeaders iterators extend it while declaring their
own result interface (ReadOnlyRecordIterator or KeyValueIterator).

Add close-path iterator-duration tests: one per test class exercising the
ReadOnlyRecordIterator via its query, plus a shouldTimeIteratorDuration for
the window store's KeyValueIterator sibling (which had no duration coverage),
each asserting the operation and iterator-duration sensors record on close.
@Jess668
Jess668 force-pushed the dedup-metered-withheaders-readonly-iterators branch from be2723b to 151d3a7 Compare August 5, 2026 14:19
*
* @param <RawKey> the raw iterator's key type
*/
abstract class AbstractMeteredIterator<RawKey> implements MeteredIterator {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MeteredWindowedKeyValueIterator, MeteredWindowStoreIterator and MeteredKeyValueStoreIterator still hand-roll this exact lifecycle, field for field. The first is the base of MeteredWindowedKeyValueWithHeadersIterator, so one Metered*WithHeaders iterator is still left out. Should we do a follow-up making them extend this class, after which the javadoc's Metered*WithHeaders scoping can go.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, will do the migration in a follow up to keep this PR scoped to the *WithHeaders extraction

Jess668 added 2 commits August 6, 2026 09:15
…tion tests

- Make AbstractMeteredIterator.startTimestamp() final: the constructor's
  openIterators.add(this) sorts through it via the set's startTimestamp
  comparator, on a half-built object, so a subclass must not be able to
  override it with something that reads its own not-yet-assigned state.
- Tighten the new iterator-duration tests: open two iterators (2ms then 3ms)
  and assert exact avg (2.5ms) and max (3ms) instead of one sample / > 0.0,
  so avg is actually pinned distinctly from max. Applied across the KV,
  session and window ReadOnlyRecord tests and the window KeyValueIterator
  sibling test.
…ation

Bring the session store's sibling-path duration test in line with the KV one
(already two-sample) and the tests added earlier in this PR: open two iterators
(2ms then 3ms) and assert exact avg (2.5ms) and max (3ms) instead of a single
sample / > 0.0, so avg is pinned distinctly from max.
operationSensor.record(duration);
iteratorSensor.record(duration);
numOpenIterators.decrement();
openIterators.remove(this);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openIterators is a ConcurrentSkipListSet keyed only by startTimestamp(), so two iterators opened in the same millisecond collide: the second add is silently dropped and this remove can evict the other, still-open one. Not this PR's to fix, but worth a ticket.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…lose()

- Assert the operation sensor's latency (get-latency-avg / fetch-latency-avg)
  is exactly 2.5ms in the three ReadOnlyRecord duration tests instead of
  > 0.0: that sensor is recorded only from the iterator's close() on these
  paths, so the two samples (2ms, 3ms) average deterministically.
- Make AbstractMeteredIterator.close() final, like startTimestamp(): it owns
  the metering lifecycle (sensor recording, numOpenIterators decrement,
  openIterators deregistration), so a subclass overriding it and forgetting
  super.close() would silently drop the decrement and deregistration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants