diff --git a/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java b/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java index d11efd483cb..1b9cef4154e 100644 --- a/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java +++ b/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java @@ -49,6 +49,8 @@ import org.apache.accumulo.core.client.admin.TableOperations; import org.apache.accumulo.core.clientImpl.thrift.SecurityErrorCode; import org.apache.accumulo.core.clientImpl.thrift.TVersionedProperties; +import org.apache.accumulo.core.clientImpl.thrift.TableOperationExceptionType; +import org.apache.accumulo.core.clientImpl.thrift.ThriftTableOperationException; import org.apache.accumulo.core.data.NamespaceId; import org.apache.accumulo.core.data.constraints.Constraint; import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; @@ -150,10 +152,6 @@ public void delete(String namespace) throws AccumuloException, AccumuloSecurityE SecurityErrorCode.UNSUPPORTED_OPERATION); } - if (!context.getTableMapping(namespaceId).getIdToNameMap().isEmpty()) { - throw new NamespaceNotEmptyException(namespaceId.canonical(), namespace, null); - } - List args = Arrays.asList(ByteBuffer.wrap(namespace.getBytes(UTF_8))); Map opts = new HashMap<>(); @@ -162,6 +160,13 @@ public void delete(String namespace) throws AccumuloException, AccumuloSecurityE } catch (NamespaceExistsException e) { // should not happen throw new AssertionError(e); + } catch (AccumuloException e) { + if (e.getCause() instanceof ThriftTableOperationException ttoe + && ttoe.getType() == TableOperationExceptionType.NAMESPACE_NOTEMPTY) { + throw new NamespaceNotEmptyException(ttoe.getTableId(), namespace, ttoe.getDescription(), + ttoe); + } + throw e; } } diff --git a/core/src/main/thrift-gen-java/org/apache/accumulo/core/clientImpl/thrift/TableOperationExceptionType.java b/core/src/main/thrift-gen-java/org/apache/accumulo/core/clientImpl/thrift/TableOperationExceptionType.java index 639fd8892f5..871b01a23f4 100644 --- a/core/src/main/thrift-gen-java/org/apache/accumulo/core/clientImpl/thrift/TableOperationExceptionType.java +++ b/core/src/main/thrift-gen-java/org/apache/accumulo/core/clientImpl/thrift/TableOperationExceptionType.java @@ -37,7 +37,8 @@ public enum TableOperationExceptionType implements org.apache.thrift.TEnum { NAMESPACE_NOTFOUND(8), INVALID_NAME(9), OBSOLETE_BULK_BAD_LOAD_MAPPING(10), - BULK_CONCURRENT_MERGE(11); + BULK_CONCURRENT_MERGE(11), + NAMESPACE_NOTEMPTY(12); private final int value; @@ -84,6 +85,8 @@ public static TableOperationExceptionType findByValue(int value) { return OBSOLETE_BULK_BAD_LOAD_MAPPING; case 11: return BULK_CONCURRENT_MERGE; + case 12: + return NAMESPACE_NOTEMPTY; default: return null; } diff --git a/core/src/main/thrift/client.thrift b/core/src/main/thrift/client.thrift index 2fd886a9c53..2cc267ae990 100644 --- a/core/src/main/thrift/client.thrift +++ b/core/src/main/thrift/client.thrift @@ -56,6 +56,7 @@ enum TableOperationExceptionType { INVALID_NAME OBSOLETE_BULK_BAD_LOAD_MAPPING BULK_CONCURRENT_MERGE + NAMESPACE_NOTEMPTY } enum ConfigurationType { diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/namespace/delete/DeleteNamespace.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/namespace/delete/DeleteNamespace.java index 1f218059681..2c756901f95 100644 --- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/namespace/delete/DeleteNamespace.java +++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/namespace/delete/DeleteNamespace.java @@ -20,7 +20,9 @@ import static org.apache.accumulo.core.util.LazySingletons.GSON; +import org.apache.accumulo.core.clientImpl.AcceptableThriftTableOperationException; import org.apache.accumulo.core.clientImpl.thrift.TableOperation; +import org.apache.accumulo.core.clientImpl.thrift.TableOperationExceptionType; import org.apache.accumulo.core.data.NamespaceId; import org.apache.accumulo.core.fate.FateId; import org.apache.accumulo.core.fate.Repo; @@ -48,7 +50,12 @@ public long isReady(FateId fateId, FateEnv environment) throws Exception { } @Override - public Repo call(FateId fateId, FateEnv environment) { + public Repo call(FateId fateId, FateEnv environment) throws Exception { + if (!environment.getContext().getTableMapping(namespaceId).getIdToNameMap().isEmpty()) { + throw new AcceptableThriftTableOperationException(namespaceId.canonical(), null, + TableOperation.DELETE, TableOperationExceptionType.NAMESPACE_NOTEMPTY, + "Namespace is not empty"); + } environment.getEventPublisher().event("deleting namespace %s ", namespaceId); return new NamespaceCleanUp(namespaceId); } diff --git a/test/src/main/java/org/apache/accumulo/test/NamespacesIT_SimpleSuite.java b/test/src/main/java/org/apache/accumulo/test/NamespacesIT_SimpleSuite.java index f91124245ee..5e94f87c1e4 100644 --- a/test/src/main/java/org/apache/accumulo/test/NamespacesIT_SimpleSuite.java +++ b/test/src/main/java/org/apache/accumulo/test/NamespacesIT_SimpleSuite.java @@ -20,6 +20,9 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.apache.accumulo.test.harness.AccumuloITBase.MINI_CLUSTER_ONLY; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -39,6 +42,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.UUID; import org.apache.accumulo.cluster.ClusterUser; import org.apache.accumulo.core.client.Accumulo; @@ -60,6 +64,7 @@ import org.apache.accumulo.core.client.admin.TableOperations; import org.apache.accumulo.core.client.security.SecurityErrorCode; import org.apache.accumulo.core.client.security.tokens.PasswordToken; +import org.apache.accumulo.core.clientImpl.AcceptableThriftTableOperationException; import org.apache.accumulo.core.clientImpl.Namespace; import org.apache.accumulo.core.clientImpl.thrift.TableOperation; import org.apache.accumulo.core.clientImpl.thrift.TableOperationExceptionType; @@ -70,6 +75,8 @@ import org.apache.accumulo.core.data.Range; import org.apache.accumulo.core.data.RowRange; import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.fate.FateId; +import org.apache.accumulo.core.fate.FateInstanceType; import org.apache.accumulo.core.iterators.Filter; import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; import org.apache.accumulo.core.iterators.SortedKeyValueIterator; @@ -79,6 +86,8 @@ import org.apache.accumulo.core.security.SystemPermission; import org.apache.accumulo.core.security.TablePermission; import org.apache.accumulo.core.util.tables.TableNameUtil; +import org.apache.accumulo.manager.tableOps.FateEnv; +import org.apache.accumulo.manager.tableOps.namespace.delete.DeleteNamespace; import org.apache.accumulo.test.constraints.NumericValueConstraint; import org.apache.accumulo.test.harness.SharedMiniClusterBase; import org.apache.commons.lang3.StringUtils; @@ -268,6 +277,23 @@ public void deleteNonEmptyNamespace() throws Exception { assertThrows(NamespaceNotEmptyException.class, () -> c.namespaceOperations().delete(namespace)); } + @Test + public void deleteNamespaceFateOpRejectsNonEmptyNamespace() throws Exception { + String tableName = namespace + ".1"; + c.namespaceOperations().create(namespace); + c.tableOperations().create(tableName); + + var context = getCluster().getServerContext(); + FateEnv env = createMock(FateEnv.class); + expect(env.getContext()).andReturn(context).anyTimes(); + replay(env); + + var e = assertThrows(AcceptableThriftTableOperationException.class, + () -> new DeleteNamespace(context.getNamespaceId(namespace)) + .call(FateId.from(FateInstanceType.USER, UUID.randomUUID()), env)); + assertEquals(TableOperationExceptionType.NAMESPACE_NOTEMPTY, e.getType()); + } + @Test public void setProperties() throws Exception { c.namespaceOperations().create(namespace);