-
Notifications
You must be signed in to change notification settings - Fork 4.7k
HIVE-28916: Fix unbalannced calls in ObjectStore rollback transaction #5780
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
base: master
Are you sure you want to change the base?
Conversation
...e-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java
Outdated
Show resolved
Hide resolved
Some thoughts:
|
@dengzhhu653 There are some cases where rollback transaction does not need fail the api calls, for example |
|
Per my understanding, this shouldn't happen, imaging we rollback the transaction at place1, then the ObjectStore
the Metastore client call should get this exception, but our tests work fine. |
Yes it works now because current code does not put Additionally, the failed tests in this PR reveal following unbalanced calls that are hidden by current implementation:
|
@@ -1299,7 +1297,9 @@ private void create_database_core(RawStore ms, final Database db) | |||
success = ms.commitTransaction(); | |||
} finally { | |||
if (!success) { | |||
ms.rollbackTransaction(); | |||
if (openTransaction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are you checking for an openTransaction
flag here? I don't see the same check in other places.
if (isActiveTransaction() && transactionStatus != TXN_STATUS.ROLLBACK) {
currentTransaction.rollback();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In create_database_core
it may throw exception before calling openTransaction()
, so it may not need call rollbackTransaction()
in finally block.
ms.openTransaction(); | ||
firePreEvent(new PreCreateDataConnectorEvent(connector, this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, firePreEvent
may throw exception and not call openTransaction()
.
@@ -983,12 +983,11 @@ public void alter_catalog(AlterCatalogRequest rqst) throws TException { | |||
GetCatalogResponse oldCat = null; | |||
|
|||
try { | |||
ms.openTransaction(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to open txn before the PreAlterCatalogEvent
? are those transactional as well?
@@ -191,6 +184,10 @@ public void alterTable(RawStore msdb, Warehouse wh, String catName, String dbnam | |||
TableName.getQualified(catName, dbname, name) + " doesn't exist"); | |||
} | |||
|
|||
String expectedKey = environmentContext != null && environmentContext.getProperties() != null ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why move non-transactional logic under the txn boundary?
@@ -561,17 +561,10 @@ public void shutdown() { | |||
@Override | |||
public boolean openTransaction() { | |||
openTrasactionCalls++; | |||
if (openTrasactionCalls == 1) { | |||
if (currentTransaction == null || !currentTransaction.isActive()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we check for !currentTransaction.isActive()
? What if we called rollback on the interior txn?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To open transaction if it's not opened. It would reopen a new transaction if has already called rollback.
transactionStatus = TXN_STATUS.COMMITED; | ||
currentTransaction.commit(); | ||
} | ||
openTrasactionCalls--; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if commit throws RuntimeException, db txn would be closed, but openTrasactionCalls won't be 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If commit throw RuntimeException, it should call rollback in the finally block of previous layer where the openTransactionCalls would be decreased.
@@ -662,7 +655,7 @@ public void rollbackTransaction() { | |||
currentTransaction.rollback(); | |||
} | |||
} finally { | |||
openTrasactionCalls = 0; | |||
openTrasactionCalls--; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after rollback openTrasactionCalls should be 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our unit test could not pass if is 0 here, the key point seems that if we should support such usage:
openTransaction()
// new function1
{
openTransaction()
commitTransaction() # place1
}
// new function2
{
openTransaction()
commitTransaction()
}
commitTransaction() # place2
commitTransaction(); | ||
throw new NoSuchObjectException("partition values=" | ||
+ partVals.toString()); | ||
return new GetHelper<Partition>(catName, dbName, tblName, false, true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why refactor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may throw exception, so we need such logic:
try {
openTransaction();
success = commitTransaction();
} finally {
if (!success) rollbackTransaction();
}
What changes were proposed in this pull request?
Fix the bug in
ObjectStore#openTransaction
andObjectStore#rollbackTransaction
.Why are the changes needed?
Currently
rollbackTransaction()
always resetopenTransactionCalls
to 0, but it would cause unbalanced issue in nested transaction calls, for example:If the new function1 rollbackTransaction in place1, then it would get unbalanced exception in place2.
Does this PR introduce any user-facing change?
No.
How was this patch tested?
Add a unit test:
mvn test -Dtest.groups= -Dtest=org.apache.hadoop.hive.metastore.TestObjectStore#testNestedTransaction -pl :hive-standalone-metastore-server