Java tutorial
/* * 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 com.google.common.collect.Iterables; import io.hops.exception.StorageException; import io.hops.exception.TransactionContextException; import io.hops.memcache.PathMemcache; import io.hops.metadata.hdfs.dal.BlockInfoDataAccess; import io.hops.metadata.hdfs.entity.INodeCandidatePrimaryKey; import io.hops.transaction.EntityManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo; import org.apache.hadoop.hdfs.server.namenode.INode; import org.apache.hadoop.hdfs.server.namenode.INodeAttributes; import org.apache.hadoop.hdfs.server.namenode.INodeDirectory; import org.apache.hadoop.hdfs.server.namenode.INodeDirectoryWithQuota; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public abstract class BaseINodeLock extends Lock { protected final static Log LOG = LogFactory.getLog(BaseINodeLock.class); private final Map<INode, TransactionLockTypes.INodeLockType> allLockedInodesInTx; private final ResolvedINodesMap resolvedINodesMap; protected static TransactionLockTypes.INodeLockType DEFAULT_INODE_LOCK_TYPE = TransactionLockTypes.INodeLockType.READ_COMMITTED; public static void setDefaultLockType(TransactionLockTypes.INodeLockType defaultLockType) { DEFAULT_INODE_LOCK_TYPE = defaultLockType; } protected BaseINodeLock() { this.allLockedInodesInTx = new HashMap<INode, TransactionLockTypes.INodeLockType>(); this.resolvedINodesMap = new ResolvedINodesMap(); } private class ResolvedINodesMap { private final Map<String, PathRelatedINodes> pathToPathINodes = new HashMap<String, PathRelatedINodes>(); private final Collection<INode> individualInodes = new ArrayList<INode>(); private class PathRelatedINodes { private List<INode> pathINodes; private List<INode> childINodes; } private PathRelatedINodes getWithLazyInit(String path) { if (!pathToPathINodes.containsKey(path)) { PathRelatedINodes pathRelatedINodes = new PathRelatedINodes(); pathToPathINodes.put(path, pathRelatedINodes); return pathRelatedINodes; } return pathToPathINodes.get(path); } private void putPathINodes(String path, List<INode> iNodes) { PathRelatedINodes pathRelatedINodes = getWithLazyInit(path); pathRelatedINodes.pathINodes = iNodes; } private void putChildINodes(String path, List<INode> iNodes) { PathRelatedINodes pathRelatedINodes = getWithLazyInit(path); pathRelatedINodes.childINodes = iNodes; } private void putIndividualINode(INode iNode) { individualInodes.add(iNode); } private List<INode> getPathINodes(String path) { return pathToPathINodes.get(path).pathINodes; } private List<INode> getChildINodes(String path) { return pathToPathINodes.get(path).childINodes; } public Iterable<INode> getAll() { Iterable iterable = null; for (PathRelatedINodes pathRelatedINodes : pathToPathINodes.values()) { List<INode> pathINodes = pathRelatedINodes.pathINodes == null ? Collections.EMPTY_LIST : pathRelatedINodes.pathINodes; List<INode> childINodes = pathRelatedINodes.childINodes == null ? Collections.EMPTY_LIST : pathRelatedINodes.childINodes; if (iterable == null) { iterable = Iterables.concat(pathINodes, childINodes); } else { iterable = Iterables.concat(iterable, pathINodes, childINodes); } } if (iterable == null) { iterable = Collections.EMPTY_LIST; } return Iterables.concat(iterable, individualInodes); } } Iterable<INode> getAllResolvedINodes() { return resolvedINodesMap.getAll(); } void addPathINodes(String path, List<INode> iNodes) { resolvedINodesMap.putPathINodes(path, iNodes); PathMemcache.getInstance().set(path, iNodes); } void addChildINodes(String path, List<INode> iNodes) { resolvedINodesMap.putChildINodes(path, iNodes); } void addIndividualINode(INode iNode) { resolvedINodesMap.putIndividualINode(iNode); } List<INode> getPathINodes(String path) { return resolvedINodesMap.getPathINodes(path); } INode getTargetINode(String path) { List<INode> list = resolvedINodesMap.getPathINodes(path); return list.get(list.size() - 1); } List<INode> getChildINodes(String path) { return resolvedINodesMap.getChildINodes(path); } public TransactionLockTypes.INodeLockType getLockedINodeLockType(INode inode) { return allLockedInodesInTx.get(inode); } protected INode find(TransactionLockTypes.INodeLockType lock, String name, int parentId, int possibleINodeId) throws StorageException, TransactionContextException { setINodeLockType(lock); INode inode = EntityManager.find(INode.Finder.ByNameAndParentId, name, parentId, possibleINodeId); addLockedINodes(inode, lock); return inode; } protected INode find(TransactionLockTypes.INodeLockType lock, String name, int parentId) throws StorageException, TransactionContextException { setINodeLockType(lock); INode inode = EntityManager.find(INode.Finder.ByNameAndParentId, name, parentId); addLockedINodes(inode, lock); return inode; } protected INode find(TransactionLockTypes.INodeLockType lock, int id) throws StorageException, TransactionContextException { setINodeLockType(lock); INode inode = EntityManager.find(INode.Finder.ByINodeId, id); addLockedINodes(inode, lock); return inode; } private List<INode> findBatch(TransactionLockTypes.INodeLockType lock, String[] names, int[] parentIds) throws TransactionContextException, StorageException { setINodeLockType(lock); List<INode> inodes = (List<INode>) EntityManager.findList(INode.Finder.ByNamesAndParentIds, names, parentIds); if (inodes != null) { for (INode inode : inodes) { addLockedINodes(inode, lock); } } return inodes; } protected void addLockedINodes(INode inode, TransactionLockTypes.INodeLockType lock) { if (inode == null) { return; } TransactionLockTypes.INodeLockType oldLock = allLockedInodesInTx.get(inode); if (oldLock == null || oldLock.compareTo(lock) < 0) { allLockedInodesInTx.put(inode, lock); } } protected void setINodeLockType(TransactionLockTypes.INodeLockType lock) throws StorageException { switch (lock) { case WRITE: case WRITE_ON_TARGET_AND_PARENT: EntityManager.writeLock(); break; case READ: EntityManager.readLock(); break; case READ_COMMITTED: EntityManager.readCommited(); break; } } protected void acquireINodeAttributes() throws StorageException, TransactionContextException { List<INodeCandidatePrimaryKey> pks = new ArrayList<INodeCandidatePrimaryKey>(); for (INode inode : getAllResolvedINodes()) { if (inode instanceof INodeDirectoryWithQuota) { INodeCandidatePrimaryKey pk = new INodeCandidatePrimaryKey(inode.getId()); pks.add(pk); } } acquireLockList(DEFAULT_LOCK_TYPE, INodeAttributes.Finder.ByINodeIds, pks); } protected List<INode> fetchINodesUsingMemcache(TransactionLockTypes.INodeLockType lockType, String path, boolean tryToSetParitionKey) throws IOException { int[] inodeIds = PathMemcache.getInstance().get(path); if (inodeIds != null) { if (tryToSetParitionKey) { setPartitioningKey(inodeIds[inodeIds.length - 1]); } final String[] names = INode.getPathNames(path); final int[] parentIds = getParentIds(inodeIds); List<INode> inodes = readINodesWhileRespectingLocks(lockType, names, parentIds); if (inodes != null) { if (verifyINodes(inodes, names, parentIds, inodeIds)) { addPathINodes(path, inodes); return inodes; } else { PathMemcache.getInstance().delete(path); } } } return null; } private List<INode> readINodesWhileRespectingLocks(TransactionLockTypes.INodeLockType lockType, final String[] names, final int[] parentIds) throws TransactionContextException, StorageException { int rowsToReadWithDefaultLock = names.length; if (!lockType.equals(DEFAULT_INODE_LOCK_TYPE)) { if (lockType.equals(TransactionLockTypes.INodeLockType.WRITE_ON_TARGET_AND_PARENT)) { rowsToReadWithDefaultLock -= 2; } else { rowsToReadWithDefaultLock -= 1; } } List<INode> inodes = null; if (rowsToReadWithDefaultLock > 0) { inodes = findBatch(DEFAULT_INODE_LOCK_TYPE, Arrays.copyOf(names, rowsToReadWithDefaultLock), Arrays.copyOf(parentIds, rowsToReadWithDefaultLock)); } if (inodes != null) { if (lockType.equals(TransactionLockTypes.INodeLockType.WRITE_ON_TARGET_AND_PARENT)) { INode parent = find(lockType, names[names.length - 2], parentIds[parentIds.length - 2]); inodes.add(parent); } INode target = find(lockType, names[names.length - 1], parentIds[parentIds.length - 1]); inodes.add(target); } return inodes; } private boolean verifyINodes(final List<INode> inodes, final String[] names, final int[] parentIds, final int[] inodeIds) throws IOException { boolean verified = false; if (names.length == parentIds.length) { if (inodes.size() == names.length) { boolean noChangeInInodes = true; for (int i = 0; i < inodes.size(); i++) { INode inode = inodes.get(i); noChangeInInodes = inode != null && inode.getLocalName().equals(names[i]) && inode.getParentId() == parentIds[i] && inode.getId() == inodeIds[i]; if (!noChangeInInodes) { break; } } verified = noChangeInInodes; } } return verified; } private int[] getParentIds(int[] inodeIds) { int[] parentIds = new int[inodeIds.length]; parentIds[0] = INodeDirectory.ROOT_PARENT_ID; System.arraycopy(inodeIds, 0, parentIds, 1, inodeIds.length - 1); return parentIds; } protected void setPartitioningKey(Integer inodeId) throws StorageException, TransactionContextException { if (inodeId == null || !isSetPartitionKeyEnabled()) { LOG.warn("Transaction Partition Key is not Set"); } else { //set partitioning key Object[] key = new Object[2]; key[0] = inodeId; key[1] = new Long(0); EntityManager.setPartitionKey(BlockInfoDataAccess.class, key); LOG.debug("Setting Partitioning Key to be " + inodeId); EntityManager.find(BlockInfo.Finder.ByBlockIdAndINodeId, key[1], key[0]); } } @Override protected final Type getType() { return Type.INode; } }