Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -55,6 +55,7 @@
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.ScmUtils;
import org.apache.hadoop.hdds.scm.ha.SCMNodeDetails;
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
import org.apache.hadoop.hdds.scm.server.SCMDatanodeHeartbeatDispatcher;
import org.apache.hadoop.hdds.utils.HddsServerUtil;
import org.apache.hadoop.hdds.utils.db.Table;
Expand All @@ -78,8 +79,12 @@

import org.apache.hadoop.ozone.OmUtils;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.recon.api.handlers.EntityHandler;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.recon.api.handlers.BucketHandler;
import org.apache.hadoop.ozone.recon.api.ServiceNotReadyException;
import org.apache.hadoop.ozone.recon.api.types.NSSummary;
import org.apache.hadoop.ozone.recon.api.types.DUResponse;
Expand Down Expand Up @@ -392,6 +397,100 @@ public static StringBuilder constructFullPathPrefix(long initialParentId, String
return fullPath;
}

/**
* Converts a key prefix into an object path for FSO buckets, using IDs.
*
* This method transforms a user-provided path (e.g., "volume/bucket/dir1") into
* a database-friendly format ("/volumeID/bucketID/ParentId/") by replacing names
* with their corresponding IDs. It simplifies database queries for FSO bucket operations.
* <pre>
* {@code
* Examples:
* - Input: "volume/bucket/key" -> Output: "/volumeID/bucketID/parentDirID/key"
* - Input: "volume/bucket/dir1" -> Output: "/volumeID/bucketID/dir1ID/"
* - Input: "volume/bucket/dir1/key1" -> Output: "/volumeID/bucketID/dir1ID/key1"
* - Input: "volume/bucket/dir1/dir2" -> Output: "/volumeID/bucketID/dir2ID/"
* }
* </pre>
* @param prevKeyPrefix The path to be converted.
* @return The object path as "/volumeID/bucketID/ParentId/" or an empty string if an error occurs.
* @throws IOException If database access fails.
* @throws IllegalArgumentException If the provided path is invalid or cannot be converted.
*/
public static String convertToObjectPathForOpenKeySearch(String prevKeyPrefix,
ReconOMMetadataManager omMetadataManager,
ReconNamespaceSummaryManager reconNamespaceSummaryManager,
OzoneStorageContainerManager reconSCM)
throws IOException {
try {
String[] names = EntityHandler.parseRequestPath(EntityHandler.normalizePath(
prevKeyPrefix, BucketLayout.FILE_SYSTEM_OPTIMIZED));
Table<String, OmKeyInfo> openFileTable = omMetadataManager.getOpenKeyTable(
BucketLayout.FILE_SYSTEM_OPTIMIZED);

// Root-Level: Return the original path
if (names.length == 0 || names[0].isEmpty()) {
return prevKeyPrefix;
}

// Volume-Level: Fetch the volumeID
String volumeName = names[0];
validateNames(volumeName);
String volumeKey = omMetadataManager.getVolumeKey(volumeName);
long volumeId = omMetadataManager.getVolumeTable().getSkipCache(volumeKey).getObjectID();
if (names.length == 1) {
return constructObjectPathWithPrefix(volumeId);
}

// Bucket-Level: Fetch the bucketID
String bucketName = names[1];
validateNames(bucketName);
String bucketKey = omMetadataManager.getBucketKey(volumeName, bucketName);
OmBucketInfo bucketInfo = omMetadataManager.getBucketTable().getSkipCache(bucketKey);
long bucketId = bucketInfo.getObjectID();
if (names.length == 2 || bucketInfo.getBucketLayout() != BucketLayout.FILE_SYSTEM_OPTIMIZED) {
return constructObjectPathWithPrefix(volumeId, bucketId);
}

// Directory or Key-Level: Check both key and directory
BucketHandler handler =
BucketHandler.getBucketHandler(reconNamespaceSummaryManager, omMetadataManager, reconSCM, bucketInfo);

if (names.length >= 3) {
String lastEntiry = names[names.length - 1];

// Check if the directory exists
OmDirectoryInfo dirInfo = handler.getDirInfo(names);
if (dirInfo != null && dirInfo.getName().equals(lastEntiry)) {
return constructObjectPathWithPrefix(volumeId, bucketId, dirInfo.getObjectID()) + OM_KEY_PREFIX;
}

// Check if the key exists
long dirID = handler.getDirObjectId(names, names.length);
String keyKey = constructObjectPathWithPrefix(volumeId, bucketId, dirID) +
OM_KEY_PREFIX + lastEntiry;
OmKeyInfo keyInfo = openFileTable.getSkipCache(keyKey);
if (keyInfo != null && keyInfo.getFileName().equals(lastEntiry)) {
return constructObjectPathWithPrefix(volumeId, bucketId,
keyInfo.getParentObjectID()) + OM_KEY_PREFIX + lastEntiry;
}

return prevKeyPrefix;
}
} catch (IllegalArgumentException e) {
log.error(
"IllegalArgumentException encountered while converting key prefix to object path: {}",
prevKeyPrefix, e);
throw e;
} catch (RuntimeException e) {
log.error(
"RuntimeException encountered while converting key prefix to object path: {}",
prevKeyPrefix, e);
return prevKeyPrefix;
}
return prevKeyPrefix;
}

private static void triggerRebuild(ReconNamespaceSummaryManager reconNamespaceSummaryManager,
ReconOMMetadataManager omMetadataManager) {
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
Expand Down
Loading
Loading