blob: 906a1e1e5ab12a555fa784e08525896ac63acee9 [file] [log] [blame]
/*
* 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.ozone.recon.api.handlers;
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.TableIterator;
import org.apache.hadoop.ozone.OmUtils;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.recon.ReconConstants;
import org.apache.hadoop.ozone.recon.api.types.NamespaceSummaryResponse;
import org.apache.hadoop.ozone.recon.api.types.DUResponse;
import org.apache.hadoop.ozone.recon.api.types.QuotaUsageResponse;
import org.apache.hadoop.ozone.recon.api.types.FileSizeDistributionResponse;
import org.apache.hadoop.ozone.recon.api.types.EntityType;
import org.apache.hadoop.ozone.recon.api.types.NSSummary;
import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
import org.apache.hadoop.ozone.recon.spi.ReconNamespaceSummaryManager;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
/**
* Class for handling all entity types.
*/
public abstract class EntityHandler {
private final ReconNamespaceSummaryManager reconNamespaceSummaryManager;
private final ReconOMMetadataManager omMetadataManager;
private final BucketHandler bucketHandler;
private final OzoneStorageContainerManager reconSCM;
private final String normalizedPath;
private final String[] names;
public EntityHandler(
ReconNamespaceSummaryManager reconNamespaceSummaryManager,
ReconOMMetadataManager omMetadataManager,
OzoneStorageContainerManager reconSCM,
BucketHandler bucketHandler, String path) {
this.reconNamespaceSummaryManager = reconNamespaceSummaryManager;
this.omMetadataManager = omMetadataManager;
this.reconSCM = reconSCM;
this.bucketHandler = bucketHandler;
normalizedPath = normalizePath(path);
names = parseRequestPath(normalizedPath);
}
public abstract NamespaceSummaryResponse getSummaryResponse()
throws IOException;
public abstract DUResponse getDuResponse(
boolean listFile, boolean withReplica)
throws IOException;
public abstract QuotaUsageResponse getQuotaResponse()
throws IOException;
public abstract FileSizeDistributionResponse getDistResponse()
throws IOException;
public ReconOMMetadataManager getOmMetadataManager() {
return omMetadataManager;
}
public OzoneStorageContainerManager getReconSCM() {
return reconSCM;
}
public ReconNamespaceSummaryManager getReconNamespaceSummaryManager() {
return reconNamespaceSummaryManager;
}
public BucketHandler getBucketHandler() {
return bucketHandler;
}
public String getNormalizedPath() {
return normalizedPath;
}
public String[] getNames() {
return names.clone();
}
/**
* Return the entity handler of client's request, check path existence.
* If path doesn't exist, return UnknownEntityHandler
* @param reconNamespaceSummaryManager ReconNamespaceSummaryManager
* @param omMetadataManager ReconOMMetadataManager
* @param reconSCM OzoneStorageContainerManager
* @param path the original path request used to identify root level
* @return the entity handler of client's request
*/
public static EntityHandler getEntityHandler(
ReconNamespaceSummaryManager reconNamespaceSummaryManager,
ReconOMMetadataManager omMetadataManager,
OzoneStorageContainerManager reconSCM,
String path) throws IOException {
BucketHandler bucketHandler;
String normalizedPath = normalizePath(path);
String[] names = parseRequestPath(normalizedPath);
if (path.equals(OM_KEY_PREFIX)) {
return EntityType.ROOT.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, null, path);
}
if (names.length == 0) {
return EntityType.UNKNOWN.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, null, path);
} else if (names.length == 1) { // volume level check
String volName = names[0];
if (!volumeExists(omMetadataManager, volName)) {
return EntityType.UNKNOWN.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, null, path);
}
return EntityType.VOLUME.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, null, path);
} else if (names.length == 2) { // bucket level check
String volName = names[0];
String bucketName = names[1];
bucketHandler = BucketHandler.getBucketHandler(
reconNamespaceSummaryManager,
omMetadataManager, reconSCM,
volName, bucketName);
if (bucketHandler == null
|| !bucketHandler.bucketExists(volName, bucketName)) {
return EntityType.UNKNOWN.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, null, path);
}
return EntityType.BUCKET.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, bucketHandler, path);
} else { // length > 3. check dir or key existence
String volName = names[0];
String bucketName = names[1];
String keyName = BucketHandler.getKeyName(names);
bucketHandler = BucketHandler.getBucketHandler(
reconNamespaceSummaryManager,
omMetadataManager, reconSCM,
volName, bucketName);
// check if either volume or bucket doesn't exist
if (bucketHandler == null
|| !volumeExists(omMetadataManager, volName)
|| !bucketHandler.bucketExists(volName, bucketName)) {
return EntityType.UNKNOWN.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, null, path);
}
return bucketHandler.determineKeyPath(keyName)
.create(reconNamespaceSummaryManager,
omMetadataManager, reconSCM, bucketHandler, path);
}
}
/**
* Given an object ID, return the file size distribution.
* @param objectId the object's ID
* @return int array indicating file size distribution
* @throws IOException ioEx
*/
protected int[] getTotalFileSizeDist(long objectId) throws IOException {
NSSummary nsSummary = reconNamespaceSummaryManager.getNSSummary(objectId);
if (nsSummary == null) {
return new int[ReconConstants.NUM_OF_BINS];
}
int[] res = nsSummary.getFileSizeBucket();
for (long childId: nsSummary.getChildDir()) {
int[] subDirFileSizeDist = getTotalFileSizeDist(childId);
for (int i = 0; i < ReconConstants.NUM_OF_BINS; ++i) {
res[i] += subDirFileSizeDist[i];
}
}
return res;
}
protected int getTotalDirCount(long objectId) throws IOException {
NSSummary nsSummary =
getReconNamespaceSummaryManager().getNSSummary(objectId);
if (nsSummary == null) {
return 0;
}
Set<Long> subdirs = nsSummary.getChildDir();
int totalCnt = subdirs.size();
for (long subdir : subdirs) {
totalCnt += getTotalDirCount(subdir);
}
return totalCnt;
}
/**
* Return all volumes in the file system.
* This method can be optimized by using username as a filter.
* @return a list of volume names under the system
*/
List<OmVolumeArgs> listVolumes() throws IOException {
List<OmVolumeArgs> result = new ArrayList<>();
Table<String, OmVolumeArgs> volumeTable =
omMetadataManager.getVolumeTable();
TableIterator<String, ? extends Table.KeyValue<String, OmVolumeArgs>>
iterator = volumeTable.iterator();
while (iterator.hasNext()) {
Table.KeyValue<String, OmVolumeArgs> kv = iterator.next();
OmVolumeArgs omVolumeArgs = kv.getValue();
if (omVolumeArgs != null) {
result.add(omVolumeArgs);
}
}
return result;
}
/**
* List all buckets under a volume, if volume name is null, return all buckets
* under the system.
* @param volumeName volume name
* @return a list of buckets
* @throws IOException IOE
*/
List<OmBucketInfo> listBucketsUnderVolume(final String volumeName)
throws IOException {
List<OmBucketInfo> result = new ArrayList<>();
// if volume name is null, seek prefix is an empty string
String seekPrefix = "";
Table<String, OmBucketInfo> bucketTable =
omMetadataManager.getBucketTable();
TableIterator<String, ? extends Table.KeyValue<String, OmBucketInfo>>
iterator = bucketTable.iterator();
if (volumeName != null) {
if (!volumeExists(omMetadataManager, volumeName)) {
return result;
}
seekPrefix = omMetadataManager.getVolumeKey(volumeName + OM_KEY_PREFIX);
}
while (iterator.hasNext()) {
Table.KeyValue<String, OmBucketInfo> kv = iterator.next();
String key = kv.getKey();
OmBucketInfo omBucketInfo = kv.getValue();
if (omBucketInfo != null) {
// We should return only the keys, whose keys match with the seek prefix
if (key.startsWith(seekPrefix)) {
result.add(omBucketInfo);
}
}
}
return result;
}
static boolean volumeExists(ReconOMMetadataManager omMetadataManager,
String volName) throws IOException {
String volDBKey = omMetadataManager.getVolumeKey(volName);
return omMetadataManager.getVolumeTable().getSkipCache(volDBKey) != null;
}
/**
* Given an object ID, return total count of keys under this object.
* @param objectId the object's ID
* @return count of keys
* @throws IOException ioEx
*/
protected long getTotalKeyCount(long objectId) throws IOException {
NSSummary nsSummary = reconNamespaceSummaryManager.getNSSummary(objectId);
if (nsSummary == null) {
return 0L;
}
long totalCnt = nsSummary.getNumOfFiles();
for (long childId: nsSummary.getChildDir()) {
totalCnt += getTotalKeyCount(childId);
}
return totalCnt;
}
/**
* Given an object ID, return total data size (no replication)
* under this object.
* @param objectId the object's ID
* @return total used data size in bytes
* @throws IOException ioEx
*/
protected long getTotalSize(long objectId) throws IOException {
NSSummary nsSummary = reconNamespaceSummaryManager.getNSSummary(objectId);
if (nsSummary == null) {
return 0L;
}
long totalSize = nsSummary.getSizeOfFiles();
for (long childId: nsSummary.getChildDir()) {
totalSize += getTotalSize(childId);
}
return totalSize;
}
public static String[] parseRequestPath(String path) {
if (path.startsWith(OM_KEY_PREFIX)) {
path = path.substring(1);
}
String[] names = path.split(OM_KEY_PREFIX);
return names;
}
private static String normalizePath(String path) {
return OM_KEY_PREFIX + OmUtils.normalizeKey(path, false);
}
}