MINOR: De-duplicate Metered*WithHeaders read-only-record iterators - #22975
MINOR: De-duplicate Metered*WithHeaders read-only-record iterators#22975Jess668 wants to merge 5 commits into
Conversation
…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.
be2723b to
151d3a7
Compare
| * | ||
| * @param <RawKey> the raw iterator's key type | ||
| */ | ||
| abstract class AbstractMeteredIterator<RawKey> implements MeteredIterator { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
agreed, will do the migration in a follow up to keep this PR scoped to the *WithHeaders extraction
…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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
…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.
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. Onlynext()genuinely differs per store.Extract that lifecycle into a shared
AbstractMeteredReadOnlyRecordIterator<RawKey, K, V>. Each store's iterator now extends it and implements onlynext().Reviewers: Alieh Saeedi asaeedi@confluent.io