/* * 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.transaction.lock; import io.hops.leader_election.node.ActiveNode; import org.apache.hadoop.hdfs.server.namenode.INode; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.List; final class RenameINodeLock extends INodeLock { private static final Comparator PATH_COMPARTOR = new Comparator<String>() { @Override public int compare(String o1, String o2) { String[] o1Path = INode.getPathNames(o1); String[] o2Path = INode.getPathNames(o2); if (o1Path.length > o2Path.length) { return 1; } else if (o1Path.length == o2Path.length) { return o1.compareTo(o2); } return -1; } }; private final boolean legacyRename; public RenameINodeLock(boolean skipReadingQuotaAttr,TransactionLockTypes.INodeLockType lockType, TransactionLockTypes.INodeResolveType resolveType, boolean ignoreLocalSubtreeLocks, long namenodeId, Collection<ActiveNode> activeNamenodes, String src, String dst, boolean legacyRename) { super(lockType, resolveType, false, ignoreLocalSubtreeLocks, skipReadingQuotaAttr, namenodeId, activeNamenodes, src, dst); this.legacyRename = legacyRename; } public RenameINodeLock(TransactionLockTypes.INodeLockType lockType, TransactionLockTypes.INodeResolveType resolveType, boolean ignoreLocalSubtreeLocks, long namenodeId, Collection<ActiveNode> activeNamenodes, String src, String dst, boolean legacyRename) { super(lockType, resolveType, false, ignoreLocalSubtreeLocks, false, namenodeId, activeNamenodes, src, dst); this.legacyRename = legacyRename; } public RenameINodeLock(boolean skipReadingQuotaAttr, TransactionLockTypes.INodeLockType lockType, TransactionLockTypes.INodeResolveType resolveType, Collection<ActiveNode> activeNamenodes, String src, String dst, boolean legacyRename) { super(skipReadingQuotaAttr, lockType, resolveType, false, activeNamenodes, src, dst); this.legacyRename = legacyRename; } public RenameINodeLock(TransactionLockTypes.INodeLockType lockType, TransactionLockTypes.INodeResolveType resolveType, Collection<ActiveNode> activeNamenodes, String src, String dst, boolean legacyRename) { super(false, lockType, resolveType, false, activeNamenodes, src, dst); this.legacyRename = legacyRename; } public RenameINodeLock(TransactionLockTypes.INodeLockType lockType, TransactionLockTypes.INodeResolveType resolveType, boolean ignoreLocalSubtreeLocks, long namenodeId, List<ActiveNode> activeNamenodes, String src, String dst) { this(lockType, resolveType, ignoreLocalSubtreeLocks, namenodeId, activeNamenodes, src, dst, false); } public RenameINodeLock(TransactionLockTypes.INodeLockType lockType, TransactionLockTypes.INodeResolveType resolveType, Collection<ActiveNode> activeNamenodes, String src, String dst) { this(lockType, resolveType, activeNamenodes, src, dst, false); } @Override protected void acquire(TransactionLocks locks) throws IOException { //consider src = /a/b/c and dst = /d //during the acquire lock of src write locks will be acquired on parent of c and c //during the acquire lock of dst write lock on the root will be acquired but the snapshot //layer will not let the request go to the db as it has already cached the root inode //one simple solution is that to acquire lock on the short path first //setPartitioningKey(PathMemcache.getInstance().getPartitionKey(locks.getInodeParam()[0])); String src = paths[0]; String dst = paths[1]; Arrays.sort(paths, PATH_COMPARTOR); acquireINodeLocks(); if (legacyRename) // In deprecated rename, it allows to move a dir to an existing destination. { List<INode> dstINodes = getPathINodes(dst); String[] dstComponents = INode.getPathNames(dst); String[] srcComponents = INode.getPathNames(src); INode lastComp = dstINodes.get(dstINodes.size() - 1); if (dstINodes.size() == dstComponents.length && lastComp.isDirectory()) { //the dst exist and is a directory. int parttitionId = INode.calculatePartitionId(lastComp.getId(), srcComponents[srcComponents.length - 1], (short)(lastComp.myDepth()+1)); find(srcComponents[srcComponents.length - 1], lastComp.getId(), parttitionId); } } if(!skipReadingQuotaAttr) { acquireINodeAttributes(); } } }