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);
+  }
+
+}