|
104 | 104 | import static org.junit.jupiter.api.Assertions.assertEquals; |
105 | 105 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
106 | 106 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| 107 | +import static org.mockito.ArgumentMatchers.any; |
107 | 108 | import static org.mockito.Mockito.doReturn; |
108 | 109 | import static org.mockito.Mockito.doThrow; |
109 | 110 | import static org.mockito.Mockito.spy; |
@@ -162,6 +163,47 @@ public void testBeginTransaction() throws LabelAlreadyUsedException, AnalysisExc |
162 | 163 | assertEquals(transactionSource.toString(), transactionState.getCoordinator().toString()); |
163 | 164 | } |
164 | 165 |
|
| 166 | + @Test |
| 167 | + public void testBeginTransactionEditLogAndReplay() throws Exception { |
| 168 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 169 | + String label = UUIDUtil.genUUID().toString(); |
| 170 | + long transactionId = masterTransMgr |
| 171 | + .beginTransaction(GlobalStateMgrTestUtil.testDbId1, Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 172 | + label, transactionSource, LoadJobSourceType.FRONTEND, Config.stream_load_default_timeout_second); |
| 173 | + |
| 174 | + TransactionState transactionState = fakeEditLog.getTransaction(transactionId); |
| 175 | + assertNotNull(transactionState); |
| 176 | + assertEquals(TransactionStatus.PREPARE, transactionState.getTransactionStatus()); |
| 177 | + |
| 178 | + FakeGlobalStateMgr.setGlobalStateMgr(slaveGlobalStateMgr); |
| 179 | + slaveTransMgr.replayUpsertTransactionState(transactionState); |
| 180 | + assertTrue(GlobalStateMgrTestUtil.compareState(masterGlobalStateMgr, slaveGlobalStateMgr)); |
| 181 | + } |
| 182 | + |
| 183 | + @Test |
| 184 | + public void testBeginTransactionEditLogException() throws Exception { |
| 185 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 186 | + EditLog spyEditLog = spy(masterGlobalStateMgr.getEditLog()); |
| 187 | + doThrow(new RuntimeException("EditLog write failed")) |
| 188 | + .when(spyEditLog).logInsertTransactionState(any(TransactionState.class), any()); |
| 189 | + EditLog originalEditLog = replaceDatabaseTransactionMgrEditLog(spyEditLog); |
| 190 | + |
| 191 | + String label = UUIDUtil.genUUID().toString(); |
| 192 | + try { |
| 193 | + RuntimeException exception = Assertions.assertThrows(RuntimeException.class, |
| 194 | + () -> masterTransMgr.beginTransaction(GlobalStateMgrTestUtil.testDbId1, |
| 195 | + Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 196 | + label, transactionSource, LoadJobSourceType.FRONTEND, |
| 197 | + Config.stream_load_default_timeout_second)); |
| 198 | + assertEditLogWriteFailed(exception); |
| 199 | + assertEquals(0, masterTransMgr.getTransactionNum()); |
| 200 | + assertEquals(TransactionStatus.UNKNOWN, |
| 201 | + masterTransMgr.getLabelStatus(GlobalStateMgrTestUtil.testDbId1, label).getStatus()); |
| 202 | + } finally { |
| 203 | + replaceDatabaseTransactionMgrEditLog(originalEditLog); |
| 204 | + } |
| 205 | + } |
| 206 | + |
165 | 207 | @Test |
166 | 208 | public void testBeginTransactionWithSameLabel() throws LabelAlreadyUsedException, AnalysisException, |
167 | 209 | RunningTxnExceedException, DuplicatedRequestException { |
@@ -197,6 +239,50 @@ public void testBeginTransactionWithSameLabel() throws LabelAlreadyUsedException |
197 | 239 | } |
198 | 240 | } |
199 | 241 |
|
| 242 | + @Test |
| 243 | + public void testAbortTransactionEditLogAndReplay() throws Exception { |
| 244 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 245 | + String label = UUIDUtil.genUUID().toString(); |
| 246 | + long transactionId = masterTransMgr |
| 247 | + .beginTransaction(GlobalStateMgrTestUtil.testDbId1, Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 248 | + label, transactionSource, LoadJobSourceType.FRONTEND, Config.stream_load_default_timeout_second); |
| 249 | + |
| 250 | + masterTransMgr.abortTransaction(GlobalStateMgrTestUtil.testDbId1, transactionId, "artificial failure"); |
| 251 | + |
| 252 | + TransactionState transactionState = fakeEditLog.getTransaction(transactionId); |
| 253 | + assertNotNull(transactionState); |
| 254 | + assertEquals(TransactionStatus.ABORTED, transactionState.getTransactionStatus()); |
| 255 | + assertEquals("artificial failure", transactionState.getReason()); |
| 256 | + |
| 257 | + FakeGlobalStateMgr.setGlobalStateMgr(slaveGlobalStateMgr); |
| 258 | + slaveTransMgr.replayUpsertTransactionState(transactionState); |
| 259 | + assertTrue(GlobalStateMgrTestUtil.compareState(masterGlobalStateMgr, slaveGlobalStateMgr)); |
| 260 | + } |
| 261 | + |
| 262 | + @Test |
| 263 | + public void testAbortTransactionEditLogException() throws Exception { |
| 264 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 265 | + String label = UUIDUtil.genUUID().toString(); |
| 266 | + long transactionId = masterTransMgr |
| 267 | + .beginTransaction(GlobalStateMgrTestUtil.testDbId1, Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 268 | + label, transactionSource, LoadJobSourceType.FRONTEND, Config.stream_load_default_timeout_second); |
| 269 | + |
| 270 | + EditLog spyEditLog = spy(masterGlobalStateMgr.getEditLog()); |
| 271 | + doThrow(new RuntimeException("EditLog write failed")) |
| 272 | + .when(spyEditLog).logInsertTransactionState(any(TransactionState.class), any()); |
| 273 | + EditLog originalEditLog = replaceDatabaseTransactionMgrEditLog(spyEditLog); |
| 274 | + try { |
| 275 | + RuntimeException exception = Assertions.assertThrows(RuntimeException.class, |
| 276 | + () -> masterTransMgr.abortTransaction(GlobalStateMgrTestUtil.testDbId1, |
| 277 | + transactionId, "artificial failure")); |
| 278 | + assertEditLogWriteFailed(exception); |
| 279 | + assertEquals(TransactionStatus.PREPARE, masterTransMgr |
| 280 | + .getTransactionState(GlobalStateMgrTestUtil.testDbId1, transactionId).getTransactionStatus()); |
| 281 | + } finally { |
| 282 | + replaceDatabaseTransactionMgrEditLog(originalEditLog); |
| 283 | + } |
| 284 | + } |
| 285 | + |
200 | 286 | // all replica committed success |
201 | 287 | @Test |
202 | 288 | public void testCommitTransaction1() throws StarRocksException { |
@@ -900,6 +986,93 @@ public void testPrepareTransaction() throws StarRocksException { |
900 | 986 | assertTrue(GlobalStateMgrTestUtil.compareState(masterGlobalStateMgr, slaveGlobalStateMgr)); |
901 | 987 | } |
902 | 988 |
|
| 989 | + @Test |
| 990 | + public void testPrepareTransactionEditLogException() throws Exception { |
| 991 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 992 | + long transactionId = masterTransMgr |
| 993 | + .beginTransaction(GlobalStateMgrTestUtil.testDbId1, Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 994 | + UUIDUtil.genUUID().toString(), transactionSource, |
| 995 | + LoadJobSourceType.FRONTEND, Config.stream_load_default_timeout_second); |
| 996 | + |
| 997 | + EditLog spyEditLog = spy(masterGlobalStateMgr.getEditLog()); |
| 998 | + doThrow(new RuntimeException("EditLog write failed")) |
| 999 | + .when(spyEditLog).logInsertTransactionState(any(TransactionState.class), any()); |
| 1000 | + EditLog originalEditLog = replaceDatabaseTransactionMgrEditLog(spyEditLog); |
| 1001 | + try { |
| 1002 | + RuntimeException exception = Assertions.assertThrows(RuntimeException.class, |
| 1003 | + () -> masterTransMgr.prepareTransaction(GlobalStateMgrTestUtil.testDbId1, transactionId, -1, |
| 1004 | + buildTabletCommitInfos(), Lists.newArrayList(), null)); |
| 1005 | + assertEditLogWriteFailed(exception); |
| 1006 | + TransactionState transactionState = |
| 1007 | + masterTransMgr.getTransactionState(GlobalStateMgrTestUtil.testDbId1, transactionId); |
| 1008 | + assertEquals(TransactionStatus.PREPARE, transactionState.getTransactionStatus()); |
| 1009 | + assertTrue(transactionState.getIdToTableCommitInfos().isEmpty()); |
| 1010 | + } finally { |
| 1011 | + replaceDatabaseTransactionMgrEditLog(originalEditLog); |
| 1012 | + } |
| 1013 | + } |
| 1014 | + |
| 1015 | + @Test |
| 1016 | + public void testCommitPreparedTransactionEditLogException() throws Exception { |
| 1017 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 1018 | + long transactionId = masterTransMgr |
| 1019 | + .beginTransaction(GlobalStateMgrTestUtil.testDbId1, Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 1020 | + UUIDUtil.genUUID().toString(), transactionSource, |
| 1021 | + LoadJobSourceType.FRONTEND, Config.stream_load_default_timeout_second); |
| 1022 | + masterTransMgr.prepareTransaction(GlobalStateMgrTestUtil.testDbId1, transactionId, -1, |
| 1023 | + buildTabletCommitInfos(), Lists.newArrayList(), null); |
| 1024 | + assertEquals(TransactionStatus.PREPARED, |
| 1025 | + masterTransMgr.getTransactionState(GlobalStateMgrTestUtil.testDbId1, transactionId).getTransactionStatus()); |
| 1026 | + |
| 1027 | + EditLog spyEditLog = spy(masterGlobalStateMgr.getEditLog()); |
| 1028 | + doThrow(new RuntimeException("EditLog write failed")) |
| 1029 | + .when(spyEditLog).logInsertTransactionState(any(TransactionState.class), any()); |
| 1030 | + EditLog originalEditLog = replaceDatabaseTransactionMgrEditLog(spyEditLog); |
| 1031 | + try { |
| 1032 | + RuntimeException exception = Assertions.assertThrows(RuntimeException.class, |
| 1033 | + () -> masterTransMgr.commitPreparedTransaction( |
| 1034 | + masterGlobalStateMgr.getLocalMetastore().getDb(GlobalStateMgrTestUtil.testDbId1), |
| 1035 | + transactionId, 1000L)); |
| 1036 | + assertEditLogWriteFailed(exception); |
| 1037 | + assertEquals(TransactionStatus.PREPARED, masterTransMgr |
| 1038 | + .getTransactionState(GlobalStateMgrTestUtil.testDbId1, transactionId).getTransactionStatus()); |
| 1039 | + } finally { |
| 1040 | + replaceDatabaseTransactionMgrEditLog(originalEditLog); |
| 1041 | + } |
| 1042 | + } |
| 1043 | + |
| 1044 | + @Test |
| 1045 | + public void testFinishTransactionEditLogException() throws Exception { |
| 1046 | + FakeGlobalStateMgr.setGlobalStateMgr(masterGlobalStateMgr); |
| 1047 | + long transactionId = masterTransMgr |
| 1048 | + .beginTransaction(GlobalStateMgrTestUtil.testDbId1, Lists.newArrayList(GlobalStateMgrTestUtil.testTableId1), |
| 1049 | + UUIDUtil.genUUID().toString(), transactionSource, |
| 1050 | + LoadJobSourceType.FRONTEND, Config.stream_load_default_timeout_second); |
| 1051 | + masterTransMgr.commitTransaction(GlobalStateMgrTestUtil.testDbId1, transactionId, buildTabletCommitInfos(), |
| 1052 | + Lists.newArrayList(), null); |
| 1053 | + |
| 1054 | + Partition testPartition = masterGlobalStateMgr.getLocalMetastore() |
| 1055 | + .getTable(GlobalStateMgrTestUtil.testDbId1, GlobalStateMgrTestUtil.testTableId1) |
| 1056 | + .getPartition(GlobalStateMgrTestUtil.testPartition1); |
| 1057 | + long visibleVersionBefore = testPartition.getDefaultPhysicalPartition().getVisibleVersion(); |
| 1058 | + |
| 1059 | + EditLog spyEditLog = spy(masterGlobalStateMgr.getEditLog()); |
| 1060 | + doThrow(new RuntimeException("EditLog write failed")) |
| 1061 | + .when(spyEditLog).logInsertTransactionState(any(TransactionState.class), any()); |
| 1062 | + EditLog originalEditLog = replaceDatabaseTransactionMgrEditLog(spyEditLog); |
| 1063 | + try { |
| 1064 | + RuntimeException exception = Assertions.assertThrows(RuntimeException.class, |
| 1065 | + () -> masterTransMgr.finishTransaction(GlobalStateMgrTestUtil.testDbId1, |
| 1066 | + transactionId, Sets.newHashSet())); |
| 1067 | + assertEditLogWriteFailed(exception); |
| 1068 | + assertEquals(TransactionStatus.COMMITTED, masterTransMgr |
| 1069 | + .getTransactionState(GlobalStateMgrTestUtil.testDbId1, transactionId).getTransactionStatus()); |
| 1070 | + assertEquals(visibleVersionBefore, testPartition.getDefaultPhysicalPartition().getVisibleVersion()); |
| 1071 | + } finally { |
| 1072 | + replaceDatabaseTransactionMgrEditLog(originalEditLog); |
| 1073 | + } |
| 1074 | + } |
| 1075 | + |
903 | 1076 | @Test |
904 | 1077 | public void testSaveLoadJsonFormatImage() throws Exception { |
905 | 1078 | long transactionId = masterTransMgr |
@@ -1083,4 +1256,23 @@ public void testGetLabelStatus() throws Exception { |
1083 | 1256 | Assertions.assertEquals(TransactionStatus.ABORTED, state3.getStatus()); |
1084 | 1257 | Assertions.assertEquals("artificial failure", state3.getReason()); |
1085 | 1258 | } |
| 1259 | + |
| 1260 | + private List<TabletCommitInfo> buildTabletCommitInfos() { |
| 1261 | + return Lists.newArrayList( |
| 1262 | + new TabletCommitInfo(GlobalStateMgrTestUtil.testTabletId1, GlobalStateMgrTestUtil.testBackendId1), |
| 1263 | + new TabletCommitInfo(GlobalStateMgrTestUtil.testTabletId1, GlobalStateMgrTestUtil.testBackendId2), |
| 1264 | + new TabletCommitInfo(GlobalStateMgrTestUtil.testTabletId1, GlobalStateMgrTestUtil.testBackendId3)); |
| 1265 | + } |
| 1266 | + |
| 1267 | + private EditLog replaceDatabaseTransactionMgrEditLog(EditLog editLog) throws Exception { |
| 1268 | + DatabaseTransactionMgr dbTransactionMgr = masterTransMgr.getDatabaseTransactionMgr(GlobalStateMgrTestUtil.testDbId1); |
| 1269 | + EditLog originalEditLog = Deencapsulation.getField(dbTransactionMgr, "editLog"); |
| 1270 | + Deencapsulation.setField(dbTransactionMgr, "editLog", editLog); |
| 1271 | + return originalEditLog; |
| 1272 | + } |
| 1273 | + |
| 1274 | + private void assertEditLogWriteFailed(RuntimeException exception) { |
| 1275 | + Assertions.assertTrue(exception.getMessage().contains("EditLog write failed") |
| 1276 | + || exception.getCause() != null && exception.getCause().getMessage().contains("EditLog write failed")); |
| 1277 | + } |
1086 | 1278 | } |
0 commit comments