|
20 | 20 | package org.apache.iotdb.db.storageengine.load; |
21 | 21 |
|
22 | 22 | import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot; |
| 23 | +import org.apache.iotdb.commons.consensus.index.ProgressIndex; |
| 24 | +import org.apache.iotdb.commons.consensus.index.impl.RecoverProgressIndex; |
23 | 25 | import org.apache.iotdb.commons.queryengine.plan.planner.plan.node.PlanNodeId; |
24 | 26 | import org.apache.iotdb.consensus.iot.log.ConsensusReqReader; |
25 | 27 | import org.apache.iotdb.db.conf.IoTDBConfig; |
26 | 28 | import org.apache.iotdb.db.conf.IoTDBDescriptor; |
27 | 29 | import org.apache.iotdb.db.exception.load.LoadFileException; |
| 30 | +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; |
| 31 | +import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; |
| 32 | +import org.apache.iotdb.db.pipe.processor.iotconsensusv2.IoTConsensusV2Processor; |
28 | 33 | import org.apache.iotdb.db.queryengine.plan.planner.plan.node.load.LoadTsFileConsensusNode; |
29 | 34 | import org.apache.iotdb.db.queryengine.plan.planner.plan.node.load.LoadTsFileConsensusOp; |
30 | 35 | import org.apache.iotdb.db.queryengine.plan.scheduler.load.ChunkOffsetCalculator; |
31 | 36 | import org.apache.iotdb.db.storageengine.dataregion.DataRegion; |
32 | 37 | import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; |
| 38 | +import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResourceStatus; |
33 | 39 | import org.apache.iotdb.db.storageengine.dataregion.wal.node.IWALNode; |
34 | 40 | import org.apache.iotdb.db.storageengine.dataregion.wal.node.WALNode; |
35 | 41 | import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALMode; |
@@ -798,6 +804,70 @@ public void testStagedDirectoryWithoutTerminalRecordIsKeptOnRecovery() throws Ex |
798 | 804 | assertFalse(manager.prepare(prepareNode("in-progress-load"), Collections.emptyMap())); |
799 | 805 | } |
800 | 806 |
|
| 807 | + @Test |
| 808 | + public void testIoTConsensusV2CommitUsesReceivingNodeProgress() throws Exception { |
| 809 | + assertCommittedProgress(true, config.getDataNodeId() + 1); |
| 810 | + } |
| 811 | + |
| 812 | + @Test |
| 813 | + public void testIoTConsensusV2CommitAdvancesPreparedProgress() throws Exception { |
| 814 | + assertCommittedProgress(true, config.getDataNodeId()); |
| 815 | + } |
| 816 | + |
| 817 | + @Test |
| 818 | + public void testOtherConsensusCommitPreservesCoordinatorProgress() throws Exception { |
| 819 | + assertCommittedProgress(false, config.getDataNodeId() + 1); |
| 820 | + } |
| 821 | + |
| 822 | + private void assertCommittedProgress(final boolean useIoTConsensusV2, final int coordinatorNodeId) |
| 823 | + throws Exception { |
| 824 | + LoadConsensusCompat.setIoTConsensusV2ForTest(useIoTConsensusV2); |
| 825 | + final String loadId = "load-progress"; |
| 826 | + final LoadTsFileManager manager = new LoadTsFileManager(dataRegion); |
| 827 | + try { |
| 828 | + emulateStagedFileImport(); |
| 829 | + final LoadTsFileConsensusNode piece = stagedPiece(loadId, laidOutChunk()); |
| 830 | + manager.writePiece(piece); |
| 831 | + final File staged = new File(tempDir, piece.getPieceRefs().get(0).getRelativePath()); |
| 832 | + final RecoverProgressIndex preparedLocalProgress = |
| 833 | + PipeDataNodeAgent.runtime().getNextProgressIndexForTsFileLoad(); |
| 834 | + final ProgressIndex coordinatorProgress = |
| 835 | + new RecoverProgressIndex( |
| 836 | + coordinatorNodeId, |
| 837 | + preparedLocalProgress.getDataNodeId2LocalIndex().get(config.getDataNodeId())); |
| 838 | + assertTrue( |
| 839 | + manager.prepare( |
| 840 | + prepareNode(loadId), |
| 841 | + Collections.singletonMap(new TTimePartitionSlot(0L), coordinatorProgress))); |
| 842 | + |
| 843 | + // A local write after PREPARE must precede the progress assigned when the file is imported. |
| 844 | + final ProgressIndex interveningWrite = |
| 845 | + PipeDataNodeAgent.runtime().getNextProgressIndexForTsFileLoad(); |
| 846 | + final LoadTsFileConsensusNode commit = commitNode(loadId); |
| 847 | + assertTrue(manager.loadAll(commit, Collections.emptyMap())); |
| 848 | + |
| 849 | + final TsFileResource imported = |
| 850 | + new TsFileResource(new File(new File(tempDir, "data"), staged.getName())); |
| 851 | + imported.deserialize(); |
| 852 | + imported.setStatus(TsFileResourceStatus.NORMAL); |
| 853 | + final ProgressIndex persistedProgress = imported.getMaxProgressIndexAfterClose(); |
| 854 | + final PipeTsFileInsertionEvent event = Mockito.mock(PipeTsFileInsertionEvent.class); |
| 855 | + Mockito.when(event.forceGetProgressIndex()).thenReturn(persistedProgress); |
| 856 | + assertEquals( |
| 857 | + "A V2 LOAD must remain eligible for consensus replication after resource recovery", |
| 858 | + useIoTConsensusV2, |
| 859 | + IoTConsensusV2Processor.isShouldReplicate(event)); |
| 860 | + if (useIoTConsensusV2) { |
| 861 | + assertTrue(persistedProgress.isAfter(interveningWrite)); |
| 862 | + } else { |
| 863 | + assertEquals(coordinatorProgress, persistedProgress); |
| 864 | + } |
| 865 | + } finally { |
| 866 | + manager.stop(); |
| 867 | + LoadConsensusCompat.setIoTConsensusV2ForTest(null); |
| 868 | + } |
| 869 | + } |
| 870 | + |
801 | 871 | @Test |
802 | 872 | public void testCommitKeepsTheStagedBytesWhileAReplicaMayStillNeedThem() throws Exception { |
803 | 873 | // The watermark lags behind the COMMIT command, so a replica that catches up from this node's |
|
0 commit comments