Skip to content

Commit 6fa3c81

Browse files
authored
fix(realtime): keep spill outside the write mutex (#384)
1 parent f4157fe commit 6fa3c81

3 files changed

Lines changed: 23 additions & 17 deletions

File tree

‎include/paimon/realtime/realtime_store.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ struct PAIMON_EXPORT RealtimeQueryContext {
145145
/// Customizable plugin interface for storing and querying real-time rows before Paimon data-file
146146
/// generation.
147147
///
148-
/// Paimon serializes calls to `Write` and `SealForCommit` for the same store. After sealing,
148+
/// Calls to `Write` and `SealForCommit` can overlap for the same store. Store implementations must
149+
/// synchronize segment rotation. After rotation, subsequent writes go to the new building segment
150+
/// while the sealed segment may be spilled. After sealing,
149151
/// `CreateCommitReaders` may read the immutable sealed segment while later `Write` calls append to
150152
/// a new building segment. Paimon retains control of file format, rolling, indexes, and
151153
/// commit-message generation. A store may choose its own in-memory representation, indexes, and

‎src/paimon/core/realtime/realtime_append_only_writer.cpp‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,27 +121,29 @@ Status RealtimeAppendOnlyWriter::Write(std::unique_ptr<RecordBatch>&& batch) {
121121
Status RealtimeAppendOnlyWriter::SealCurrentSegment() {
122122
PAIMON_ASSIGN_OR_RAISE(std::optional<std::shared_ptr<RealtimeSegmentHandle>> segment,
123123
realtime_store_->SealForCommit());
124-
if (segment) {
125-
if (!segment.value()) {
126-
return Status::Invalid("append real-time store sealed a null segment");
127-
}
128-
sealed_segments_.push_back(std::move(segment.value()));
129-
has_building_data_ = false;
124+
std::lock_guard<std::mutex> lock(realtime_store_mutex_);
125+
if (!segment) {
126+
return Status::OK();
130127
}
128+
if (!segment.value()) {
129+
return Status::Invalid("append real-time store sealed a null segment");
130+
}
131+
has_building_data_ = next_offset_ > segment.value()->GetOffsetRange().end;
132+
sealed_segments_.push_back(std::move(segment.value()));
131133
return Status::OK();
132134
}
133135

134136
Status RealtimeAppendOnlyWriter::Seal() {
135-
std::lock_guard<std::mutex> lock(realtime_store_mutex_);
137+
std::lock_guard<std::mutex> lock(prepare_mutex_);
136138
return SealCurrentSegment();
137139
}
138140

139141
Result<CommitIncrement> RealtimeAppendOnlyWriter::PrepareCommit(bool wait_compaction) {
140142
std::lock_guard<std::mutex> lock(prepare_mutex_);
143+
PAIMON_RETURN_NOT_OK(SealCurrentSegment());
141144
std::vector<std::shared_ptr<RealtimeSegmentHandle>> segments;
142145
{
143146
std::lock_guard<std::mutex> realtime_store_lock(realtime_store_mutex_);
144-
PAIMON_RETURN_NOT_OK(SealCurrentSegment());
145147
segments.swap(sealed_segments_);
146148
}
147149
for (const std::shared_ptr<RealtimeSegmentHandle>& segment : segments) {

‎src/paimon/core/realtime/realtime_primary_key_writer.cpp‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -209,27 +209,29 @@ Status RealtimePrimaryKeyWriter::Write(std::unique_ptr<RecordBatch>&& batch) {
209209
Status RealtimePrimaryKeyWriter::SealCurrentSegment() {
210210
PAIMON_ASSIGN_OR_RAISE(std::optional<std::shared_ptr<RealtimeSegmentHandle>> segment,
211211
realtime_store_->SealForCommit());
212-
if (segment) {
213-
if (!segment.value()) {
214-
return Status::Invalid("PK real-time store sealed a null segment");
215-
}
216-
sealed_segments_.push_back(std::move(segment.value()));
217-
has_building_data_ = false;
212+
std::lock_guard<std::mutex> lock(realtime_store_mutex_);
213+
if (!segment) {
214+
return Status::OK();
218215
}
216+
if (!segment.value()) {
217+
return Status::Invalid("PK real-time store sealed a null segment");
218+
}
219+
has_building_data_ = next_offset_ > segment.value()->GetOffsetRange().end;
220+
sealed_segments_.push_back(std::move(segment.value()));
219221
return Status::OK();
220222
}
221223

222224
Status RealtimePrimaryKeyWriter::Seal() {
223-
std::lock_guard<std::mutex> lock(realtime_store_mutex_);
225+
std::lock_guard<std::mutex> lock(prepare_mutex_);
224226
return SealCurrentSegment();
225227
}
226228

227229
Result<CommitIncrement> RealtimePrimaryKeyWriter::PrepareCommit(bool wait_compaction) {
228230
std::lock_guard<std::mutex> prepare_lock(prepare_mutex_);
231+
PAIMON_RETURN_NOT_OK(SealCurrentSegment());
229232
std::vector<std::shared_ptr<RealtimeSegmentHandle>> segments;
230233
{
231234
std::lock_guard<std::mutex> store_lock(realtime_store_mutex_);
232-
PAIMON_RETURN_NOT_OK(SealCurrentSegment());
233235
segments.swap(sealed_segments_);
234236
}
235237
for (const std::shared_ptr<RealtimeSegmentHandle>& segment : segments) {

0 commit comments

Comments
 (0)