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

rakeshr pushed a commit to branch HDDS-2939
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/HDDS-2939 by this push:
     new 3c82503  HDDS-5094. [FSO] Fail OM startup when turn on prefix layout 
with old buckets (#2151)
3c82503 is described below

commit 3c82503da3e549bb85af36063ff43d7a3889aede
Author: Rakesh Radhakrishnan <[email protected]>
AuthorDate: Fri Apr 30 12:55:01 2021 +0530

    HDDS-5094. [FSO] Fail OM startup when turn on prefix layout with old 
buckets (#2151)
---
 .../hadoop/fs/ozone/TestOzoneFileSystem.java       |   4 -
 .../fs/ozone/TestOzoneFileSystemWithFSO.java       |   5 -
 .../hadoop/ozone/om/TestOMStartupWithLayout.java   | 197 +++++++++++++++++++++
 .../org/apache/hadoop/ozone/om/OzoneManager.java   | 109 ++++++++++--
 4 files changed, 288 insertions(+), 27 deletions(-)

diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
index acc335d..d322a7a 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
@@ -211,10 +211,6 @@ public class TestOzoneFileSystem {
     return fs;
   }
 
-  public static boolean isEnabledFileSystemPaths() {
-    return enabledFileSystemPaths;
-  }
-
   public static void setIsBucketFSOptimized(boolean isBucketFSO) {
     isBucketFSOptimized = isBucketFSO;
   }
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java
index 36f0cb6..c2f67be 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java
@@ -328,11 +328,6 @@ public class TestOzoneFileSystemWithFSO extends 
TestOzoneFileSystem {
    */
   @Test
   public void testRenameDestinationParentDoesntExist() throws Exception {
-    // Skip as this will run only in new layout
-    if (!isEnabledFileSystemPaths()) {
-      return;
-    }
-
     final String root = "/root_dir";
     final String dir1 = root + "/dir1";
     final String dir2 = dir1 + "/dir2";
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMStartupWithLayout.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMStartupWithLayout.java
new file mode 100644
index 0000000..4a26615
--- /dev/null
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMStartupWithLayout.java
@@ -0,0 +1,197 @@
+/**
+ * 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.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.MiniOzoneCluster;
+import org.apache.hadoop.ozone.TestDataUtil;
+import org.apache.hadoop.ozone.client.OzoneBucket;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.OzoneVolume;
+import org.apache.hadoop.ozone.om.helpers.OzoneFSUtils;
+import org.apache.hadoop.ozone.om.request.TestOMRequestUtils;
+import org.apache.hadoop.test.GenericTestUtils;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.Timeout;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ENABLE_FILESYSTEM_PATHS;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_METADATA_LAYOUT;
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_METADATA_LAYOUT_DEFAULT;
+import static 
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_METADATA_LAYOUT_PREFIX;
+
+/**
+ * Verifies OM startup with different layout.
+ */
+public class TestOMStartupWithLayout {
+
+  /**
+   * Set a timeout for each test.
+   */
+  @Rule
+  public Timeout timeout = Timeout.seconds(300);
+
+  private static MiniOzoneCluster cluster;
+
+  @BeforeClass
+  public static void startClusterWithSimpleLayout() throws Exception {
+    OzoneConfiguration conf = new OzoneConfiguration();
+    String clusterId = UUID.randomUUID().toString();
+    String scmId = UUID.randomUUID().toString();
+    String omId = UUID.randomUUID().toString();
+    TestOMRequestUtils.configureFSOptimizedPaths(conf, true,
+        OZONE_OM_METADATA_LAYOUT_DEFAULT);
+    cluster = MiniOzoneCluster.newBuilder(conf).setClusterId(clusterId)
+        .setScmId(scmId).setOmId(omId).build();
+    cluster.waitForClusterToBeReady();
+  }
+
+  @AfterClass
+  public static void teardown() {
+    if (cluster != null) {
+      cluster.shutdown();
+    }
+  }
+
+  @Test
+  public void testWithDifferentClusterLayout() throws Exception {
+    OzoneConfiguration conf = cluster.getOzoneManager().getConfiguration();
+
+    // create a volume and a bucket with default(SIMPLE) metadata format.
+    OzoneBucket bucket = TestDataUtil.createVolumeAndBucket(cluster);
+    verifyBucketLayout(bucket, OZONE_OM_METADATA_LAYOUT_DEFAULT, false);
+
+    cluster.getOzoneManager().stop();
+
+    // case-1) Configured cluster layout as PREFIX. Bucket exists with SIMPLE
+    // layout format. OM startup should fail.
+    conf.set(OZONE_OM_METADATA_LAYOUT, OZONE_OM_METADATA_LAYOUT_PREFIX);
+    verifyOMStartupFailure(OZONE_OM_METADATA_LAYOUT_PREFIX);
+    verifyOMRestartFailure(OZONE_OM_METADATA_LAYOUT_PREFIX);
+
+    // case-2) Configured cluster layout as SIMPLE. Bucket exists with SIMPLE
+    // layout format. OM startup should be successful.
+    conf.set(OZONE_OM_METADATA_LAYOUT, OZONE_OM_METADATA_LAYOUT_DEFAULT);
+    // ensure everything works again with SIMPLE layout format
+    cluster.getOzoneManager().restart();
+    OzoneBucket bucket2 = TestDataUtil.createVolumeAndBucket(cluster);
+    verifyBucketLayout(bucket2, OZONE_OM_METADATA_LAYOUT_DEFAULT, false);
+
+    // Cleanup buckets so that the cluster can be started with PREFIX
+    OzoneClient client = cluster.getClient();
+    OzoneVolume volume =
+        client.getObjectStore().getVolume(bucket.getVolumeName());
+    OzoneVolume volume2 =
+        client.getObjectStore().getVolume(bucket2.getVolumeName());
+    volume.deleteBucket(bucket.getName());
+    volume2.deleteBucket(bucket2.getName());
+
+    // case-3) Configured cluster layout as PREFIX and ENABLE_FSPATH=false.
+    // OM startup should fail as this is INVALID config.
+    cluster.getOzoneManager().stop();
+    conf.set(OZONE_OM_METADATA_LAYOUT, OZONE_OM_METADATA_LAYOUT_PREFIX);
+    conf.setBoolean(OZONE_OM_ENABLE_FILESYSTEM_PATHS, false);
+    verifyOmStartWithInvalidConfig(OZONE_OM_METADATA_LAYOUT_PREFIX);
+    verifyOmRestartWithInvalidConfig(OZONE_OM_METADATA_LAYOUT_PREFIX);
+
+    // case-4) Configured cluster layout as INVALID.
+    // OM startup should fail as this is INVALID config.
+    conf.set(OZONE_OM_METADATA_LAYOUT, "INVALID");
+    verifyOmStartWithInvalidConfig("INVALID");
+    verifyOmRestartWithInvalidConfig("INVALID");
+
+    // case-5) Configured cluster layout as PREFIX and ENABLE_FSPATH=true.
+    // No buckets. OM startup should be successful.
+    conf.set(OZONE_OM_METADATA_LAYOUT, OZONE_OM_METADATA_LAYOUT_PREFIX);
+    conf.setBoolean(OZONE_OM_ENABLE_FILESYSTEM_PATHS, true);
+    cluster.getOzoneManager().restart();
+    OzoneBucket bucket3 = TestDataUtil.createVolumeAndBucket(cluster);
+    verifyBucketLayout(bucket3, OZONE_OM_METADATA_LAYOUT_PREFIX, true);
+
+    // case-6) Configured cluster layout as SIMPLE. Bucket exists with PREFIX
+    // layout format. OM startup should fail.
+    conf.set(OZONE_OM_METADATA_LAYOUT, OZONE_OM_METADATA_LAYOUT_DEFAULT);
+    cluster.getOzoneManager().stop();
+    verifyOMStartupFailure(OZONE_OM_METADATA_LAYOUT_DEFAULT);
+    verifyOMRestartFailure(OZONE_OM_METADATA_LAYOUT_DEFAULT);
+  }
+
+  private void verifyBucketLayout(OzoneBucket bucket, String metadataLayout,
+      boolean isFSOBucket) {
+    Assert.assertNotNull(bucket);
+    Assert.assertEquals(2, bucket.getMetadata().size());
+    Assert.assertEquals(isFSOBucket,
+        OzoneFSUtils.isFSOptimizedBucket(bucket.getMetadata()));
+    Assert.assertEquals(metadataLayout,
+        bucket.getMetadata().get(OZONE_OM_METADATA_LAYOUT));
+  }
+
+  private void verifyOMStartupFailure(String clusterLayout) {
+    try {
+      cluster.getOzoneManager().start();
+      Assert.fail("Should fail OM startup in " + clusterLayout + " layout");
+    } catch (IOException ioe) {
+      GenericTestUtils.assertExceptionContains(
+          "Failed to start OM in " + clusterLayout + " layout format",
+          ioe);
+    }
+    cluster.getOzoneManager().stop();
+  }
+
+  private void verifyOMRestartFailure(String clusterLayout) {
+    try {
+      cluster.getOzoneManager().restart();
+      Assert.fail("Should fail OM startup in " + clusterLayout + " layout");
+    } catch (IOException ioe) {
+      GenericTestUtils.assertExceptionContains(
+          "Failed to start OM in " + clusterLayout + " layout format",
+          ioe);
+    }
+    cluster.getOzoneManager().stop();
+  }
+
+  private void verifyOmStartWithInvalidConfig(String clusterLayout)
+      throws IOException {
+    try {
+      cluster.getOzoneManager().start();
+      Assert.fail("Should fail OM startup in " + clusterLayout + " layout");
+    } catch (IllegalArgumentException iae) {
+      GenericTestUtils.assertExceptionContains(
+          "Failed to start OM in " + clusterLayout + " layout format", iae);
+    }
+    cluster.getOzoneManager().stop();
+  }
+
+  private void verifyOmRestartWithInvalidConfig(String clusterLayout)
+      throws IOException {
+    try {
+      cluster.getOzoneManager().restart();
+      Assert.fail("Should fail OM startup in " + clusterLayout + " layout");
+    } catch (IllegalArgumentException iae) {
+      GenericTestUtils.assertExceptionContains(
+          "Failed to start OM in " + clusterLayout + " layout format", iae);
+    }
+    cluster.getOzoneManager().stop();
+  }
+}
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 1132fe8..ea83ded 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
@@ -84,6 +84,8 @@ import org.apache.hadoop.hdds.utils.db.BatchOperation;
 import org.apache.hadoop.hdds.utils.db.DBCheckpoint;
 import org.apache.hadoop.hdds.utils.db.DBUpdatesWrapper;
 import org.apache.hadoop.hdds.utils.db.SequenceNumberNotFoundException;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.hdds.utils.db.TableIterator;
 import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
 import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
 import org.apache.hadoop.io.Text;
@@ -1103,23 +1105,23 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
    * Start service.
    */
   public void start() throws IOException {
+    initFSOLayout();
+
     omClientProtocolMetrics.register();
     HddsServerUtil.initializeMetrics(configuration, "OzoneManager");
 
     LOG.info(buildRpcServerStartMessage("OzoneManager RPC server",
         omRpcAddress));
 
+    metadataManager.start(configuration);
+
+    validatesBucketLayoutMismatches();
+
     // Start Ratis services
     if (omRatisServer != null) {
       omRatisServer.start();
     }
 
-    // TODO: Temporary workaround for OM upgrade path and will be replaced once
-    //  upgrade HDDS-3698 story reaches consensus. Instead of cluster level
-    //  configuration, OM needs to check this property on every bucket level.
-    getOMMetadataLayout();
-
-    metadataManager.start(configuration);
     startSecretManagerIfNecessary();
 
 
@@ -1173,6 +1175,8 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
    * Restarts the service. This method re-initializes the rpc server.
    */
   public void restart() throws IOException {
+    initFSOLayout();
+
     LOG.info(buildRpcServerStartMessage("OzoneManager RPC server",
         omRpcAddress));
 
@@ -1180,6 +1184,8 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
 
     instantiateServices();
 
+    validatesBucketLayoutMismatches();
+
     startSecretManagerIfNecessary();
 
     // Set metrics and start metrics back ground thread
@@ -3696,18 +3702,8 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
   }
 
   public String getOMMetadataLayout() {
-    String version = configuration.getTrimmed(OZONE_OM_METADATA_LAYOUT,
-        OZONE_OM_METADATA_LAYOUT_DEFAULT);
-    boolean omMetadataLayoutPrefix = StringUtils.equalsIgnoreCase(version,
-        OZONE_OM_METADATA_LAYOUT_PREFIX);
-    LOG.info("Configured {}={} and enabled:{} optimized OM FS operations",
-        OZONE_OM_METADATA_LAYOUT, version, omMetadataLayoutPrefix);
-
-    boolean isBucketFSOptimized =
-            omMetadataLayoutPrefix && getEnableFileSystemPaths();
-    OzoneManagerRatisUtils.setBucketFSOptimized(isBucketFSOptimized);
-
-    return version;
+    return configuration
+        .getTrimmed(OZONE_OM_METADATA_LAYOUT, 
OZONE_OM_METADATA_LAYOUT_DEFAULT);
   }
 
   /**
@@ -3816,4 +3812,81 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
     this.minMultipartUploadPartSize = partSizeForTest;
   }
 
+  private void initFSOLayout() {
+    // TODO: Temporary workaround for OM upgrade path and will be replaced once
+    //  upgrade HDDS-3698 story reaches consensus. Instead of cluster level
+    //  configuration, OM needs to check this property on every bucket level.
+    String metaLayout = getOMMetadataLayout();
+    boolean omMetadataLayoutPrefix = StringUtils.equalsIgnoreCase(metaLayout,
+        OZONE_OM_METADATA_LAYOUT_PREFIX);
+
+    boolean omMetadataLayoutSimple = StringUtils.equalsIgnoreCase(metaLayout,
+        OZONE_OM_METADATA_LAYOUT_DEFAULT);
+
+    if (!(omMetadataLayoutPrefix || omMetadataLayoutSimple)) {
+      StringBuilder msg = new StringBuilder();
+      msg.append("Invalid Configuration. Failed to start OM in ");
+      msg.append(metaLayout);
+      msg.append(" layout format. Supported values are either ");
+      msg.append(OZONE_OM_METADATA_LAYOUT_DEFAULT);
+      msg.append(" or ");
+      msg.append(OZONE_OM_METADATA_LAYOUT_PREFIX);
+
+      LOG.error(msg.toString());
+      throw new IllegalArgumentException(msg.toString());
+    }
+
+    if (omMetadataLayoutPrefix && !getEnableFileSystemPaths()) {
+      StringBuilder msg = new StringBuilder();
+      msg.append("Invalid Configuration. Failed to start OM in ");
+      msg.append(OZONE_OM_METADATA_LAYOUT_PREFIX);
+      msg.append(" layout format as '");
+      msg.append(OZONE_OM_ENABLE_FILESYSTEM_PATHS);
+      msg.append("' is false!");
+
+      LOG.error(msg.toString());
+      throw new IllegalArgumentException(msg.toString());
+    }
+
+    OzoneManagerRatisUtils.setBucketFSOptimized(omMetadataLayoutPrefix);
+    String status = omMetadataLayoutPrefix ? "enabled" : "disabled";
+    LOG.info("Configured {}={} and {} optimized OM FS operations",
+        OZONE_OM_METADATA_LAYOUT, metaLayout, status);
+  }
+
+  private void validatesBucketLayoutMismatches() throws IOException {
+    String clusterLevelMetaLayout = getOMMetadataLayout();
+
+    TableIterator<String, ? extends Table.KeyValue<String, OmBucketInfo>>
+        iterator = metadataManager.getBucketTable().iterator();
+
+    while (iterator.hasNext()) {
+      Map<String, String> bucketMeta = 
iterator.next().getValue().getMetadata();
+      verifyBucketMetaLayout(clusterLevelMetaLayout, bucketMeta);
+    }
+  }
+
+  private void verifyBucketMetaLayout(String clusterLevelMetaLayout,
+      Map<String, String> bucketMetadata) throws IOException {
+    String bucketMetaLayout = bucketMetadata.get(OZONE_OM_METADATA_LAYOUT);
+    if (StringUtils.isBlank(bucketMetaLayout)) {
+      // Defaulting to SIMPLE
+      bucketMetaLayout = OZONE_OM_METADATA_LAYOUT_DEFAULT;
+    }
+    boolean supportedMetadataLayout =
+        StringUtils.equalsIgnoreCase(clusterLevelMetaLayout, bucketMetaLayout);
+
+    if (!supportedMetadataLayout) {
+      StringBuilder msg = new StringBuilder();
+      msg.append("Failed to start OM in ");
+      msg.append(clusterLevelMetaLayout);
+      msg.append(" layout format as existing bucket has a different layout ");
+      msg.append(bucketMetaLayout);
+      msg.append(" metadata format");
+
+      LOG.error(msg.toString());
+      throw new IOException(msg.toString());
+    }
+  }
+
 }

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

Reply via email to