-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Hive: Unwrap RuntimeException for Hive TException with rename table #9432
Conversation
ALTER_TABLE.invoke(client, databaseName, tblName, table, new EnvironmentContext(env)); | ||
try { | ||
ALTER_TABLE.invoke(client, databaseName, tblName, table, new EnvironmentContext(env)); | ||
} catch (RuntimeException e) { |
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.
How widely is alterTable
used?
Wouldn't it be better (more general solution) to expose the wrapped MetaException
instead?
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's only being used at two places:
Are you proposing to throw non RTE MetaException
at alter table . something like
catch (RuntimeException e) {
if (e.getCause() instanceof InvalidOperationException
&& e.getCause().getMessage() != null
&& e.getCause()
.getMessage()
.contains(
String.format(
"new table %s.%s already exists", table.getDbName(), table.getTableName()))) {
throw new MetaException(
String.format("Table already exists: %s.%s", table.getDbName(), table.getTableName()));
}
throw e;
}
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.
I proposing something like this:
catch (RuntimeException e) {
if (e.getCause() instanceof MetaException) {
throw (MetaException) e.getCause()
} else {
throw e;
}
}
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.
Any thoughts on the test case testRenameTableDestinationTableAlreadyExists since it expects error message as
.isInstanceOf(AlreadyExistsException.class)
.hasMessageContaining("Table already exists");
Currently we have override this as
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("new table newdb.table_renamed already exists");
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.
alterTable
should return the MetaException
and where we call it, we should handle the InvalidOperationException
with the message of new table %s.%s already exists
and translate it to an AlreadyExistsException
.
We should only consider moving the exception if we find that all of the places where we call alterTable
we would like to throw the same AlreadyExistsException
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.
InvalidOperationException
still will be wrapped with RuntimeException
. So basically we will have to catch RuntimeException
and unwrap with AlreadyExistsException
.
Or Am I missing something here ?
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 not unwrap RTE with both MetaException
as well as InvalidOperationException
and translate to org.apache.hadoop.hive.metastore.api.AlreadyExistsException
. Since all the callers of alterTable
is already handling org.apache.hadoop.hive.metastore.api.AlreadyExistsException
.
I am thinking something like this:
catch (RuntimeException e) {
// MetaException would be wrapped into RuntimeException during reflection
if (e.getCause() instanceof MetaException) {
throw (MetaException) e.getCause();
}
// InvalidOperationException would be wrapped into RuntimeException during reflection, as
// java.lang.RuntimeException:InvalidOperationException(message:new table <> already exists)
if (e.getCause() instanceof InvalidOperationException
&& e.getCause().getMessage() != null
&& e.getCause()
.getMessage()
.contains(
String.format(
"new table %s.%s already exists", table.getDbName(), table.getTableName()))) {
throw new AlreadyExistsException(
String.format("Table already exists: %s.%s", table.getDbName(), table.getTableName()));
}
throw e;
}
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 the HiveTableOperations
we are accustomed to handle Hive MetaExceptions
, so I think handling InvalidOperationException
there would be "natural".
The alterTable
wraps the exceptions to a RuntimeException
because of the DynMethod
calls. I think this is a mistake. We should behave the same way as the metaClients.run(client -> client...)
like calls, we should throw the original MetaException
- my opinion here could be changes if this becomes a breaking change somewhere, but if it does not break code for someone, then we should change it.
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.
I made a mistake in the above command, I thought, that the root exception is MetaException
, but in reality it is TException
.
So fixing this issue, my comment correctly is below:
The alterTable
wraps the exceptions to a RuntimeException
because of the DynMethod
calls. I think this is a mistake. We should behave the same way as the metaClients.run(client -> client...)
like calls, we should throw the original TException
- my opinion here could be changes if this becomes a breaking change somewhere, but if it does not break code for someone, then we should change it.
} catch (AlreadyExistsException e) { | ||
throw new org.apache.iceberg.exceptions.AlreadyExistsException( | ||
"Table already exists: %s", to); | ||
} catch (RuntimeException e) { |
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.
You should catch here MetaException
instead of RuntimeException
from the altertable and throw AlreadyExistsException
?
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.
or if it is not coming as MetaException
, if it is coming as InvalidOperationException
cause. We should unwrap this at alterTable and throw only the cause.
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.
Unwrapping only MetaException
looks odd.
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.
I am not sure why we should explicitly catch MetaException here. Since it's already being handled with
catch (TException e) {
throw new RuntimeException("Failed to rename " + from + " to " + to, e);
}
InvalidOperationException
will always be wrapped with RuntimeException
in case of alterTable. Either we should unwrap it MetastoreUtil
or at every caller of it.
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.
Originally we were unwrapping to MetaException
but here were still catching RuntimeException
. Hence I gave that comment.
Now we are unwrapping to TException
and catching the TException
. So, now LGTM.
@ajantha-bhat: I think this looks good. Any more comments on your side? |
LGTM aswell. |
PR title may need update as it is TException now. |
@pvary , Should we merge this if there are no more comments ? |
if (e.getMessage() != null | ||
&& e.getMessage().contains(String.format("new table %s already exists", to))) { | ||
throw new org.apache.iceberg.exceptions.AlreadyExistsException( | ||
"Table already exists: %s", to); | ||
} else { | ||
throw new RuntimeException("Failed to rename " + from + " to " + to, e); | ||
} |
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.
could we please move this under a catch (InvalidOperationException)
?
But keep the old TException
handler part
Thanks @nk1506 for the PR! |
No description provided.