-
Notifications
You must be signed in to change notification settings - Fork 3.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
HBASE-24112 [RSGroup] Support renaming rsgroup #1435
Conversation
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
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.
Should we provide shell command for rename? Or maybe pass some attributes to existing rsgroup create command to indicate it is rename call? Or as of now Admin API is enough?
@@ -4146,4 +4148,21 @@ private void getProcedureResult(long procId, CompletableFuture<Void> future, int | |||
resp -> resp.hasRSGroupInfo() ? ProtobufUtil.toGroupInfo(resp.getRSGroupInfo()) : null))) | |||
.call(); | |||
} | |||
|
|||
@Override | |||
public CompletableFuture<Void> renameRSGroup(String oldName, String newName) { |
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.
Would you like to provide any validation for both strings? e.g. non-empty
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 think it is ok to leave it as it is, server side will throw ConstraintException if both are empty. Other methods like addRSGroup neither checks non-empty.
Map<String, RSGroupInfo> newGroupMap = Maps.newHashMap(rsGroupMap); | ||
newGroupMap.remove(oldRSG.getName()); | ||
RSGroupInfo newRSG = new RSGroupInfo(newName, oldRSG.getServers()); | ||
newGroupMap.put(newRSG.getName(), newRSG); |
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.
nit: simplify to newGroupMap.put(newName, newRSG);
?
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.
fixed
TableName tb = TableName.valueOf("testRename"); | ||
TEST_UTIL.createTable(tb, "tr"); | ||
ADMIN.setRSGroup(Sets.newHashSet(tb), oldgroup.getName()); | ||
Thread.sleep(500); |
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.
Instead of sleep(), we can use HBASE_TESTING_UTILITY.waitFor
:
e.g.
HBASE_TESTING_UTILITY.waitFor(1000,
() -> {
oldgroup = ADMIN.getRSGroup(oldgroup.getName());
return oldgroup.getServers().size() == 2 && ADMIN.getRSGroup(tb).getName().equals(oldgroup.getName());
});
This way we will ensure, we wait for specific period of time until our predicate returns 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.
fixed
match++; | ||
} | ||
} | ||
assertEquals(servers.size(), match); |
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.
Is this redundant assert? assertEquals(servers.size(), newgroup.getServers().size());
is already taking care 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.
The for loop above is to check the servers are exactly the same before renaming. And the match is the number of 「exactly the same」. Not redundant regarding to its purpose.
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.
Yes I agree this is useful assertion.
Actually I was wondering if we can add more context to this test as well as assertions. For example, we create and assign another table to another rsgroup. So the "if" clause checking rsgroup name in RSGroupInfoManagerImpl.java
will get tested. Otherwise this test may still pass even when we remove the "if". By the "if" I mean:
if (rsgroup.get().equals(oldName)) {
updateTables.add(table.getValue().getTableName());
}
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.
Get your idea. Fixed in new commit.
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.
Yes the test now is very comprehensive. Thanks,
9dd5c86
to
6105914
Compare
Plan to do the shell command in a separate JIRA, to make backport easier. |
@@ -38,6 +38,9 @@ | |||
// Keep servers in a sorted set so has an expected ordering when displayed. | |||
private final SortedSet<Address> servers; | |||
// Keep tables sorted too. | |||
|
|||
// TODO: Don't understand why all these should be deprecated. we have table -> rsgroup mapping. |
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.
Because we do not store the table informations in RSGroupInfo anymore, if you use the new API to get RSGroupInfo, the tables will always be empty.
hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java
Show resolved
Hide resolved
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
I do not think a green UT result can reduce the concern on the 'unexepcted behavior'. It does not happen now does mean it will not happen in the future. The root problem here, is that, after the renaming, the TableDescriptor at RS side still reference the old name, if we write some code at RS side that retrieve this value and do something, we may be in trouble. |
Get it. It means only reopening the regions can get the most updated TD on RS side in this case. What's your suggestion to this concern? |
I do not have an idea yet. Maybe we could find a way to update the table descriptor for a region at RS side without reopening it? |
Just rolled back to the previous version, the one using setRSGroups. It is the appropriate & right approach by now. |
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
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 do not have enough context to be +1. Posting some random comments here
RSGroupInfo newRSG = new RSGroupInfo(newName, oldRSG.getServers()); | ||
newGroupMap.put(newName, newRSG); | ||
flushConfig(newGroupMap); | ||
Set<TableName> updateTables = new HashSet<>(); |
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.
Set<TableName> updateTables = new HashSet<>();
TableDescriptors tableDescriptors = masterServices.getTableDescriptors();
for (Map.Entry<String, TableDescriptor> table : tableDescriptors.getAll().entrySet()) {
Optional<String> rsgroup = table.getValue().getRegionServerGroup();
if (!rsgroup.isPresent()) {
continue;
}
if (rsgroup.get().equals(oldName)) {
updateTables.add(table.getValue().getTableName());
}
}
can be replaced with, if stream is preferred, following code (not tested):
Set<TableName> updateTables = masterServices.getTableDescriptors().getAll().values()
.stream()
.filter(t -> oldName.equals(t.getRegionServerGroup().orElse(null)))
.map(TableDescriptor::getTableName)
.collect(Collectors.toSet());
match++; | ||
} | ||
} | ||
assertEquals(servers.size(), match); |
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.
Yes I agree this is useful assertion.
Actually I was wondering if we can add more context to this test as well as assertions. For example, we create and assign another table to another rsgroup. So the "if" clause checking rsgroup name in RSGroupInfoManagerImpl.java
will get tested. Otherwise this test may still pass even when we remove the "if". By the "if" I mean:
if (rsgroup.get().equals(oldName)) {
updateTables.add(table.getValue().getTableName());
}
…nsure it works as expectation
🎊 +1 overall
This message was automatically generated. |
🎊 +1 overall
This message was automatically generated. |
💔 -1 overall
This message was automatically generated. |
Shall we proceed? And regarding to this idea:
I think it worth an independent JIRA, quite big might be. |
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.
Still a little worry about adding a new method which is not perfect, but anyway, it could make it easier for user to rename a rs group. Maybe we could find a way to improve the implementation in the future.
+1.
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.
Skimmed. LGTM.
Signed-off-by: Duo Zhang <[email protected]>
Signed-off-by: Duo Zhang <[email protected]>
Signed-off-by: Duo Zhang <[email protected]>
Signed-off-by: Duo Zhang <[email protected]>
Signed-off-by: Duo Zhang <[email protected]>
JIRA link: https://issues.apache.org/jira/browse/HBASE-24112