Skip to content

Commit 88f8532

Browse files
authored
Allow heartbeat retries while a realtime TsFile is in flight (#19075)
* Fix realtime TsFile source retry progress * Fix heartbeat ordering test setup
1 parent 76d573a commit 88f8532

2 files changed

Lines changed: 78 additions & 7 deletions

File tree

‎iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/source/dataregion/realtime/PipeRealtimeDataRegionTsFileSource.java‎

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.util.ArrayDeque;
4343
import java.util.Arrays;
4444
import java.util.Deque;
45+
import java.util.Iterator;
4546
import java.util.PriorityQueue;
4647
import java.util.Queue;
4748

@@ -177,7 +178,7 @@ public void close() throws Exception {
177178
public Event supply() {
178179
if (isRegionLevelDowngradingEnabled) {
179180
synchronized (tsFileOrderingLock) {
180-
if (isClosed.get() || inFlightTsFileEpoch != null) {
181+
if (isClosed.get()) {
181182
return null;
182183
}
183184

@@ -191,21 +192,37 @@ public Event supply() {
191192
bufferedEvents.offerLast(pendingEvent);
192193
}
193194
}
194-
return supplyInternal();
195+
// A heartbeat may trigger retry of the in-flight TsFile at the sink. Keep files and other
196+
// events ordered behind it, but do not block those retries while waiting for its commit.
197+
return supplyInternal(inFlightTsFileEpoch != null);
195198
}
196199
}
197-
return supplyInternal();
200+
return supplyInternal(false);
198201
}
199202

200-
private PipeRealtimeEvent pollNextEvent() {
203+
private PipeRealtimeEvent pollNextEvent(final boolean heartbeatOnly) {
201204
if (!isRegionLevelDowngradingEnabled) {
202205
return (PipeRealtimeEvent) pendingQueue.directPoll();
203206
}
207+
if (heartbeatOnly) {
208+
final Iterator<PipeRealtimeEvent> iterator = bufferedEvents.iterator();
209+
while (iterator.hasNext()) {
210+
final PipeRealtimeEvent event = iterator.next();
211+
if (event.getEvent() instanceof PipeHeartbeatEvent) {
212+
if (((PipeHeartbeatEvent) event.getEvent()).isCompletionBarrier()) {
213+
return null;
214+
}
215+
iterator.remove();
216+
return event;
217+
}
218+
}
219+
return null;
220+
}
204221
return orderedTsFileEvents.isEmpty() ? bufferedEvents.pollFirst() : orderedTsFileEvents.poll();
205222
}
206223

207-
private Event supplyInternal() {
208-
PipeRealtimeEvent realtimeEvent = pollNextEvent();
224+
private Event supplyInternal(final boolean heartbeatOnly) {
225+
PipeRealtimeEvent realtimeEvent = pollNextEvent(heartbeatOnly);
209226

210227
while (realtimeEvent != null) {
211228
Event suppliedEvent = null;
@@ -255,7 +272,7 @@ private Event supplyInternal() {
255272
return suppliedEvent;
256273
}
257274

258-
realtimeEvent = pollNextEvent();
275+
realtimeEvent = pollNextEvent(heartbeatOnly);
259276
}
260277

261278
// means the pending queue is empty.

‎iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/source/PipeRealtimeExtractTest.java‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,60 @@ public void testTsFileSourceRegionLevelDowngradingUsesPipeParameters() throws Ex
13331333
}
13341334
}
13351335

1336+
@Test
1337+
public void testTsFileSourceRegionLevelDowngradingSuppliesHeartbeatWhileTsFileIsInFlight()
1338+
throws Exception {
1339+
final PipeTaskMeta pipeTaskMeta = new PipeTaskMeta(MinimumProgressIndex.INSTANCE, 1);
1340+
try (final PipeRealtimeDataRegionTsFileSource extractor =
1341+
createTsFileSourceForTest(
1342+
PipeSourceConstant.SOURCE_REALTIME_REGION_LEVEL_DOWNGRADING_KEY, pipeTaskMeta)) {
1343+
final PipeRealtimeEvent firstEvent =
1344+
extractTsFileForTest(
1345+
extractor,
1346+
pipeTaskMeta,
1347+
createTsFileResource(dataRegion1, "123-1-0-0.tsfile"),
1348+
false);
1349+
final PipeRealtimeEvent secondEvent =
1350+
extractTsFileForTest(
1351+
extractor,
1352+
pipeTaskMeta,
1353+
createTsFileResource(dataRegion1, "123-2-0-0.tsfile"),
1354+
false);
1355+
final PipeRealtimeEvent heartbeat =
1356+
PipeRealtimeEventFactory.createRealtimeEvent(dataRegion1, false);
1357+
Assert.assertTrue(heartbeat.increaseReferenceCount(TEST_REFERENCE_HOLDER));
1358+
extractor.extract(heartbeat);
1359+
final PipeRealtimeEvent completionBarrier =
1360+
PipeRealtimeEventFactory.createCompletionBarrierEvent(dataRegion1);
1361+
Assert.assertTrue(completionBarrier.increaseReferenceCount(TEST_REFERENCE_HOLDER));
1362+
extractor.extract(completionBarrier);
1363+
1364+
// Drain the pending queue before adding another heartbeat so heartbeat coalescing does not
1365+
// discard it behind the completion barrier.
1366+
Assert.assertSame(firstEvent.getEvent(), extractor.supply());
1367+
final PipeRealtimeEvent heartbeatAfterCompletionBarrier =
1368+
PipeRealtimeEventFactory.createRealtimeEvent(dataRegion1, false);
1369+
Assert.assertTrue(
1370+
heartbeatAfterCompletionBarrier.increaseReferenceCount(TEST_REFERENCE_HOLDER));
1371+
extractor.extract(heartbeatAfterCompletionBarrier);
1372+
1373+
Assert.assertSame(heartbeat.getEvent(), extractor.supply());
1374+
Assert.assertNull(extractor.supply());
1375+
Assert.assertFalse(secondEvent.getEvent().isReleased());
1376+
Assert.assertFalse(completionBarrier.getEvent().isReleased());
1377+
Assert.assertFalse(heartbeatAfterCompletionBarrier.getEvent().isReleased());
1378+
1379+
releaseSuppliedEvent(heartbeat.getEvent());
1380+
releaseSuppliedEvent(firstEvent.getEvent());
1381+
Assert.assertSame(secondEvent.getEvent(), extractor.supply());
1382+
releaseSuppliedEvent(secondEvent.getEvent());
1383+
Assert.assertSame(completionBarrier.getEvent(), extractor.supply());
1384+
releaseSuppliedEvent(completionBarrier.getEvent());
1385+
Assert.assertSame(heartbeatAfterCompletionBarrier.getEvent(), extractor.supply());
1386+
releaseSuppliedEvent(heartbeatAfterCompletionBarrier.getEvent());
1387+
}
1388+
}
1389+
13361390
@Test
13371391
public void testTsFileSourceRegionLevelDowngradingFollowsQueryPriority() throws Exception {
13381392
final PipeEventCommitManager commitManager = PipeEventCommitManager.getInstance();

0 commit comments

Comments
 (0)