Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,6 @@ private OMConfigKeys() {
public static final String OZONE_OM_LAYOUT_VERSION =
"ozone.om.layout.version";
public static final String OZONE_OM_LAYOUT_VERSION_DEFAULT = "V0";

public static final String OZONE_OM_LAYOUT_VERSION_V1 = "V1";
}
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ public boolean setAcls(List<OzoneAcl> newAcls) {
return OzoneAclUtil.setAcl(acls, newAcls);
}

public void setParentObjectID(long parentObjectID) {
this.parentObjectID = parentObjectID;
}

/**
* Builder of OmKeyInfo.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,46 @@ public static boolean isImmediateChild(String parentKey, String childKey) {

return parentPath.equals(childParent);
}

/**
* The function returns parent directory from the given absolute path. For
* example, the given key path '/a/b/c/d/e/file1' then it returns parent
* directory name as 'e'.
*
* @param keyName key name
*/
public static String getParentDir(@Nonnull String keyName) {
java.nio.file.Path fileName = Paths.get(keyName).getParent();
if (fileName != null) {
return fileName.toString();
}
// failed to converts a path key
return keyName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not got when parent is null, why we need to return keyName

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done to avoid any NPE and I thought below logic will throw exception. Does that make sense to you?

OzoneFileStatus toKeyParentDirStatus = getOMKeyInfoIfExists(metaMgr,
          volumeName, bucketName, toKeyParentDir, 0);
  // check if the immediate parent exists
  if (toKeyParentDirStatus == null || toKeyParentDirStatus.isFile()) {
    throw new OMException(String.format(
            "Failed to rename %s to %s, %s is a file", fromKeyName, toKeyName,
            toKeyParentDir), OMException.ResultCodes.KEY_RENAME_ERROR);
  }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean to say here because we use Paths.get will cause issue here?

Copy link
Contributor Author

@rakeshadr rakeshadr Nov 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it won't occur in general, just return keyname it for the safer side.

}

/**
* This function appends the given file name to the given key name path.
*
* @param keyName key name
* @param fileName file name
* @return full path
*/
public static String appendFileNameToKeyPath(String keyName,
String fileName) {
StringBuilder newToKeyName = new StringBuilder(keyName);
newToKeyName.append(OZONE_URI_DELIMITER);
newToKeyName.append(fileName);
return newToKeyName.toString();
}

/**
* Returns the number of path components in the given keyName.
*
* @param keyName keyname
* @return path components count
*/
public static int getFileCount(String keyName) {
java.nio.file.Path keyPath = Paths.get(keyName);
return keyPath.getNameCount();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ public void testNonExplicitlyCreatedPathExistsAfterItsLeafsWereRemoved()
interimPath.getName(), fileStatus.getPath().getName());
}

private void testRenameDir() throws Exception {
protected void testRenameDir() throws Exception {
final String dir = "/root_dir/dir1";
final Path source = new Path(fs.getUri().toString() + dir);
final Path dest = new Path(source.toString() + ".renamed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.test.LambdaTestUtils;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.junit.Rule;
Expand All @@ -50,9 +52,7 @@
import java.util.Map;

import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;

/**
* Ozone file system tests that are not covered by contract tests,
Expand Down Expand Up @@ -260,6 +260,44 @@ private void testListFilesRecursive() throws Exception {
expectedFilesCount, actualCount);
}


protected void testRenameDir() throws Exception {
final String root = "/root_dir";
final String dir = root + "/dir1";
final Path source = new Path(fs.getUri().toString() + dir);
final Path dest = new Path(source.toString() + ".renamed");
// Add a sub-dir to the directory to be moved.
final Path subdir = new Path(source, "sub_dir1");
fs.mkdirs(subdir);
LOG.info("Created dir {}", subdir);

// case-1) source is a sub-dir to destin
final Path sourceRoot = new Path(fs.getUri().toString() + root);
LOG.info("Rename op-> source:/root_dir to destin:/root_dir/dir1/sub_dir1");
try {
fs.rename(sourceRoot, subdir);
Assert.fail("Should throw exception : Cannot rename a directory to" +
" its own subdirectory");
} catch (OMException e) {
// expected
}

LOG.info("Will move {} to {}", source, dest);
fs.rename(source, dest);

assertTrue("Directory rename failed", fs.exists(dest));
// Verify that the subdir is also renamed i.e. keys corresponding to the
// sub-directories of the renamed directory have also been renamed.
assertTrue("Keys under the renamed directory not renamed",
fs.exists(new Path(dest, "sub_dir1")));

// Test if one path belongs to other FileSystem.
Path fakeDir = new Path(fs.getUri().toString() + "fake" + dir);
LambdaTestUtils.intercept(IllegalArgumentException.class, "Wrong FS",
() -> fs.rename(fakeDir, dest));
}


@Test(timeout = 300_000)
@Override
public void testFileSystem() throws Exception {
Expand Down Expand Up @@ -292,6 +330,9 @@ public void testFileSystem() throws Exception {
tableCleanup();
testListStatusOnLargeDirectory();
tableCleanup();

testRenameDir();
tableCleanup();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.hadoop.ozone.om.request.key.OMKeyDeleteRequest;
import org.apache.hadoop.ozone.om.request.key.OMKeyPurgeRequest;
import org.apache.hadoop.ozone.om.request.key.OMKeyRenameRequest;
import org.apache.hadoop.ozone.om.request.key.OMKeyRenameRequestV1;
import org.apache.hadoop.ozone.om.request.key.OMKeysRenameRequest;
import org.apache.hadoop.ozone.om.request.key.OMTrashRecoverRequest;
import org.apache.hadoop.ozone.om.request.key.acl.OMKeyAddAclRequest;
Expand Down Expand Up @@ -149,6 +150,9 @@ public static OMClientRequest createClientRequest(OMRequest omRequest) {
case DeleteKeys:
return new OMKeysDeleteRequest(omRequest);
case RenameKey:
if (omLayoutVersionV1) {
return new OMKeyRenameRequestV1(omRequest);
}
return new OMKeyRenameRequest(omRequest);
case RenameKeys:
return new OMKeysRenameRequest(omRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.google.common.base.Optional;

import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.OmUtils;
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.OzoneAclUtil;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
Expand Down Expand Up @@ -156,6 +160,9 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
getOmRequest());
OmBucketInfo omBucketInfo = OmBucketInfo.getFromProtobuf(bucketInfo);

// Add layout version V1 to bucket info
addLayoutVersionToBucket(ozoneManager, omBucketInfo);

AuditLogger auditLogger = ozoneManager.getAuditLogger();
OzoneManagerProtocolProtos.UserInfo userInfo = getOmRequest().getUserInfo();

Expand Down Expand Up @@ -335,4 +342,21 @@ public boolean checkQuotaBytesValid(OMMetadataManager metadataManager,

}

private void addLayoutVersionToBucket(OzoneManager ozoneManager,
OmBucketInfo omBucketInfo) {
Map<String, String> metadata = omBucketInfo.getMetadata();
if (metadata == null) {
metadata = new HashMap<>();
}
OzoneConfiguration configuration = ozoneManager.getConfiguration();
// TODO: Many unit test cases has null config and done a simple null
// check now. It can be done later, to avoid massive test code changes.
if (configuration != null) {
String layOutVersion = configuration
.get(OMConfigKeys.OZONE_OM_LAYOUT_VERSION,
OMConfigKeys.OZONE_OM_LAYOUT_VERSION_DEFAULT);
metadata.put(OMConfigKeys.OZONE_OM_LAYOUT_VERSION, layOutVersion);
omBucketInfo.setMetadata(metadata);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
Expand Down Expand Up @@ -696,4 +697,91 @@ public static String getAbsolutePath(String prefixName, String fileName) {
}
return prefixName.concat(OzoneConsts.OZONE_URI_DELIMITER).concat(fileName);
}

/**
* Build DirectoryInfo from OmKeyInfo.
*
* @param keyInfo omKeyInfo
* @return omDirectoryInfo object
*/
public static OmDirectoryInfo getDirectoryInfo(OmKeyInfo keyInfo){
OmDirectoryInfo.Builder builder = new OmDirectoryInfo.Builder();
builder.setParentObjectID(keyInfo.getParentObjectID());
builder.setAcls(keyInfo.getAcls());
builder.addAllMetadata(keyInfo.getMetadata());
builder.setCreationTime(keyInfo.getCreationTime());
builder.setModificationTime(keyInfo.getModificationTime());
builder.setObjectID(keyInfo.getObjectID());
builder.setUpdateID(keyInfo.getUpdateID());
builder.setName(OzoneFSUtils.getFileName(keyInfo.getKeyName()));
return builder.build();
}

/**
* Verify that the given toKey directory is a sub directory of fromKey
* directory.
* <p>
* For example, special case of renaming a directory to its own
* sub-directory is not allowed.
*
* @param fromKeyName source path
* @param toKeyName destination path
* @throws OMException if the dest dir is a sub-dir of source dir.
*/
public static void verifyToDirIsASubDirOfFromDirectory(String fromKeyName,
String toKeyName, boolean isDir) throws OMException {
if (!isDir) {
return;
}
Path dstParent = Paths.get(toKeyName).getParent();
while (dstParent != null) {
if (Paths.get(fromKeyName).equals(dstParent)) {
throw new OMException("Cannot rename a directory to its own " +
"subdirectory", OMException.ResultCodes.KEY_RENAME_ERROR);
// TODO: Existing rename throws java.lang.IllegalArgumentException.
// Should we throw same exception ?
}
dstParent = dstParent.getParent();
}
}

/**
* Verify parent exists for the destination path and return destination
* path parent Id.
* <p>
* Check whether dst parent dir exists or not. If the parent exists, then the
* source can be renamed to dst path.
*
* @param volumeName volume name
* @param bucketName bucket name
* @param toKeyName destination path
* @param fromKeyName source path
* @param metaMgr metadata manager
* @throws IOException if the destination parent dir doesn't exists.
*/
public static long getToKeyNameParentId(String volumeName,
String bucketName, String toKeyName, String fromKeyName,
OMMetadataManager metaMgr) throws IOException {

int totalDirsCount = OzoneFSUtils.getFileCount(toKeyName);
// skip parent is root '/'
if (totalDirsCount <= 1) {
String bucketKey = metaMgr.getBucketKey(volumeName, bucketName);
OmBucketInfo omBucketInfo =
metaMgr.getBucketTable().get(bucketKey);
return omBucketInfo.getObjectID();
}

String toKeyParentDir = OzoneFSUtils.getParentDir(toKeyName);

OzoneFileStatus toKeyParentDirStatus = getOMKeyInfoIfExists(metaMgr,
volumeName, bucketName, toKeyParentDir, 0);
// check if the immediate parent exists
if (toKeyParentDirStatus == null || toKeyParentDirStatus.isFile()) {
throw new IOException(String.format(
"Failed to rename %s to %s, %s is a file", fromKeyName, toKeyName,
toKeyParentDir));
}
return toKeyParentDirStatus.getKeyInfo().getObjectID();
}
}
Loading