/*
* Copyright (C) 2015 hops.io.
*
* Licensed 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 io.hops.common;
import io.hops.exception.StorageException;
import io.hops.exception.TransactionContextException;
import io.hops.metadata.HdfsStorageFactory;
import io.hops.metadata.adaptor.INodeDALAdaptor;
import io.hops.metadata.hdfs.dal.BlockLookUpDataAccess;
import io.hops.metadata.hdfs.dal.INodeDataAccess;
import io.hops.metadata.hdfs.dal.LeaseDataAccess;
import io.hops.metadata.hdfs.dal.LeasePathDataAccess;
import io.hops.metadata.hdfs.entity.BlockLookUp;
import io.hops.metadata.hdfs.entity.INodeIdentifier;
import io.hops.metadata.hdfs.entity.LeasePath;
import io.hops.transaction.EntityManager;
import io.hops.transaction.handler.HDFSOperationType;
import io.hops.transaction.handler.LightWeightRequestHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DFSUtil;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.protocol.UnresolvedPathException;
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
import org.apache.hadoop.hdfs.server.namenode.Lease;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class INodeUtil {
private final static Log LOG = LogFactory.getLog(INodeUtil.class);
public static String constructPath(byte[][] components, int start, int end) {
StringBuilder buf = new StringBuilder();
for (int i = start; i < end; i++) {
buf.append(DFSUtil.bytes2String(components[i]));
if (i < end - 1) {
buf.append(Path.SEPARATOR);
}
}
return buf.toString();
}
public static INode getNode(byte[] name, int parentId, int partitionId, boolean transactional)
throws StorageException, TransactionContextException {
String nameString = DFSUtil.bytes2String(name);
if (transactional) {
return EntityManager
.find(INode.Finder.ByNameParentIdAndPartitionId, nameString, parentId, partitionId);
} else {
return findINodeWithNoTransaction(nameString, parentId, partitionId);
}
}
private static INode findINodeWithNoTransaction(String name, int parentId, int partitionId)
throws StorageException {
LOG.debug(String
.format("Read inode with no transaction by parent_id=%d, name=%s, partitionId=%s",
parentId, name, parentId));
INodeDataAccess<INode> da = (INodeDataAccess) HdfsStorageFactory
.getDataAccess(INodeDataAccess.class);
return da.findInodeByNameParentIdAndPartitionIdPK(name, parentId, partitionId);
}
public static void resolvePathWithNoTransaction(String path,
boolean resolveLink, LinkedList<INode> preTxResolvedINodes,
boolean[] isPathFullyResolved)
throws UnresolvedPathException, StorageException,
TransactionContextException {
preTxResolvedINodes.clear();
isPathFullyResolved[0] = false;
byte[][] components = INode.getPathComponents(path);
INode curNode = getRoot();
preTxResolvedINodes.add(curNode);
if (components.length == 1) {
return;
}
INodeResolver resolver =
new INodeResolver(components, curNode, resolveLink, false);
while (resolver.hasNext()) {
curNode = resolver.next();
if (curNode != null) {
preTxResolvedINodes.add(curNode);
}
}
isPathFullyResolved[0] = preTxResolvedINodes.size() == components.length;
}
public static void findPathINodesById(int inodeId,
LinkedList<INode> preTxResolvedINodes, boolean[] isPreTxPathFullyResolved)
throws StorageException {
if (inodeId != INode.NON_EXISTING_ID) {
INode inode = indexINodeScanById(inodeId);
if (inode == null) {
isPreTxPathFullyResolved[0] = false;
return;
}
preTxResolvedINodes.add(inode);
readFromLeafToRoot(inode, preTxResolvedINodes);
}
isPreTxPathFullyResolved[0] = true;
//reverse the list
int firstCounter = 0;
int lastCounter = preTxResolvedINodes.size() - 1 - firstCounter;
INode firstNode = null;
INode lastNode = null;
while (firstCounter < (preTxResolvedINodes.size() / 2)) {
firstNode = preTxResolvedINodes.get(firstCounter);
lastNode = preTxResolvedINodes.get(lastCounter);
preTxResolvedINodes.remove(firstCounter);
preTxResolvedINodes.add(firstCounter, lastNode);
preTxResolvedINodes.remove(lastCounter);
preTxResolvedINodes.add(lastCounter, firstNode);
firstCounter++;
lastCounter = preTxResolvedINodes.size() - 1 - firstCounter;
}
}
public static Set<String> findPathsByLeaseHolder(String holder)
throws StorageException {
HashSet<String> paths = new HashSet<String>();
LeaseDataAccess<Lease> lda = (LeaseDataAccess) HdfsStorageFactory
.getDataAccess(LeaseDataAccess.class);
Lease rcLease = lda.findByPKey(holder,Lease.getHolderId(holder));
if (rcLease == null) {
return paths;
}
LeasePathDataAccess pda = (LeasePathDataAccess) HdfsStorageFactory
.getDataAccess(LeasePathDataAccess.class);
Collection<LeasePath> rclPaths = pda.findByHolderId(rcLease.getHolderID());
for (LeasePath lp : rclPaths) {
paths.add(lp.getPath());
}
return paths;
}
private static INode getRoot()
throws StorageException, TransactionContextException {
return getNode(INodeDirectory.ROOT_NAME.getBytes(),
INodeDirectory.ROOT_PARENT_ID, INodeDirectory.getRootDirPartitionKey(), false);
}
public static INode indexINodeScanById(int id) throws StorageException {
LOG.debug(String.format("Read inode with no transaction by id=%d", id));
INodeDataAccess<INode> da = (INodeDataAccess) HdfsStorageFactory
.getDataAccess(INodeDataAccess.class);
return da.findInodeByIdFTIS(id);
}
//puts the indoes in the list in reverse order
private static void readFromLeafToRoot(INode inode, LinkedList<INode> list)
throws StorageException {
INode temp = inode;
while (temp != null &&
temp.getParentId() != INodeDirectory.ROOT_PARENT_ID) {
temp = indexINodeScanById(
temp.getParentId()); // all upper components are dirs
if (temp != null) {
list.add(temp);
}
}
}
public static INodeIdentifier resolveINodeFromBlockID(final long bid)
throws StorageException {
INodeIdentifier inodeIdentifier;
LightWeightRequestHandler handler = new LightWeightRequestHandler(
HDFSOperationType.RESOLVE_INODE_FROM_BLOCKID) {
@Override
public Object performTask() throws IOException {
BlockLookUpDataAccess<BlockLookUp> da =
(BlockLookUpDataAccess) HdfsStorageFactory
.getDataAccess(BlockLookUpDataAccess.class);
BlockLookUp blu = da.findByBlockId(bid);
if (blu == null) {
return null;
}
INodeIdentifier inodeIdent = new INodeIdentifier(blu.getInodeId());
INodeDALAdaptor ida = (INodeDALAdaptor) HdfsStorageFactory
.getDataAccess(INodeDataAccess.class);
INode inode = ida.findInodeByIdFTIS(blu.getInodeId());
if (inode != null) {
inodeIdent.setName(inode.getLocalName());
inodeIdent.setPid(inode.getParentId());
inodeIdent.setPartitionId(inode.getPartitionId());
}
return inodeIdent;
}
};
try {
inodeIdentifier = (INodeIdentifier) handler.handle();
} catch (IOException ex) {
throw new StorageException(ex.getMessage());
}
return inodeIdentifier;
}
public static INodeIdentifier resolveINodeFromBlock(final Block b)
throws StorageException {
if (b instanceof BlockInfo || b instanceof BlockInfoUnderConstruction) {
INodeIdentifier inodeIden =
new INodeIdentifier(((BlockInfo) b).getInodeId());
INodeDALAdaptor ida = (INodeDALAdaptor) HdfsStorageFactory
.getDataAccess(INodeDataAccess.class);
INode inode = ida.findInodeByIdFTIS(((BlockInfo) b).getInodeId());
if (inode != null) {
inodeIden.setName(inode.getLocalName());
inodeIden.setPid(inode.getParentId());
inodeIden.setPartitionId(inode.getPartitionId());
}
return inodeIden;
} else {
return resolveINodeFromBlockID(b.getBlockId());
}
}
public static int[] resolveINodesFromBlockIds(final long[] blockIds)
throws StorageException {
LightWeightRequestHandler handler =
new LightWeightRequestHandler(HDFSOperationType.GET_INODEIDS_FOR_BLKS) {
@Override
public Object performTask() throws IOException {
BlockLookUpDataAccess<BlockLookUp> da =
(BlockLookUpDataAccess) HdfsStorageFactory
.getDataAccess(BlockLookUpDataAccess.class);
return da.findINodeIdsByBlockIds(blockIds);
}
};
try {
return (int[]) handler.handle();
} catch (IOException ex) {
throw new StorageException(ex.getMessage());
}
}
public static INodeIdentifier resolveINodeFromId(final int id)
throws StorageException {
INodeIdentifier inodeIdentifier;
LightWeightRequestHandler handler =
new LightWeightRequestHandler(HDFSOperationType.RESOLVE_INODE_FROM_ID) {
@Override
public Object performTask() throws StorageException, IOException {
INodeDALAdaptor ida = (INodeDALAdaptor) HdfsStorageFactory
.getDataAccess(INodeDataAccess.class);
INode inode = ida.findInodeByIdFTIS(id);
INodeIdentifier inodeIdent = new INodeIdentifier(id);
if (inode != null) {
inodeIdent.setName(inode.getLocalName());
inodeIdent.setPid(inode.getParentId());
inodeIdent.setPartitionId(inode.getPartitionId());
}
return inodeIdent;
}
};
try {
inodeIdentifier = (INodeIdentifier) handler.handle();
} catch (IOException ex) {
throw new StorageException(ex.getMessage());
}
return inodeIdentifier;
}
public static String constructPath(List<INode> pathINodes) {
StringBuilder builder = new StringBuilder();
for (INode node : pathINodes) {
if (node.isDirectory()) {
builder.append(node.getLocalName() + "/");
} else {
builder.append(node.getLocalName());
}
}
return builder.toString();
}
}