Skip to content

[FLINK-40584][state/rocksdb] Bound MapState and timer prefix iterators - #29209

Open
Savonitar wants to merge 3 commits into
apache:masterfrom
Savonitar:fix/rocksdb-prefix-iterator-bounds
Open

Savonitar wants to merge 3 commits into
apache:masterfrom
Savonitar:fix/rocksdb-prefix-iterator-bounds

Conversation

@Savonitar

@Savonitar Savonitar commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of the change

RocksDB MapState and timer iterators currently check their key prefix in Java after a native seek returns. When state contains many tombstones, RocksDB can scan through unrelated key ranges while searching for the next live entry. This increases CPU usage during state access and can significantly delay timer queue initialization after restore, which performs a seek for every assigned key group.
This change sets a native exclusive upper bound for each iterator, limiting it to the map’s key-group/key/namespace prefix or the timer queue’s key-group prefix. It prevents scanning unrelated tombstones while preserving the intended results. The change also guards exhausted MapState resume seeks before advancing and clears inherited seek restrictions on the private options copy so they cannot omit valid entries.

Brief change log

  • Check iterator validity before advancing after a MapState cache-refill seek.
  • Bound MapState iteration, isEmpty(), and clear() to the current key-group/key/namespace prefix, and timer iteration to its key-group prefix.
  • Give each bounded iterator its own ReadOptions and upper-bound Slice, closing them together with the native iterator.
  • Enable auto-prefix mode and clear inherited prefix and lower-bound restrictions on the private options copy.

Verifying this change

This change added tests and can be verified as follows:

  • Added RocksDBMapStateTest coverage for exhausted resume seeks and operations next to tombstone-heavy neighboring maps.
  • Extended KeyGroupPartitionedPriorityQueueWithRocksDBStoreTest to verify bounded seeks during timer queue initialization and cache refill.
  • Added RocksDBPrefixIteratorTest coverage for prefix-end calculation, native iteration boundaries, prefix extractors, inherited read options, snapshots, and resource cleanup.
  • Confirmed that the relevant regression tests fail when the bounds, validity guard, or read-option protections are removed.
  • Verified locally with JDK 17: all 51 focused cases passed, and the full RocksDB module unit suite completed with 881 executed cases passing. Spotless and Checkstyle passed.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): (no)
  • The public API, i.e., is any changed class annotated with @Public(Evolving): (no)
  • The serializers: (no)
  • The runtime per-record code paths (performance sensitive): (yes RocksDB MapState access and timer queue operations)
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Kubernetes/Yarn, ZooKeeper: (yes, timer queue initialization during state restoration, e.g. after recovery)
  • The S3 file system connector: (no)

Documentation

  • Does this pull request introduce a new feature? (no)
  • If yes, how is the feature documented? (no)

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Fable 5.1

…advancing

Cache refill can seek past the last entry after MapState.remove() deletes
the resume key. That removal does not update the cached deletion flag,
so advancing the exhausted iterator violates the RocksDB API contract.
Stop native MapState and timer seeks at the end of their key/namespace
or key-group prefix instead of traversing unrelated tombstones during
state access and timer queue initialization.

Generated-by: Claude Fable 5.1
…nded iterators

The bounded iterator copies the backend's ReadOptions, so a prefixSameAsStart
or iterate_lower_bound set globally by an options factory would carry over
and silently drop keys inside the bound: the first stops at the next
extracted prefix, the second clamps the seek. Clear both on the private
copy, the shared options stay untouched.
@Savonitar

Copy link
Copy Markdown
Contributor Author

cc: @pnowojski

@flinkbot

flinkbot commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

@pnowojski pnowojski left a comment

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.

I have previously reviewed internal version of this PR. We have verified it on our production to resolve the performance issue when there are a lot of uncompacted deletion markers in the SST files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants