You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by si...@apache.org on 2023/02/21 16:40:44 UTC

[ozone] branch master updated: HDDS-7906. [Snapshot] Wait for checkpoint creation if snapshot in cache and not committed to DB. (#4249)

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 4d09962a65 HDDS-7906. [Snapshot] Wait for checkpoint creation if snapshot in cache and not committed to DB. (#4249)
4d09962a65 is described below

commit 4d09962a659a2b39a2580215975180e5491b1b00
Author: Sadanand Shenoy <sa...@gmail.com>
AuthorDate: Tue Feb 21 22:10:38 2023 +0530

    HDDS-7906. [Snapshot] Wait for checkpoint creation if snapshot in cache and not committed to DB. (#4249)
---
 .../hadoop/hdds/utils/db/RDBCheckpointManager.java |  3 +-
 .../hadoop/fs/ozone/TestRootedOzoneFileSystem.java | 39 ++++++++++++++++++++++
 .../hadoop/ozone/om/OmMetadataManagerImpl.java     | 33 ++++++++----------
 .../apache/hadoop/ozone/om/OmSnapshotManager.java  | 13 ++++++--
 .../ozone/om/ratis/OzoneManagerDoubleBuffer.java   |  7 ++--
 .../om/ratis/TestOzoneManagerDoubleBuffer.java     | 12 ++++---
 6 files changed, 74 insertions(+), 33 deletions(-)

diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/RDBCheckpointManager.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/RDBCheckpointManager.java
index 7bb4694093..ee5408b13b 100644
--- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/RDBCheckpointManager.java
+++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/RDBCheckpointManager.java
@@ -113,7 +113,8 @@ public class RDBCheckpointManager implements Closeable {
    * Wait for checkpoint directory to be created for 5 secs with 100 millis
    * poll interval.
    */
-  private void waitForCheckpointDirectoryExist(File file) throws IOException {
+  public static void waitForCheckpointDirectoryExist(File file)
+      throws IOException {
     Instant start = Instant.now();
     try {
       with().atMost(POLL_MAX_DURATION)
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
index 482eb1d47c..c319dd3fd3 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
@@ -2213,4 +2213,43 @@ public class TestRootedOzoneFileSystem {
     OzoneVolume ozoneVolume = objectStore.getVolume(linkVolume);
     ozoneVolume.createBucket(linkBucket, builder.build());
   }
+
+  @Test
+  public void testSnapshotRead() throws Exception {
+    // Init data
+    OzoneBucket bucket1 =
+        TestDataUtil.createVolumeAndBucket(cluster, bucketLayout);
+    Path volume1Path = new Path(OZONE_URI_DELIMITER, bucket1.getVolumeName());
+    Path bucket1Path = new Path(volume1Path, bucket1.getName());
+    Path file1 = new Path(bucket1Path, "key1");
+    Path file2 = new Path(bucket1Path, "key2");
+
+    ContractTestUtils.touch(fs, file1);
+    ContractTestUtils.touch(fs, file2);
+
+    OzoneBucket bucket2 =
+        TestDataUtil.createVolumeAndBucket(cluster, bucketLayout);
+    Path volume2Path = new Path(OZONE_URI_DELIMITER, bucket2.getVolumeName());
+    Path bucket2Path = new Path(volume2Path, bucket2.getName());
+
+    fs.mkdirs(bucket2Path);
+    Path snapPath1 = fs.createSnapshot(bucket1Path, "snap1");
+    Path snapPath2 = fs.createSnapshot(bucket2Path, "snap1");
+
+    Path file3 = new Path(bucket1Path, "key3");
+    ContractTestUtils.touch(fs, file3);
+
+    Path snapPath3 = fs.createSnapshot(bucket1Path, "snap2");
+
+    try {
+      FileStatus[] f1 = fs.listStatus(snapPath1);
+      FileStatus[] f2 = fs.listStatus(snapPath2);
+      FileStatus[] f3 = fs.listStatus(snapPath3);
+      Assert.assertEquals(2, f1.length);
+      Assert.assertEquals(0, f2.length);
+      Assert.assertEquals(3, f3.length);
+    } catch (Exception e) {
+      Assert.fail("Failed to read/list on snapshotPath, exception: " + e);
+    }
+  }
 }
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
index f079030e64..180e5b5e6c 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java
@@ -40,6 +40,7 @@ import org.apache.hadoop.hdds.utils.db.DBStore;
 import org.apache.hadoop.hdds.utils.db.DBStoreBuilder;
 import org.apache.hadoop.hdds.utils.db.RocksDBConfiguration;
 import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.hdds.utils.db.RDBCheckpointManager;
 import org.apache.hadoop.hdds.utils.db.Table.KeyValue;
 import org.apache.hadoop.hdds.utils.db.TableIterator;
 import org.apache.hadoop.hdds.utils.db.TypedTable;
@@ -305,32 +306,25 @@ public class OmMetadataManagerImpl implements OMMetadataManager,
   }
 
   // metadata constructor for snapshots
-  private OmMetadataManagerImpl(OzoneConfiguration conf, String snapshotDirName)
-      throws IOException {
+  OmMetadataManagerImpl(OzoneConfiguration conf, String snapshotDirName,
+      boolean isSnapshotInCache) throws IOException {
     lock = new OmReadOnlyLock();
     omEpoch = 0;
     String snapshotDir = OMStorage.getOmDbDir(conf) +
         OM_KEY_PREFIX + OM_SNAPSHOT_DIR;
-    setStore(loadDB(conf, new File(snapshotDir),
-        OM_DB_NAME + snapshotDirName, true));
+    File metaDir = new File(snapshotDir);
+    String dbName = OM_DB_NAME + snapshotDirName;
+    // The check is only to prevent every snapshot read to perform a disk IO
+    // and check if a checkpoint dir exists. If entry is present in cache,
+    // it is most likely DB entries will get flushed in this wait time.
+    if (isSnapshotInCache) {
+      File checkpoint = Paths.get(metaDir.toPath().toString(), dbName).toFile();
+      RDBCheckpointManager.waitForCheckpointDirectoryExist(checkpoint);
+    }
+    setStore(loadDB(conf, metaDir, dbName, true));
     initializeOmTables(false);
   }
 
-  /**
-   * Factory method for creating snapshot metadata manager.
-   *
-   * @param conf - ozone configuration
-   * @param snapshotDirName - the UUID that identifies the snapshot
-   * @return the metadata manager representing the snapshot
-   * @throws IOException
-   */
-  public static OmMetadataManagerImpl createSnapshotMetadataManager(
-      OzoneConfiguration conf, String snapshotDirName) throws IOException {
-    OmMetadataManagerImpl smm = new OmMetadataManagerImpl(conf,
-        snapshotDirName);
-    return smm;
-  }
-
   @Override
   public Table<String, PersistedUserVolumeInfo> getUserTable() {
     return userTable;
@@ -913,7 +907,6 @@ public class OmMetadataManagerImpl implements OMMetadataManager,
     }
     return false;
   }
-
   /**
    * Checks if a key starts with the given prefix is present in the table.
    *
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 8164b0a3f9..a218414acc 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
@@ -32,6 +32,7 @@ import org.apache.hadoop.hdds.utils.db.DBCheckpoint;
 import org.apache.hadoop.hdds.utils.db.RDBStore;
 import org.apache.hadoop.hdds.utils.db.managed.ManagedOptions;
 import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksDB;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
 import org.apache.hadoop.ozone.OzoneConfigKeys;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
 import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
@@ -94,6 +95,10 @@ public final class OmSnapshotManager implements AutoCloseable {
         // see if the snapshot exists
         snapshotInfo = getSnapshotInfo(snapshotTableKey);
 
+        boolean isSnapshotInCache =
+            ozoneManager.getMetadataManager().getSnapshotInfoTable()
+                .getCacheValue(new CacheKey<>(snapshotTableKey)) != null;
+
         // read in the snapshot
         OzoneConfiguration conf = ozoneManager.getConfiguration();
         OMMetadataManager snapshotMetadataManager;
@@ -102,9 +107,8 @@ public final class OmSnapshotManager implements AutoCloseable {
         // RocksDB instance, creating an OmMetadataManagerImpl instance based on
         // that
         try {
-          snapshotMetadataManager = OmMetadataManagerImpl
-              .createSnapshotMetadataManager(
-              conf, snapshotInfo.getCheckpointDirName());
+          snapshotMetadataManager = new OmMetadataManagerImpl(conf,
+                  snapshotInfo.getCheckpointDirName(), isSnapshotInCache);
         } catch (IOException e) {
           LOG.error("Failed to retrieve snapshot: {}, {}", snapshotTableKey, e);
           throw e;
@@ -156,6 +160,9 @@ public final class OmSnapshotManager implements AutoCloseable {
     final DBCheckpoint dbCheckpoint = store.getSnapshot(
         snapshotInfo.getCheckpointDirName());
 
+    LOG.info("Created checkpoint : {} for snapshot {}",
+        dbCheckpoint.getCheckpointLocation(), snapshotInfo.getName());
+
     final RocksDBCheckpointDiffer dbCpDiffer =
         store.getRocksDBCheckpointDiffer();
 
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerDoubleBuffer.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerDoubleBuffer.java
index 9e03e10f52..6c8048a5bb 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerDoubleBuffer.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerDoubleBuffer.java
@@ -440,10 +440,9 @@ public final class OzoneManagerDoubleBuffer {
       // 1. It is first element in the response,
       // 2. Current request is createSnapshot request.
       // 3. Previous request was createSnapshot request.
-      if (response.isEmpty() ||
-          omResponse.getCreateSnapshotResponse() != null ||
-          (previousOmResponse != null &&
-              previousOmResponse.getCreateSnapshotResponse() != null)) {
+      if (response.isEmpty() || omResponse.hasCreateSnapshotResponse()
+          || (previousOmResponse != null &&
+          previousOmResponse.hasCreateSnapshotResponse())) {
         response.add(new LinkedList<>());
       }
 
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerDoubleBuffer.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerDoubleBuffer.java
index cb977f46db..57dbf47e3e 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerDoubleBuffer.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerDoubleBuffer.java
@@ -33,6 +33,7 @@ import org.apache.hadoop.ozone.om.ratis.metrics.OzoneManagerDoubleBufferMetrics;
 import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.response.bucket.OMBucketCreateResponse;
 import org.apache.hadoop.ozone.om.response.key.OMKeyCreateResponse;
+import org.apache.hadoop.ozone.om.response.snapshot.OMSnapshotCreateResponse;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateSnapshotResponse;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
 import org.junit.jupiter.api.AfterEach;
@@ -68,9 +69,9 @@ class TestOzoneManagerDoubleBuffer {
   private static OMClientResponse omBucketCreateResponse =
       mock(OMBucketCreateResponse.class);
   private static OMClientResponse omSnapshotCreateResponse1 =
-      mock(OMBucketCreateResponse.class);
+      mock(OMSnapshotCreateResponse.class);
   private static OMClientResponse omSnapshotCreateResponse2 =
-      mock(OMBucketCreateResponse.class);
+      mock(OMSnapshotCreateResponse.class);
   @TempDir
   private File tempDir;
 
@@ -109,9 +110,10 @@ class TestOzoneManagerDoubleBuffer {
     when(omBucketResponse.getTraceID()).thenReturn("bucketTraceId");
     when(omSnapshotResponse1.getTraceID()).thenReturn("snapshotTraceId-1");
     when(omSnapshotResponse2.getTraceID()).thenReturn("snapshotTraceId-2");
-
-    when(omKeyResponse.getCreateSnapshotResponse()).thenReturn(null);
-    when(omBucketResponse.getCreateSnapshotResponse()).thenReturn(null);
+    when(omSnapshotResponse1.hasCreateSnapshotResponse())
+        .thenReturn(true);
+    when(omSnapshotResponse2.hasCreateSnapshotResponse())
+        .thenReturn(true);
     when(omSnapshotResponse1.getCreateSnapshotResponse())
         .thenReturn(snapshotResponse1);
     when(omSnapshotResponse2.getCreateSnapshotResponse())


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org