Skip to content

feat(realtime): support two-stage scan and read - #199

Open
lxy-9602 wants to merge 5 commits into
apache:mainfrom
lxy-9602:rt-real-time-split
Open

feat(realtime): support two-stage scan and read#199
lxy-9602 wants to merge 5 commits into
apache:mainfrom
lxy-9602:rt-real-time-split

Conversation

@lxy-9602

Copy link
Copy Markdown
Collaborator

Purpose

Linked issue: #158

This PR extends the real-time append read path introduced in #163 to support separate scan and
reader creation stages.

The main changes are:

  • capture immutable memory views during scan planning and register them in RealtimeContext;
  • add version, snapshot id, partition-bucket, committed offset, memory upper offset, and an opaque
    read-view ticket to RealtimeSplit;
  • allow ReadContext to share the same RealtimeContext used by the writer and scanner;
  • resolve the ticket when creating a reader and validate that its partition-bucket and offset range
    match the split;
  • use RealtimeReader to keep the memory view alive while disk and memory data are being read;
  • release abandoned or completed read views through a background release queue, avoiding large
    segment destruction on the query thread;
  • preserve an already-created reader across commit, refresh, and memory-segment reclamation.

A real-time split ticket is currently single-use. Once reader creation consumes the ticket, retrying
the same reader task requires creating a new scan plan and RealtimeSplit. Tickets are also
process-local and must be resolved by the RealtimeContext that created them.

Tests

Added or updated coverage for:

  • pinning, resolving, and releasing a read-view ticket;
  • expiration and cleanup of abandoned read-view tickets;
  • rejection when the same RealtimeSplit ticket is reused;
  • reading from a reader created before commit and refresh after its memory segment is reclaimed;
  • reading a pinned plan after writer close;
  • updated Arrow memory-indexer reader ownership.

API and Format

This PR changes public APIs:

  • adds ReadContextBuilder::WithRealtimeContext;
  • adds read-view ticket lifecycle APIs to RealtimeContext;
  • adds RealtimeReader, which keeps a MemReadView alive for the reader lifetime;
  • changes MemIndexer::CreateQueryReaders to return RealtimeReader instances.

There is no change to the Paimon table storage format, data-file format, snapshot format, or commit
protocol.

RealtimeSplit carries versioned real-time metadata, but cross-process split serialization is not
implemented in this PR. Its opaque ticket is currently resolved only inside the originating process.

Documentation

Generative AI tooling

Generated-by: OpenAI Codex (GPT-5)

Comment thread include/paimon/defs.h Outdated
Comment thread src/paimon/core/core_options.cpp Outdated

@zjw1111 zjw1111 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Concurrent consumption of the same real-time split needs to be prevented.

Comment thread src/paimon/core/realtime/realtime_context.cpp Outdated
Comment thread src/paimon/core/realtime/realtime_context_test.cpp Outdated
Comment thread include/paimon/realtime/mem_indexer.h Outdated
Comment thread src/paimon/core/table/source/append_only_table_read.cpp Outdated
Comment thread include/paimon/realtime/realtime_context.h Outdated
std::shared_ptr<MemReadView> read_view;
};

class RealtimeContextImpl final : public RealtimeContext {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This class is compiled under the repository-wide -fvisibility=hidden, but realtime_context_test.cpp and realtime_write_inte_test.cpp call its out-of-line methods while their executables link against paimon_shared. Those methods are therefore private/hidden in the shared library (for example Cast, GetOrCreateMemIndexer, and ResolveReadView), so the test link will fail with undefined symbols. Please either export the test-used class/symbols, link this implementation into those tests, or exercise it through public APIs.

RealtimeReader::Create(memory.read_view, std::move(memory_reader)));
readers.push_back(std::move(realtime_reader));
}
PAIMON_RETURN_NOT_OK(realtime_context_impl->ReleaseReadView(realtime_split->OpaqueTicket()));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This consumes the ticket before the public TableRead::CreateReader(vector<Split>) call has succeeded as a whole. With two real-time splits, split 1 can release its ticket here and split 2 can then fail (for example, a plugin error or ticket expiry); the vector overload returns an error, but retrying that failed call now fails on split 1 because its ticket is gone. Please make the ticket claims/consumption rollbackable across the vector overload, or defer consumption until all per-split readers have been created, and add a two-split regression test.

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