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

adoroszlai 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 a8db9cd476 HDDS-11749. Extract moveToTrash implementation to client 
code (#7453)
a8db9cd476 is described below

commit a8db9cd4766db9086b6c28d431e2faf1df1d9a49
Author: Ashish Kumar <[email protected]>
AuthorDate: Wed Nov 20 19:32:13 2024 +0530

    HDDS-11749. Extract moveToTrash implementation to client code (#7453)
---
 .../apache/hadoop/fs/ozone/OzoneTrashPolicy.java   | 208 +++++++++++++++++++++
 .../org/apache/hadoop/fs/ozone/package-info.java   |  20 ++
 .../apache/hadoop/ozone/om/TrashPolicyOzone.java   | 168 +----------------
 3 files changed, 232 insertions(+), 164 deletions(-)

diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/fs/ozone/OzoneTrashPolicy.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/fs/ozone/OzoneTrashPolicy.java
new file mode 100644
index 0000000000..a250832215
--- /dev/null
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/fs/ozone/OzoneTrashPolicy.java
@@ -0,0 +1,208 @@
+/*
+ * 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.hadoop.fs.ozone;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileAlreadyExistsException;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.InvalidPathException;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.TrashPolicyDefault;
+import org.apache.hadoop.fs.permission.FsAction;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.OFSPath;
+import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
+import org.apache.hadoop.ozone.om.helpers.OzoneFSUtils;
+import org.apache.hadoop.util.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_DEFAULT;
+import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY;
+
+
+/**
+ * TrashPolicy for Ozone Specific Trash Operations.
+ */
+public class OzoneTrashPolicy extends TrashPolicyDefault {
+
+  private static final Logger LOG =
+      LoggerFactory.getLogger(OzoneTrashPolicy.class);
+
+  protected static final Path CURRENT = new Path("Current");
+
+  protected static final int MSECS_PER_MINUTE = 60 * 1000;
+
+  private static final FsPermission PERMISSION =
+      new FsPermission(FsAction.ALL, FsAction.NONE, FsAction.NONE);
+  private OzoneConfiguration ozoneConfiguration;
+
+  public OzoneConfiguration getOzoneConfiguration() {
+    return ozoneConfiguration;
+  }
+
+  @Override
+  public void initialize(Configuration conf, FileSystem fs) {
+    this.fs = fs;
+    ozoneConfiguration = OzoneConfiguration.of(conf);
+    float hadoopTrashInterval = conf.getFloat(
+        FS_TRASH_INTERVAL_KEY, FS_TRASH_INTERVAL_DEFAULT);
+    // check whether user has configured ozone specific trash-interval
+    // if not fall back to hadoop configuration
+    this.deletionInterval = (long)(conf.getFloat(
+        OMConfigKeys.OZONE_FS_TRASH_INTERVAL_KEY, hadoopTrashInterval)
+        * MSECS_PER_MINUTE);
+  }
+
+  @Override
+  public boolean moveToTrash(Path path) throws IOException {
+    if (validatePath(path)) {
+      if (!isEnabled()) {
+        return false;
+      }
+
+      if (!path.isAbsolute()) {                  // make path absolute
+        path = new Path(fs.getWorkingDirectory(), path);
+      }
+
+      // check that path exists
+      fs.getFileStatus(path);
+      String qpath = fs.makeQualified(path).toString();
+
+      Path trashRoot = fs.getTrashRoot(path);
+      Path trashCurrent = new Path(trashRoot, CURRENT);
+      if (qpath.startsWith(trashRoot.toString())) {
+        return false;                               // already in trash
+      }
+
+      if (trashRoot.getParent().toString().startsWith(qpath)) {
+        throw new IOException("Cannot move \"" + path
+            + "\" to the trash, as it contains the trash");
+      }
+
+      Path trashPath;
+      Path baseTrashPath;
+      if (fs.getUri().getScheme().equals(OzoneConsts.OZONE_OFS_URI_SCHEME)) {
+        OFSPath ofsPath = new OFSPath(path, ozoneConfiguration);
+        // trimming volume and bucket in order to be compatible with o3fs
+        // Also including volume and bucket name in the path is redundant as
+        // the key is already in a particular volume and bucket.
+        Path trimmedVolumeAndBucket =
+            new Path(OzoneConsts.OZONE_URI_DELIMITER
+                + ofsPath.getKeyName());
+        trashPath = makeTrashRelativePath(trashCurrent, 
trimmedVolumeAndBucket);
+        baseTrashPath = makeTrashRelativePath(trashCurrent,
+            trimmedVolumeAndBucket.getParent());
+      } else {
+        trashPath = makeTrashRelativePath(trashCurrent, path);
+        baseTrashPath = makeTrashRelativePath(trashCurrent, path.getParent());
+      }
+
+      IOException cause = null;
+
+      // try twice, in case checkpoint between the mkdirs() & rename()
+      for (int i = 0; i < 2; i++) {
+        try {
+          if (!fs.mkdirs(baseTrashPath, PERMISSION)) {      // create current
+            LOG.warn("Can't create(mkdir) trash directory: " + baseTrashPath);
+            return false;
+          }
+        } catch (FileAlreadyExistsException e) {
+          // find the path which is not a directory, and modify baseTrashPath
+          // & trashPath, then mkdirs
+          Path existsFilePath = baseTrashPath;
+          while (!fs.exists(existsFilePath)) {
+            existsFilePath = existsFilePath.getParent();
+          }
+          baseTrashPath = new Path(baseTrashPath.toString()
+              .replace(existsFilePath.toString(),
+                  existsFilePath.toString() + Time.now()));
+          trashPath = new Path(baseTrashPath, trashPath.getName());
+          // retry, ignore current failure
+          --i;
+          continue;
+        } catch (IOException e) {
+          LOG.warn("Can't create trash directory: " + baseTrashPath, e);
+          cause = e;
+          break;
+        }
+        try {
+          // if the target path in Trash already exists, then append with
+          // a current time in millisecs.
+          String orig = trashPath.toString();
+
+          while (fs.exists(trashPath)) {
+            trashPath = new Path(orig + Time.now());
+          }
+
+          // move to current trash
+          boolean renamed = fs.rename(path, trashPath);
+          if (!renamed) {
+            LOG.error("Failed to move to trash: {}", path);
+            throw new IOException("Failed to move to trash: " + path);
+          }
+          LOG.info("Moved: '" + path + "' to trash at: " + trashPath);
+          return true;
+        } catch (IOException e) {
+          cause = e;
+        }
+      }
+      throw (IOException) new IOException("Failed to move to trash: " + path)
+          .initCause(cause);
+    }
+    return false;
+  }
+
+  private boolean validatePath(Path path) throws IOException {
+    String key = path.toUri().getPath();
+    // Check to see if bucket is path item to be deleted.
+    // Cannot moveToTrash if bucket is deleted,
+    // return error for this condition
+    OFSPath ofsPath = new OFSPath(key.substring(1), ozoneConfiguration);
+    if (path.isRoot() || ofsPath.isBucket()) {
+      throw new IOException("Recursive rm of bucket "
+          + path + " not permitted");
+    }
+
+    Path trashRoot = this.fs.getTrashRoot(path);
+
+    LOG.debug("Key path to moveToTrash: {}", key);
+    String trashRootKey = trashRoot.toUri().getPath();
+    LOG.debug("TrashrootKey for moveToTrash: {}", trashRootKey);
+
+    if (!OzoneFSUtils.isValidName(key)) {
+      throw new InvalidPathException("Invalid path Name " + key);
+    }
+    // first condition tests when length key is <= length trash
+    // and second when length key > length trash
+    if ((key.contains(this.fs.TRASH_PREFIX)) && (trashRootKey.startsWith(key))
+        || key.startsWith(trashRootKey)) {
+      return false;
+    }
+    return true;
+  }
+
+  private Path makeTrashRelativePath(Path basePath, Path rmFilePath) {
+    return Path.mergePaths(basePath, rmFilePath);
+  }
+
+}
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/fs/ozone/package-info.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/fs/ozone/package-info.java
new file mode 100644
index 0000000000..17803f7af0
--- /dev/null
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/fs/ozone/package-info.java
@@ -0,0 +1,20 @@
+/**
+ * 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.fs.ozone;
+/**
+ * Ozone trash policy implementation.
+ */
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/TrashPolicyOzone.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/TrashPolicyOzone.java
index 9064d5d454..2aa8114e27 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/TrashPolicyOzone.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/TrashPolicyOzone.java
@@ -33,22 +33,14 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.TrashPolicyDefault;
 import org.apache.hadoop.fs.FileAlreadyExistsException;
-import org.apache.hadoop.fs.permission.FsAction;
-import org.apache.hadoop.fs.permission.FsPermission;
-import org.apache.hadoop.fs.InvalidPathException;
+import org.apache.hadoop.fs.ozone.OzoneTrashPolicy;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
-import org.apache.hadoop.ozone.OzoneConsts;
 import org.apache.hadoop.ozone.conf.OMClientConfig;
-import org.apache.hadoop.ozone.om.helpers.OzoneFSUtils;
-import org.apache.hadoop.ozone.OFSPath;
 import org.apache.hadoop.util.Time;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY;
-import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_DEFAULT;
 import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_CHECKPOINT_INTERVAL_KEY;
 import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_CHECKPOINT_INTERVAL_DEFAULT;
 
@@ -57,45 +49,26 @@ import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_CHECKP
  *  of TrashPolicy ozone-specific trash optimizations are/will be made such as
  *  having a multithreaded TrashEmptier.
  */
-public class TrashPolicyOzone extends TrashPolicyDefault {
+public class TrashPolicyOzone extends OzoneTrashPolicy {
 
   private static final Logger LOG =
       LoggerFactory.getLogger(TrashPolicyOzone.class);
 
-  private static final Path CURRENT = new Path("Current");
-
-  private static final FsPermission PERMISSION =
-      new FsPermission(FsAction.ALL, FsAction.NONE, FsAction.NONE);
-
   private static final DateFormat CHECKPOINT = new SimpleDateFormat(
       "yyMMddHHmmss");
   /** Format of checkpoint directories used prior to Hadoop 0.23. */
   private static final DateFormat OLD_CHECKPOINT =
       new SimpleDateFormat("yyMMddHHmm");
-  private static final int MSECS_PER_MINUTE = 60 * 1000;
-
   private long emptierInterval;
 
-  private Configuration configuration;
-
   private OzoneManager om;
 
-  private OzoneConfiguration ozoneConfiguration;
-
   public TrashPolicyOzone() {
   }
 
   @Override
   public void initialize(Configuration conf, FileSystem fs) {
-    this.fs = fs;
-    this.configuration = conf;
-    float hadoopTrashInterval = conf.getFloat(
-        FS_TRASH_INTERVAL_KEY, FS_TRASH_INTERVAL_DEFAULT);
-    // check whether user has configured ozone specific trash-interval
-    // if not fall back to hadoop configuration
-    this.deletionInterval = (long)(conf.getFloat(
-        OMConfigKeys.OZONE_FS_TRASH_INTERVAL_KEY, hadoopTrashInterval)
-        * MSECS_PER_MINUTE);
+    super.initialize(conf, fs);
     float hadoopCheckpointInterval = conf.getFloat(
         FS_TRASH_CHECKPOINT_INTERVAL_KEY,
         FS_TRASH_CHECKPOINT_INTERVAL_DEFAULT);
@@ -112,7 +85,6 @@ public class TrashPolicyOzone extends TrashPolicyDefault {
           + "Changing to default value 0", deletionInterval);
       this.deletionInterval = 0;
     }
-    ozoneConfiguration = OzoneConfiguration.of(this.configuration);
   }
 
   TrashPolicyOzone(FileSystem fs, Configuration conf, OzoneManager om) {
@@ -122,142 +94,10 @@ public class TrashPolicyOzone extends TrashPolicyDefault {
 
   @Override
   public Runnable getEmptier() throws IOException {
-    return new TrashPolicyOzone.Emptier((OzoneConfiguration) configuration,
+    return new TrashPolicyOzone.Emptier(getOzoneConfiguration(),
         emptierInterval, om.getThreadNamePrefix());
   }
 
-  @Override
-  public boolean moveToTrash(Path path) throws IOException {
-    if (validatePath(path)) {
-      if (!isEnabled()) {
-        return false;
-      }
-
-      if (!path.isAbsolute()) {                  // make path absolute
-        path = new Path(fs.getWorkingDirectory(), path);
-      }
-
-      // check that path exists
-      fs.getFileStatus(path);
-      String qpath = fs.makeQualified(path).toString();
-
-      Path trashRoot = fs.getTrashRoot(path);
-      Path trashCurrent = new Path(trashRoot, CURRENT);
-      if (qpath.startsWith(trashRoot.toString())) {
-        return false;                               // already in trash
-      }
-
-      if (trashRoot.getParent().toString().startsWith(qpath)) {
-        throw new IOException("Cannot move \"" + path
-            + "\" to the trash, as it contains the trash");
-      }
-
-      Path trashPath;
-      Path baseTrashPath;
-      if (fs.getUri().getScheme().equals(OzoneConsts.OZONE_OFS_URI_SCHEME)) {
-        OFSPath ofsPath = new OFSPath(path, ozoneConfiguration);
-        // trimming volume and bucket in order to be compatible with o3fs
-        // Also including volume and bucket name in the path is redundant as
-        // the key is already in a particular volume and bucket.
-        Path trimmedVolumeAndBucket =
-            new Path(OzoneConsts.OZONE_URI_DELIMITER
-                + ofsPath.getKeyName());
-        trashPath = makeTrashRelativePath(trashCurrent, 
trimmedVolumeAndBucket);
-        baseTrashPath = makeTrashRelativePath(trashCurrent,
-            trimmedVolumeAndBucket.getParent());
-      } else {
-        trashPath = makeTrashRelativePath(trashCurrent, path);
-        baseTrashPath = makeTrashRelativePath(trashCurrent, path.getParent());
-      }
-
-      IOException cause = null;
-
-      // try twice, in case checkpoint between the mkdirs() & rename()
-      for (int i = 0; i < 2; i++) {
-        try {
-          if (!fs.mkdirs(baseTrashPath, PERMISSION)) {      // create current
-            LOG.warn("Can't create(mkdir) trash directory: " + baseTrashPath);
-            return false;
-          }
-        } catch (FileAlreadyExistsException e) {
-          // find the path which is not a directory, and modify baseTrashPath
-          // & trashPath, then mkdirs
-          Path existsFilePath = baseTrashPath;
-          while (!fs.exists(existsFilePath)) {
-            existsFilePath = existsFilePath.getParent();
-          }
-          baseTrashPath = new Path(baseTrashPath.toString()
-              .replace(existsFilePath.toString(),
-                  existsFilePath.toString() + Time.now()));
-          trashPath = new Path(baseTrashPath, trashPath.getName());
-          // retry, ignore current failure
-          --i;
-          continue;
-        } catch (IOException e) {
-          LOG.warn("Can't create trash directory: " + baseTrashPath, e);
-          cause = e;
-          break;
-        }
-        try {
-          // if the target path in Trash already exists, then append with
-          // a current time in millisecs.
-          String orig = trashPath.toString();
-
-          while (fs.exists(trashPath)) {
-            trashPath = new Path(orig + Time.now());
-          }
-
-          // move to current trash
-          boolean renamed = fs.rename(path, trashPath);
-          if (!renamed) {
-            LOG.error("Failed to move to trash: {}", path);
-            throw new IOException("Failed to move to trash: " + path);
-          }
-          LOG.info("Moved: '" + path + "' to trash at: " + trashPath);
-          return true;
-        } catch (IOException e) {
-          cause = e;
-        }
-      }
-      throw (IOException) new IOException("Failed to move to trash: " + path)
-          .initCause(cause);
-    }
-    return false;
-  }
-
-  private boolean validatePath(Path path) throws IOException {
-    String key = path.toUri().getPath();
-    // Check to see if bucket is path item to be deleted.
-    // Cannot moveToTrash if bucket is deleted,
-    // return error for this condition
-    OFSPath ofsPath = new OFSPath(key.substring(1), ozoneConfiguration);
-    if (path.isRoot() || ofsPath.isBucket()) {
-      throw new IOException("Recursive rm of bucket "
-          + path.toString() + " not permitted");
-    }
-
-    Path trashRoot = this.fs.getTrashRoot(path);
-
-    LOG.debug("Key path to moveToTrash: {}", key);
-    String trashRootKey = trashRoot.toUri().getPath();
-    LOG.debug("TrashrootKey for moveToTrash: {}", trashRootKey);
-
-    if (!OzoneFSUtils.isValidName(key)) {
-      throw new InvalidPathException("Invalid path Name " + key);
-    }
-    // first condition tests when length key is <= length trash
-    // and second when length key > length trash
-    if ((key.contains(this.fs.TRASH_PREFIX)) && (trashRootKey.startsWith(key))
-        || key.startsWith(trashRootKey)) {
-      return false;
-    }
-    return true;
-  }
-
-  private Path makeTrashRelativePath(Path basePath, Path rmFilePath) {
-    return Path.mergePaths(basePath, rmFilePath);
-  }
-
   protected class Emptier implements Runnable {
 
     private Configuration conf;


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

Reply via email to