-
Notifications
You must be signed in to change notification settings - Fork 2.5k
[HUDI-3798] Fixing ending of a transaction by different owner and removing some extraneous methods in trxn manager #5255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,20 +69,28 @@ private HoodieWriteConfig getWriteConfig() { | |
|
|
||
| @Test | ||
| public void testSingleWriterTransaction() { | ||
| transactionManager.beginTransaction(); | ||
| transactionManager.endTransaction(); | ||
| Option<HoodieInstant> lastCompletedInstant = getInstant("0000001"); | ||
| Option<HoodieInstant> newTxnOwnerInstant = getInstant("0000002"); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant, lastCompletedInstant); | ||
| transactionManager.endTransaction(newTxnOwnerInstant); | ||
| } | ||
|
|
||
| @Test | ||
| public void testSingleWriterNestedTransaction() { | ||
| transactionManager.beginTransaction(); | ||
| Option<HoodieInstant> lastCompletedInstant = getInstant("0000001"); | ||
| Option<HoodieInstant> newTxnOwnerInstant = getInstant("0000002"); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant, lastCompletedInstant); | ||
|
|
||
| Option<HoodieInstant> lastCompletedInstant1 = getInstant("0000003"); | ||
| Option<HoodieInstant> newTxnOwnerInstant1 = getInstant("0000004"); | ||
|
|
||
| assertThrows(HoodieLockException.class, () -> { | ||
| transactionManager.beginTransaction(); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant1, lastCompletedInstant1); | ||
| }); | ||
|
|
||
| transactionManager.endTransaction(); | ||
| transactionManager.endTransaction(newTxnOwnerInstant); | ||
| assertDoesNotThrow(() -> { | ||
| transactionManager.endTransaction(); | ||
| transactionManager.endTransaction(newTxnOwnerInstant1); | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -94,11 +102,16 @@ public void testMultiWriterTransactions() { | |
| final AtomicBoolean writer1Completed = new AtomicBoolean(false); | ||
| final AtomicBoolean writer2Completed = new AtomicBoolean(false); | ||
|
|
||
| Option<HoodieInstant> lastCompletedInstant1 = getInstant("0000001"); | ||
| Option<HoodieInstant> newTxnOwnerInstant1 = getInstant("0000002"); | ||
| Option<HoodieInstant> lastCompletedInstant2 = getInstant("0000003"); | ||
| Option<HoodieInstant> newTxnOwnerInstant2 = getInstant("0000004"); | ||
|
|
||
| // Let writer1 get the lock first, then wait for others | ||
| // to join the sync up point. | ||
| Thread writer1 = new Thread(() -> { | ||
| assertDoesNotThrow(() -> { | ||
| transactionManager.beginTransaction(); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant1, lastCompletedInstant1); | ||
| }); | ||
| latch.countDown(); | ||
| try { | ||
|
|
@@ -111,7 +124,7 @@ public void testMultiWriterTransactions() { | |
| // | ||
| } | ||
| assertDoesNotThrow(() -> { | ||
| transactionManager.endTransaction(); | ||
| transactionManager.endTransaction(newTxnOwnerInstant1); | ||
| }); | ||
| writer1Completed.set(true); | ||
| }); | ||
|
|
@@ -127,10 +140,10 @@ public void testMultiWriterTransactions() { | |
| // | ||
| } | ||
| assertDoesNotThrow(() -> { | ||
| transactionManager.beginTransaction(); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant2, lastCompletedInstant2); | ||
| }); | ||
| assertDoesNotThrow(() -> { | ||
| transactionManager.endTransaction(); | ||
| transactionManager.endTransaction(newTxnOwnerInstant2); | ||
| }); | ||
| writer2Completed.set(true); | ||
| }); | ||
|
|
@@ -152,6 +165,32 @@ public void testMultiWriterTransactions() { | |
| Assertions.assertTrue(writer2Completed.get()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testEndTransactionByDiffOwner() throws InterruptedException { | ||
| // 1. Begin and end by the same transaction owner | ||
| Option<HoodieInstant> lastCompletedInstant = getInstant("0000001"); | ||
| Option<HoodieInstant> newTxnOwnerInstant = getInstant("0000002"); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant, lastCompletedInstant); | ||
|
|
||
| CountDownLatch countDownLatch = new CountDownLatch(1); | ||
| // Another writer thread | ||
| Thread writer2 = new Thread(() -> { | ||
| Option<HoodieInstant> newTxnOwnerInstant1 = getInstant("0000003"); | ||
| transactionManager.endTransaction(newTxnOwnerInstant1); | ||
| countDownLatch.countDown(); | ||
| }); | ||
|
|
||
| writer2.start(); | ||
| countDownLatch.await(30, TimeUnit.SECONDS); | ||
| // should not have reset the state within transaction manager since the owner is different. | ||
| Assertions.assertTrue(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. iiuc, even in this scenario, without this patch,
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe make reset method just visible for testing?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we usually don't use VisibleForTesting annotation. lets sync up on this. we might have tests in InProcessLockProvider to assert for the condition you are talking about
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok found it: |
||
| Assertions.assertTrue(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
|
|
||
| transactionManager.endTransaction(newTxnOwnerInstant); | ||
| Assertions.assertFalse(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
| Assertions.assertFalse(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testTransactionsWithInstantTime() { | ||
| // 1. Begin and end by the same transaction owner | ||
|
|
@@ -164,14 +203,15 @@ public void testTransactionsWithInstantTime() { | |
| Assertions.assertFalse(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
| Assertions.assertFalse(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
|
|
||
| // 2. Begin transaction with a new txn owner, but end transaction with no/wrong owner | ||
| // 2. Begin transaction with a new txn owner, but end transaction with wrong owner | ||
| lastCompletedInstant = getInstant("0000002"); | ||
| newTxnOwnerInstant = getInstant("0000003"); | ||
| transactionManager.beginTransaction(newTxnOwnerInstant, lastCompletedInstant); | ||
| transactionManager.endTransaction(); | ||
| transactionManager.endTransaction(getInstant("0000004")); | ||
| // Owner reset would not happen as the end txn was invoked with an incorrect current txn owner | ||
| Assertions.assertTrue(transactionManager.getCurrentTransactionOwner() == newTxnOwnerInstant); | ||
| Assertions.assertTrue(transactionManager.getLastCompletedTransactionOwner() == lastCompletedInstant); | ||
| transactionManager.endTransaction(newTxnOwnerInstant); | ||
|
|
||
| // 3. But, we should be able to begin a new transaction for a new owner | ||
| lastCompletedInstant = getInstant("0000003"); | ||
|
|
@@ -183,15 +223,7 @@ public void testTransactionsWithInstantTime() { | |
| Assertions.assertFalse(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
| Assertions.assertFalse(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
|
|
||
| // 4. Transactions with no owners should also go through | ||
| transactionManager.beginTransaction(); | ||
| Assertions.assertFalse(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
| Assertions.assertFalse(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
| transactionManager.endTransaction(); | ||
| Assertions.assertFalse(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
| Assertions.assertFalse(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
|
|
||
| // 5. Transactions with new instants but with same timestamps should properly reset owners | ||
| // 4. Transactions with new instants but with same timestamps should properly reset owners | ||
| transactionManager.beginTransaction(getInstant("0000005"), Option.empty()); | ||
| Assertions.assertTrue(transactionManager.getCurrentTransactionOwner().isPresent()); | ||
| Assertions.assertFalse(transactionManager.getLastCompletedTransactionOwner().isPresent()); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.