This is an automated email from the ASF dual-hosted git repository.

siyao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 9434105b75 HDDS-8555. [Snapshot] When snapshot feature is disabled, 
block OM startup if there are still snapshots in the system (#4994)
9434105b75 is described below

commit 9434105b75ab30f4673e98d527e0817a79153cb6
Author: Siyao Meng <[email protected]>
AuthorDate: Wed Jun 28 11:16:48 2023 -0700

    HDDS-8555. [Snapshot] When snapshot feature is disabled, block OM startup 
if there are still snapshots in the system (#4994)
---
 .../ozone/om/TestOmSnapshotDisabledRestart.java    | 116 +++++++++++++++++++++
 .../apache/hadoop/ozone/om/OmSnapshotManager.java  |  49 +++++++--
 .../org/apache/hadoop/ozone/om/OzoneManager.java   |  12 +--
 .../hadoop/ozone/om/TestOmSnapshotManager.java     |  18 ++++
 4 files changed, 178 insertions(+), 17 deletions(-)

diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotDisabledRestart.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotDisabledRestart.java
new file mode 100644
index 0000000000..18761bd35f
--- /dev/null
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotDisabledRestart.java
@@ -0,0 +1,116 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.ozone.om;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.utils.IOUtils;
+import org.apache.hadoop.ozone.MiniOzoneCluster;
+import org.apache.hadoop.ozone.MiniOzoneHAClusterImpl;
+import org.apache.hadoop.ozone.client.ObjectStore;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.OzoneVolume;
+import org.apache.ozone.test.LambdaTestUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+
+import java.util.UUID;
+
+/**
+ * Integration test to verify that if snapshot feature is disabled, OM start up
+ * will fail when there are still snapshots remaining.
+ */
+@Disabled("HDDS-8945")
+public class TestOmSnapshotDisabledRestart {
+
+  private static MiniOzoneHAClusterImpl cluster = null;
+  private static OzoneClient client;
+  private static ObjectStore store;
+
+  @BeforeAll
+  @Timeout(60)
+  public static void init() throws Exception {
+    OzoneConfiguration conf = new OzoneConfiguration();
+    String clusterId = UUID.randomUUID().toString();
+    String scmId = UUID.randomUUID().toString();
+
+    // Enable filesystem snapshot feature at the beginning
+    conf.setBoolean(OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_KEY, true);
+
+    cluster = (MiniOzoneHAClusterImpl) MiniOzoneCluster.newOMHABuilder(conf)
+        .setClusterId(clusterId)
+        .setScmId(scmId)
+        .setOMServiceId("om-service-test2")
+        .setNumOfOzoneManagers(3)
+        .build();
+    cluster.waitForClusterToBeReady();
+    client = cluster.newClient();
+
+    OzoneManager leaderOzoneManager = cluster.getOMLeader();
+    OzoneConfiguration leaderConfig = leaderOzoneManager.getConfiguration();
+    cluster.setConf(leaderConfig);
+    store = client.getObjectStore();
+  }
+
+  @AfterAll
+  public static void tearDown() throws Exception {
+    IOUtils.closeQuietly(client);
+    if (cluster != null) {
+      cluster.shutdown();
+    }
+  }
+
+  @Test
+  public void testSnapshotFeatureFlag() throws Exception {
+    // Verify that OM start up will indeed fail when there are still snapshots
+    // while snapshot feature is disabled.
+
+    String volumeName = "vol-" + RandomStringUtils.randomNumeric(5);
+    String bucketName = "buck-" + RandomStringUtils.randomNumeric(5);
+    String snapshotName = "snap-" + RandomStringUtils.randomNumeric(5);
+
+    store.createVolume(volumeName);
+    OzoneVolume volume = store.getVolume(volumeName);
+    volume.createBucket(bucketName);
+    // Create a snapshot
+    store.createSnapshot(volumeName, bucketName, snapshotName);
+
+    cluster.getOzoneManagersList().forEach(om -> {
+      try {
+        cluster.shutdownOzoneManager(om);
+        // Disable snapshot feature
+        om.getConfiguration().setBoolean(
+            OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_KEY, false);
+        // Restart OM, expect OM start up failure
+        LambdaTestUtils.intercept(RuntimeException.class, "snapshots 
remaining",
+            () -> cluster.restartOzoneManager(om, true));
+        // Enable snapshot feature again
+        om.getConfiguration().setBoolean(
+            OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_KEY, true);
+        // Should pass this time
+        cluster.restartOzoneManager(om, true);
+      } catch (Exception e) {
+        Assertions.fail("Failed to restart OM", e);
+      }
+    });
+  }
+}
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
index 355eb7f832..24492361c8 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
@@ -60,8 +60,6 @@ import org.apache.hadoop.ozone.om.exceptions.OMException;
 import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
 import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
 import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
-import org.apache.hadoop.ozone.om.request.key.OMDirectoriesPurgeRequestWithFSO;
-import org.apache.hadoop.ozone.om.request.key.OMKeyPurgeRequest;
 import org.apache.hadoop.ozone.om.service.SnapshotDiffCleanupService;
 import org.apache.hadoop.ozone.om.snapshot.SnapshotDiffObject;
 import org.apache.hadoop.ozone.om.helpers.SnapshotDiffJob;
@@ -171,17 +169,25 @@ public final class OmSnapshotManager implements 
AutoCloseable {
   // Soft limit of the snapshot cache size.
   private final int softCacheSize;
 
-  /**
-   * TODO: [SNAPSHOT] HDDS-8529: Refactor the constructor in a way that when
-   *  ozoneManager.isFilesystemSnapshotEnabled() returns false,
-   *  no snapshot-related background job or initialization would run,
-   *  except for applying previously committed Ratis transactions in e.g.:
-   *  1. {@link OMKeyPurgeRequest#validateAndUpdateCache}
-   *  2. {@link OMDirectoriesPurgeRequestWithFSO#validateAndUpdateCache}
-   */
   public OmSnapshotManager(OzoneManager ozoneManager) {
+
+    boolean isFilesystemSnapshotEnabled =
+        ozoneManager.isFilesystemSnapshotEnabled();
     LOG.info("Ozone filesystem snapshot feature is {}.",
-        ozoneManager.isFilesystemSnapshotEnabled() ? "enabled" : "disabled");
+        isFilesystemSnapshotEnabled ? "enabled" : "disabled");
+
+    // Confirm that snapshot feature can be safely disabled.
+    // Throw unchecked exception if that is not the case.
+    if (!isFilesystemSnapshotEnabled &&
+        !canDisableFsSnapshot(ozoneManager.getMetadataManager())) {
+      throw new RuntimeException("Ozone Manager is refusing to start up" +
+          "because filesystem snapshot feature is disabled in config while" +
+          "there are still snapshots remaining in the system (including the " +
+          "ones that are marked as deleted but not yet cleaned up by the " +
+          "background worker thread). " +
+          "Please set config ozone.filesystem.snapshot.enabled to true and " +
+          "try to start this Ozone Manager again.");
+    }
 
     this.options = new ManagedDBOptions();
     this.options.setCreateIfMissing(true);
@@ -303,6 +309,27 @@ public final class OmSnapshotManager implements 
AutoCloseable {
     }
   }
 
+  /**
+   * Help reject OM startup if snapshot feature is disabled
+   * but there are snapshots remaining in this OM. Note: snapshots that are
+   * already deleted but not cleaned up yet still counts.
+   * @param ommm OMMetadataManager
+   * @return true if SnapshotInfoTable is empty, false otherwise.
+   */
+  @VisibleForTesting
+  public boolean canDisableFsSnapshot(OMMetadataManager ommm) {
+
+    boolean isSnapshotInfoTableEmpty;
+    try {
+      isSnapshotInfoTableEmpty = ommm.getSnapshotInfoTable().isEmpty();
+    } catch (IOException e) {
+      throw new IllegalStateException(
+          "Unable to check SnapshotInfoTable emptiness", e);
+    }
+
+    return isSnapshotInfoTableEmpty;
+  }
+
   private CacheLoader<String, OmSnapshot> createCacheLoader() {
     return new CacheLoader<String, OmSnapshot>() {
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index c6588a4e3e..066c6af3a7 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -442,7 +442,7 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
   private final OzoneLockProvider ozoneLockProvider;
   private final OMPerformanceMetrics perfMetrics;
 
-  private final boolean fsSnapshotEnabled;
+  private boolean fsSnapshotEnabled;
 
   /**
    * OM Startup mode.
@@ -554,10 +554,6 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
     // Ratis server comes with JvmPauseMonitor, no need to start another
     jvmPauseMonitor = !isRatisEnabled ? newJvmPauseMonitor(omId) : null;
 
-    fsSnapshotEnabled = configuration.getBoolean(
-        OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_KEY,
-        OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_DEFAULT);
-
     String defaultBucketLayoutString =
         configuration.getTrimmed(OZONE_DEFAULT_BUCKET_LAYOUT,
             OZONE_DEFAULT_BUCKET_LAYOUT_DEFAULT);
@@ -787,6 +783,7 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
       multiTenantManager = new OMMultiTenantManagerImpl(this, configuration);
       OzoneAclUtils.setOMMultiTenantManager(multiTenantManager);
     }
+
     volumeManager = new VolumeManagerImpl(metadataManager);
 
     bucketManager = new BucketManagerImpl(this, metadataManager);
@@ -824,7 +821,10 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
     omMetadataReader = new OmMetadataReader(keyManager, prefixManager,
         this, LOG, AUDIT, metrics);
 
-    // TODO: [SNAPSHOT] Revisit this in HDDS-8529.
+    // Reload snapshot feature config flag
+    fsSnapshotEnabled = configuration.getBoolean(
+        OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_KEY,
+        OMConfigKeys.OZONE_FILESYSTEM_SNAPSHOT_ENABLED_DEFAULT);
     omSnapshotManager = new OmSnapshotManager(this);
 
     // Snapshot metrics
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
index d5887126de..0d570535e1 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
@@ -115,6 +115,24 @@ public class TestOmSnapshotManager {
     FileUtils.deleteDirectory(testDir);
   }
 
+  @Test
+  public void testSnapshotFeatureFlagSafetyCheck() throws IOException {
+    // Verify that the snapshot feature config safety check method
+    // is returning the expected value.
+
+    Table<String, SnapshotInfo> snapshotInfoTable = mock(Table.class);
+    HddsWhiteboxTestUtils.setInternalState(
+        om.getMetadataManager(), SNAPSHOT_INFO_TABLE, snapshotInfoTable);
+
+    when(snapshotInfoTable.isEmpty()).thenReturn(false);
+    Assert.assertFalse(om.getOmSnapshotManager()
+        .canDisableFsSnapshot(om.getMetadataManager()));
+
+    when(snapshotInfoTable.isEmpty()).thenReturn(true);
+    Assert.assertTrue(om.getOmSnapshotManager()
+        .canDisableFsSnapshot(om.getMetadataManager()));
+  }
+
   @Test
   public void testCloseOnEviction() throws IOException {
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to