HBASE-14212 Add IT test for procedure-v2-based namespace DDL (Stephen Yuan Jiang)
This commit is contained in:
parent
eeefc3d589
commit
daccb1c0c2
@ -58,13 +58,19 @@ import org.junit.experimental.categories.Category;
|
||||
* <li>DeleteTableAction</li>
|
||||
* <li>AddRowAction</li>
|
||||
* </ul>
|
||||
* Actions performing DDL operations:
|
||||
* Actions performing column family DDL operations:
|
||||
* <ul>
|
||||
* <li>AddColumnFamilyAction</li>
|
||||
* <li>AlterColumnFamilyVersionsAction</li>
|
||||
* <li>AlterColumnFamilyEncodingAction</li>
|
||||
* <li>DeleteColumnFamilyAction</li>
|
||||
* </ul>
|
||||
* Actions performing namespace DDL operations:
|
||||
* <ul>
|
||||
* <li>AddNamespaceAction</li>
|
||||
* <li>AlterNamespaceAction</li>
|
||||
* <li>DeleteNamespaceAction</li>
|
||||
* </ul>
|
||||
* <br/>
|
||||
*
|
||||
* The threads run for a period of time (default 20 minutes) then are stopped at the end of
|
||||
@ -115,6 +121,9 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
|
||||
protected int numThreads, numRegions;
|
||||
|
||||
ConcurrentHashMap<String, NamespaceDescriptor> namespaceMap =
|
||||
new ConcurrentHashMap<String, NamespaceDescriptor>();
|
||||
|
||||
ConcurrentHashMap<TableName, HTableDescriptor> enabledTables =
|
||||
new ConcurrentHashMap<TableName, HTableDescriptor>();
|
||||
|
||||
@ -140,6 +149,11 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
admin.disableTables("ittable-\\d+");
|
||||
admin.deleteTables("ittable-\\d+");
|
||||
}
|
||||
enabledTables.clear();
|
||||
disabledTables.clear();
|
||||
deletedTables.clear();
|
||||
namespaceMap.clear();
|
||||
|
||||
Connection connection = getConnection();
|
||||
connection.close();
|
||||
super.cleanUpCluster();
|
||||
@ -165,6 +179,23 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
return connection;
|
||||
}
|
||||
|
||||
protected void verifyNamespaces() throws IOException{
|
||||
Connection connection = getConnection();
|
||||
Admin admin = connection.getAdmin();
|
||||
// iterating concurrent map
|
||||
for (String nsName : namespaceMap.keySet()){
|
||||
try {
|
||||
Assert.assertTrue(
|
||||
"Namespace: " + nsName + " in namespaceMap does not exist",
|
||||
admin.getNamespaceDescriptor(nsName) != null);
|
||||
} catch (NamespaceNotFoundException nsnfe) {
|
||||
Assert.fail(
|
||||
"Namespace: " + nsName + " in namespaceMap does not exist: " + nsnfe.getMessage());
|
||||
}
|
||||
}
|
||||
admin.close();
|
||||
}
|
||||
|
||||
protected void verifyTables() throws IOException{
|
||||
Connection connection = getConnection();
|
||||
Admin admin = connection.getAdmin();
|
||||
@ -201,6 +232,148 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
abstract void perform() throws IOException;
|
||||
}
|
||||
|
||||
private abstract class NamespaceAction extends MasterAction {
|
||||
final String nsTestConfigKey = "hbase.namespace.testKey";
|
||||
|
||||
// NamespaceAction has implemented selectNamespace() shared by multiple namespace Actions
|
||||
protected NamespaceDescriptor selectNamespace(
|
||||
ConcurrentHashMap<String, NamespaceDescriptor> namespaceMap) {
|
||||
// randomly select namespace from namespaceMap
|
||||
if (namespaceMap.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// synchronization to prevent removal from multiple threads
|
||||
synchronized (namespaceMap) {
|
||||
ArrayList<String> namespaceList = new ArrayList<String>(namespaceMap.keySet());
|
||||
String randomKey = namespaceList.get(RandomUtils.nextInt(namespaceList.size()));
|
||||
NamespaceDescriptor randomNsd = namespaceMap.get(randomKey);
|
||||
// remove from namespaceMap
|
||||
namespaceMap.remove(randomKey);
|
||||
return randomNsd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateNamespaceAction extends NamespaceAction {
|
||||
@Override
|
||||
void perform() throws IOException {
|
||||
Admin admin = connection.getAdmin();
|
||||
try {
|
||||
NamespaceDescriptor nsd;
|
||||
while (true) {
|
||||
nsd = createNamespaceDesc();
|
||||
try {
|
||||
if (admin.getNamespaceDescriptor(nsd.getName()) != null) {
|
||||
// the namespace has already existed.
|
||||
continue;
|
||||
} else {
|
||||
// currently, the code never return null - always throws exception if
|
||||
// namespace is not found - this just a defensive programming to make
|
||||
// sure null situation is handled in case the method changes in the
|
||||
// future.
|
||||
break;
|
||||
}
|
||||
} catch (NamespaceNotFoundException nsnfe) {
|
||||
// This is expected for a random generated NamespaceDescriptor
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG.info("Creating namespace:" + nsd);
|
||||
admin.createNamespace(nsd);
|
||||
NamespaceDescriptor freshNamespaceDesc = admin.getNamespaceDescriptor(nsd.getName());
|
||||
Assert.assertTrue("Namespace: " + nsd + " was not created", freshNamespaceDesc != null);
|
||||
LOG.info("Created namespace:" + freshNamespaceDesc);
|
||||
namespaceMap.put(nsd.getName(), freshNamespaceDesc);
|
||||
} catch (Exception e){
|
||||
LOG.warn("Caught exception in action: " + this.getClass());
|
||||
throw e;
|
||||
} finally {
|
||||
admin.close();
|
||||
}
|
||||
verifyNamespaces();
|
||||
}
|
||||
|
||||
private NamespaceDescriptor createNamespaceDesc() {
|
||||
String namespaceName = "itnamespace" + String.format("%010d",
|
||||
RandomUtils.nextInt(Integer.MAX_VALUE));
|
||||
NamespaceDescriptor nsd = NamespaceDescriptor.create(namespaceName).build();
|
||||
|
||||
nsd.setConfiguration(
|
||||
nsTestConfigKey,
|
||||
String.format("%010d", RandomUtils.nextInt(Integer.MAX_VALUE)));
|
||||
return nsd;
|
||||
}
|
||||
}
|
||||
|
||||
private class ModifyNamespaceAction extends NamespaceAction {
|
||||
@Override
|
||||
void perform() throws IOException {
|
||||
NamespaceDescriptor selected = selectNamespace(namespaceMap);
|
||||
if (selected == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Admin admin = connection.getAdmin();
|
||||
try {
|
||||
String namespaceName = selected.getName();
|
||||
LOG.info("Modifying namespace :" + selected);
|
||||
NamespaceDescriptor modifiedNsd = NamespaceDescriptor.create(namespaceName).build();
|
||||
String nsValueNew;
|
||||
do {
|
||||
nsValueNew = String.format("%010d", RandomUtils.nextInt(Integer.MAX_VALUE));
|
||||
} while (selected.getConfigurationValue(nsTestConfigKey).equals(nsValueNew));
|
||||
modifiedNsd.setConfiguration(nsTestConfigKey, nsValueNew);
|
||||
admin.modifyNamespace(modifiedNsd);
|
||||
NamespaceDescriptor freshNamespaceDesc = admin.getNamespaceDescriptor(namespaceName);
|
||||
Assert.assertTrue(
|
||||
"Namespace: " + selected + " was not modified",
|
||||
freshNamespaceDesc.getConfigurationValue(nsTestConfigKey).equals(nsValueNew));
|
||||
LOG.info("Modified namespace :" + freshNamespaceDesc);
|
||||
namespaceMap.put(namespaceName, freshNamespaceDesc);
|
||||
} catch (Exception e){
|
||||
LOG.warn("Caught exception in action: " + this.getClass());
|
||||
throw e;
|
||||
} finally {
|
||||
admin.close();
|
||||
}
|
||||
verifyNamespaces();
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteNamespaceAction extends NamespaceAction {
|
||||
@Override
|
||||
void perform() throws IOException {
|
||||
NamespaceDescriptor selected = selectNamespace(namespaceMap);
|
||||
if (selected == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Admin admin = connection.getAdmin();
|
||||
try {
|
||||
String namespaceName = selected.getName();
|
||||
LOG.info("Deleting namespace :" + selected);
|
||||
admin.deleteNamespace(namespaceName);
|
||||
try {
|
||||
if (admin.getNamespaceDescriptor(namespaceName) != null) {
|
||||
// the namespace still exists.
|
||||
Assert.assertTrue("Namespace: " + selected + " was not deleted", false);
|
||||
} else {
|
||||
LOG.info("Deleted namespace :" + selected);
|
||||
}
|
||||
} catch (NamespaceNotFoundException nsnfe) {
|
||||
// This is expected result
|
||||
LOG.info("Deleted namespace :" + selected);
|
||||
}
|
||||
} catch (Exception e){
|
||||
LOG.warn("Caught exception in action: " + this.getClass());
|
||||
throw e;
|
||||
} finally {
|
||||
admin.close();
|
||||
}
|
||||
verifyNamespaces();
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class TableAction extends MasterAction{
|
||||
// TableAction has implemented selectTable() shared by multiple table Actions
|
||||
protected HTableDescriptor selectTable(ConcurrentHashMap<TableName, HTableDescriptor> tableMap)
|
||||
@ -610,6 +783,9 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
}
|
||||
|
||||
private enum ACTION {
|
||||
CREATE_NAMESPACE,
|
||||
MODIFY_NAMESPACE,
|
||||
DELETE_NAMESPACE,
|
||||
CREATE_TABLE,
|
||||
DISABLE_TABLE,
|
||||
ENABLE_TABLE,
|
||||
@ -637,6 +813,15 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
|
||||
try {
|
||||
switch (selectedAction) {
|
||||
case CREATE_NAMESPACE:
|
||||
new CreateNamespaceAction().perform();
|
||||
break;
|
||||
case MODIFY_NAMESPACE:
|
||||
new ModifyNamespaceAction().perform();
|
||||
break;
|
||||
case DELETE_NAMESPACE:
|
||||
new DeleteNamespaceAction().perform();
|
||||
break;
|
||||
case CREATE_TABLE:
|
||||
// stop creating new tables in the later stage of the test to avoid too many empty
|
||||
// tables
|
||||
@ -741,6 +926,8 @@ public class IntegrationTestDDLMasterFailover extends IntegrationTestBase {
|
||||
// verify
|
||||
LOG.info("Verify actions of all threads succeeded");
|
||||
checkException(workers);
|
||||
LOG.info("Verify namespaces");
|
||||
verifyNamespaces();
|
||||
LOG.info("Verify states of all tables");
|
||||
verifyTables();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user