You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by dl...@apache.org on 2021/09/07 17:00:26 UTC
[accumulo] branch main updated: Prevent compactions from starting
when deleting a table
This is an automated email from the ASF dual-hosted git repository.
dlmarion pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push:
new 7011224 Prevent compactions from starting when deleting a table
7011224 is described below
commit 70112240c5a36f5a146d8ecafa322cd7d94cd387
Author: Dave Marion <dl...@apache.org>
AuthorDate: Tue Sep 7 13:00:19 2021 -0400
Prevent compactions from starting when deleting a table
Closes #2182
---
.../java/org/apache/accumulo/core/Constants.java | 1 +
.../manager/tableOps/compact/CompactionDriver.java | 18 ++-
.../manager/tableOps/delete/PreDeleteTable.java | 17 +++
.../tableOps/compact/CompactionDriverTest.java | 124 +++++++++++++++++++++
4 files changed, 157 insertions(+), 3 deletions(-)
diff --git a/core/src/main/java/org/apache/accumulo/core/Constants.java b/core/src/main/java/org/apache/accumulo/core/Constants.java
index a46803f..b96c8a9 100644
--- a/core/src/main/java/org/apache/accumulo/core/Constants.java
+++ b/core/src/main/java/org/apache/accumulo/core/Constants.java
@@ -38,6 +38,7 @@ public class Constants {
public static final String ZTABLES = "/tables";
public static final byte[] ZTABLES_INITIAL_ID = {'0'};
public static final String ZTABLE_NAME = "/name";
+ public static final String ZTABLE_DELETE_MARKER = "/deleting";
public static final String ZTABLE_CONF = "/conf";
public static final String ZTABLE_STATE = "/state";
public static final String ZTABLE_FLUSH_ID = "/flush-id";
diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriver.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriver.java
index 00eaf94..24a5f62 100644
--- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriver.java
+++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriver.java
@@ -40,12 +40,18 @@ import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
import org.apache.accumulo.manager.Manager;
import org.apache.accumulo.manager.tableOps.ManagerRepo;
import org.apache.accumulo.manager.tableOps.Utils;
+import org.apache.accumulo.manager.tableOps.delete.PreDeleteTable;
import org.apache.accumulo.server.manager.LiveTServerSet.TServerConnection;
import org.apache.thrift.TException;
import org.slf4j.LoggerFactory;
class CompactionDriver extends ManagerRepo {
+ public static String createCompactionCancellationPath(String instanceId, TableId tableId) {
+ return Constants.ZROOT + "/" + instanceId + Constants.ZTABLES + "/" + tableId.canonical()
+ + Constants.ZTABLE_COMPACT_CANCEL_ID;
+ }
+
private static final long serialVersionUID = 1L;
private long compactId;
@@ -71,9 +77,7 @@ class CompactionDriver extends ManagerRepo {
return 0;
}
- String zCancelID = Constants.ZROOT + "/" + manager.getInstanceID() + Constants.ZTABLES + "/"
- + tableId + Constants.ZTABLE_COMPACT_CANCEL_ID;
-
+ String zCancelID = createCompactionCancellationPath(manager.getInstanceID(), tableId);
ZooReaderWriter zoo = manager.getContext().getZooReaderWriter();
if (Long.parseLong(new String(zoo.getData(zCancelID))) >= compactId) {
@@ -82,6 +86,14 @@ class CompactionDriver extends ManagerRepo {
TableOperation.COMPACT, TableOperationExceptionType.OTHER, "Compaction canceled");
}
+ String deleteMarkerPath =
+ PreDeleteTable.createDeleteMarkerPath(manager.getInstanceID(), tableId);
+ if (zoo.exists(deleteMarkerPath)) {
+ // table is being deleted
+ throw new AcceptableThriftTableOperationException(tableId.canonical(), null,
+ TableOperation.COMPACT, TableOperationExceptionType.OTHER, "Table is being deleted");
+ }
+
MapCounter<TServerInstance> serversToFlush = new MapCounter<>();
long t1 = System.currentTimeMillis();
diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/delete/PreDeleteTable.java b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/delete/PreDeleteTable.java
index a88bb5e..ac39708 100644
--- a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/delete/PreDeleteTable.java
+++ b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/delete/PreDeleteTable.java
@@ -18,17 +18,26 @@
*/
package org.apache.accumulo.manager.tableOps.delete;
+import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.clientImpl.thrift.TableOperation;
import org.apache.accumulo.core.data.NamespaceId;
import org.apache.accumulo.core.data.TableId;
import org.apache.accumulo.fate.Repo;
+import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
+import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.manager.Manager;
import org.apache.accumulo.manager.tableOps.ManagerRepo;
import org.apache.accumulo.manager.tableOps.Utils;
import org.apache.accumulo.manager.tableOps.compact.cancel.CancelCompactions;
+import org.apache.zookeeper.KeeperException;
public class PreDeleteTable extends ManagerRepo {
+ public static String createDeleteMarkerPath(String instanceId, TableId tableId) {
+ return Constants.ZROOT + "/" + instanceId + Constants.ZTABLES + "/" + tableId.canonical()
+ + Constants.ZTABLE_DELETE_MARKER;
+ }
+
private static final long serialVersionUID = 1L;
private TableId tableId;
@@ -45,9 +54,17 @@ public class PreDeleteTable extends ManagerRepo {
+ Utils.reserveTable(env, tableId, tid, false, true, TableOperation.DELETE);
}
+ private void preventFutureCompactions(Manager environment)
+ throws KeeperException, InterruptedException {
+ String deleteMarkerPath = createDeleteMarkerPath(environment.getInstanceID(), tableId);
+ ZooReaderWriter zoo = environment.getContext().getZooReaderWriter();
+ zoo.putPersistentData(deleteMarkerPath, new byte[] {}, NodeExistsPolicy.SKIP);
+ }
+
@Override
public Repo<Manager> call(long tid, Manager environment) throws Exception {
try {
+ preventFutureCompactions(environment);
CancelCompactions.mutateZooKeeper(tid, tableId, environment);
return new DeleteTable(namespaceId, tableId);
} finally {
diff --git a/server/manager/src/test/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriverTest.java b/server/manager/src/test/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriverTest.java
new file mode 100644
index 0000000..1ccfc9f
--- /dev/null
+++ b/server/manager/src/test/java/org/apache/accumulo/manager/tableOps/compact/CompactionDriverTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.accumulo.manager.tableOps.compact;
+
+import static org.junit.Assert.fail;
+
+import java.util.UUID;
+
+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.data.TableId;
+import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
+import org.apache.accumulo.manager.Manager;
+import org.apache.accumulo.manager.tableOps.delete.PreDeleteTable;
+import org.apache.accumulo.server.ServerContext;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+public class CompactionDriverTest {
+
+ @Test
+ public void testCancelId() throws Exception {
+
+ final String instance = UUID.randomUUID().toString();
+ final long compactId = 123;
+ final long cancelId = 124;
+ final NamespaceId namespaceId = NamespaceId.of("13");
+ final TableId tableId = TableId.of("42");
+ final byte[] startRow = new byte[0];
+ final byte[] endRow = new byte[0];
+
+ Manager manager = EasyMock.createNiceMock(Manager.class);
+ ServerContext ctx = EasyMock.createNiceMock(ServerContext.class);
+ ZooReaderWriter zrw = EasyMock.createNiceMock(ZooReaderWriter.class);
+ EasyMock.expect(manager.getInstanceID()).andReturn(instance).anyTimes();
+ EasyMock.expect(manager.getContext()).andReturn(ctx);
+ EasyMock.expect(ctx.getZooReaderWriter()).andReturn(zrw);
+
+ final String zCancelID = CompactionDriver.createCompactionCancellationPath(instance, tableId);
+ EasyMock.expect(zrw.getData(zCancelID)).andReturn(Long.toString(cancelId).getBytes());
+
+ EasyMock.replay(manager, ctx, zrw);
+
+ final CompactionDriver driver =
+ new CompactionDriver(compactId, namespaceId, tableId, startRow, endRow);
+ try {
+ driver.isReady(Long.parseLong(tableId.toString()), manager);
+ } catch (AcceptableThriftTableOperationException e) {
+ if (e.getTableId().equals(tableId.toString()) && e.getOp().equals(TableOperation.COMPACT)
+ && e.getType().equals(TableOperationExceptionType.OTHER)
+ && e.getDescription().equals("Compaction canceled")) {
+ // success
+ } else {
+ fail("Unexpected error thrown: " + e.getMessage());
+ }
+ } catch (Exception e) {
+ fail("Unhandled error thrown: " + e.getMessage());
+ }
+ EasyMock.verify(manager, ctx, zrw);
+ }
+
+ @Test
+ public void testTableBeingDeleted() throws Exception {
+
+ final String instance = UUID.randomUUID().toString();
+ final long compactId = 123;
+ final long cancelId = 122;
+ final NamespaceId namespaceId = NamespaceId.of("14");
+ final TableId tableId = TableId.of("43");
+ final byte[] startRow = new byte[0];
+ final byte[] endRow = new byte[0];
+
+ Manager manager = EasyMock.createNiceMock(Manager.class);
+ ServerContext ctx = EasyMock.createNiceMock(ServerContext.class);
+ ZooReaderWriter zrw = EasyMock.createNiceMock(ZooReaderWriter.class);
+ EasyMock.expect(manager.getInstanceID()).andReturn(instance).anyTimes();
+ EasyMock.expect(manager.getContext()).andReturn(ctx);
+ EasyMock.expect(ctx.getZooReaderWriter()).andReturn(zrw);
+
+ final String zCancelID = CompactionDriver.createCompactionCancellationPath(instance, tableId);
+ EasyMock.expect(zrw.getData(zCancelID)).andReturn(Long.toString(cancelId).getBytes());
+
+ String deleteMarkerPath = PreDeleteTable.createDeleteMarkerPath(instance, tableId);
+ EasyMock.expect(zrw.exists(deleteMarkerPath)).andReturn(true);
+
+ EasyMock.replay(manager, ctx, zrw);
+
+ final CompactionDriver driver =
+ new CompactionDriver(compactId, namespaceId, tableId, startRow, endRow);
+ try {
+ driver.isReady(Long.parseLong(tableId.toString()), manager);
+ } catch (AcceptableThriftTableOperationException e) {
+ if (e.getTableId().equals(tableId.toString()) && e.getOp().equals(TableOperation.COMPACT)
+ && e.getType().equals(TableOperationExceptionType.OTHER)
+ && e.getDescription().equals("Table is being deleted")) {
+ // success
+ } else {
+ fail("Unexpected error thrown: " + e.getMessage());
+ }
+ } catch (Exception e) {
+ fail("Unhandled error thrown: " + e.getMessage());
+ }
+ EasyMock.verify(manager, ctx, zrw);
+ }
+
+}