Java tutorial
/** * 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 io.hops.transaction.context; import com.google.common.base.Predicate; import io.hops.exception.LockUpgradeException; import io.hops.exception.StorageException; import io.hops.exception.TransactionContextException; import io.hops.metadata.common.FinderType; import io.hops.metadata.hdfs.dal.INodeDataAccess; import io.hops.transaction.lock.BaseINodeLock; import io.hops.transaction.lock.Lock; import io.hops.transaction.lock.TransactionLockTypes; import io.hops.transaction.lock.TransactionLocks; import org.apache.hadoop.hdfs.server.namenode.INode; 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 class INodeContext extends BaseEntityContext<Integer, INode> { private final INodeDataAccess<INode> dataAccess; private final Map<String, INode> inodesNameParentIndex = new HashMap<String, INode>(); private final Map<Integer, List<INode>> inodesParentIndex = new HashMap<Integer, List<INode>>(); private final List<INode> renamedInodes = new ArrayList<INode>(); public INodeContext(INodeDataAccess dataAccess) { this.dataAccess = dataAccess; } @Override public void clear() throws TransactionContextException { super.clear(); inodesNameParentIndex.clear(); inodesParentIndex.clear(); renamedInodes.clear(); } @Override public INode find(FinderType<INode> finder, Object... params) throws TransactionContextException, StorageException { INode.Finder iFinder = (INode.Finder) finder; switch (iFinder) { case ByINodeId: return findByInodeId(iFinder, params); case ByNameAndParentId: return findByNameAndParentId(iFinder, params); } throw new RuntimeException(UNSUPPORTED_FINDER); } @Override public Collection<INode> findList(FinderType<INode> finder, Object... params) throws TransactionContextException, StorageException { INode.Finder iFinder = (INode.Finder) finder; switch (iFinder) { case ByParentId: return findByParentId(iFinder, params); case ByNamesAndParentIds: return findBatch(iFinder, params); } throw new RuntimeException(UNSUPPORTED_FINDER); } @Override public void remove(INode iNode) throws TransactionContextException { super.remove(iNode); inodesNameParentIndex.remove(iNode.nameParentKey()); log("removed-inode", "id", iNode.getId(), "name", iNode.getLocalName()); } @Override public void update(INode iNode) throws TransactionContextException { super.update(iNode); inodesNameParentIndex.put(iNode.nameParentKey(), iNode); log("updated-inode", "id", iNode.getId(), "name", iNode.getLocalName()); } @Override public void prepare(TransactionLocks lks) throws TransactionContextException, StorageException { // if the list is not empty then check for the lock types // lock type is checked after when list length is checked // because some times in the tx handler the acquire lock // function is empty and in that case tlm will throw // null pointer exceptions Collection<INode> removed = getRemoved(); Collection<INode> added = new ArrayList<INode>(getAdded()); added.addAll(renamedInodes); Collection<INode> modified = getModified(); if (lks.containsLock(Lock.Type.INode)) { BaseINodeLock hlk = (BaseINodeLock) lks.getLock(Lock.Type.INode); if (!removed.isEmpty()) { for (INode inode : removed) { TransactionLockTypes.INodeLockType lock = hlk.getLockedINodeLockType(inode); if (lock != null && lock != TransactionLockTypes.INodeLockType.WRITE && lock != TransactionLockTypes.INodeLockType.WRITE_ON_TARGET_AND_PARENT) { throw new LockUpgradeException( "Trying to remove inode id=" + inode.getId() + " acquired lock was " + lock); } } } if (!modified.isEmpty()) { for (INode inode : modified) { TransactionLockTypes.INodeLockType lock = hlk.getLockedINodeLockType(inode); if (lock != null && lock != TransactionLockTypes.INodeLockType.WRITE && lock != TransactionLockTypes.INodeLockType.WRITE_ON_TARGET_AND_PARENT) { throw new LockUpgradeException( "Trying to update inode id=" + inode.getId() + " acquired lock was " + lock); } } } } dataAccess.prepare(removed, added, modified); } @Override public void snapshotMaintenance(TransactionContextMaintenanceCmds cmds, Object... params) throws TransactionContextException { HdfsTransactionContextMaintenanceCmds hopCmds = (HdfsTransactionContextMaintenanceCmds) cmds; switch (hopCmds) { case INodePKChanged: //delete the previous row from db INode inodeBeforeChange = (INode) params[0]; INode inodeAfterChange = (INode) params[1]; super.remove(inodeBeforeChange); renamedInodes.add(inodeAfterChange); log("snapshot-maintenance-inode-pk-change", "Before inodeId", inodeBeforeChange.getId(), "name", inodeBeforeChange.getLocalName(), "pid", inodeBeforeChange.getParentId(), "After inodeId", inodeAfterChange.getId(), "name", inodeAfterChange.getLocalName(), "pid", inodeAfterChange.getParentId()); log("snapshot-maintenance-removed-inode", "name", inodeBeforeChange.getLocalName(), "inodeId", inodeBeforeChange.getId(), "pid", inodeBeforeChange.getParentId()); break; case Concat: // do nothing // why? files y and z are merged into file x. // all the blocks will be added to file x and the inodes y and z will be deleted. // Inode deletion is handled by the concat function break; } } @Override Integer getKey(INode iNode) { return iNode.getId(); } private INode findByInodeId(INode.Finder inodeFinder, Object[] params) throws TransactionContextException, StorageException { INode result = null; final Integer inodeId = (Integer) params[0]; if (contains(inodeId)) { result = get(inodeId); hit(inodeFinder, result, "id", inodeId); } else { aboutToAccessStorage(inodeFinder, params); result = dataAccess.indexScanfindInodeById(inodeId); gotFromDB(inodeId, result); if (result != null) { inodesNameParentIndex.put(result.nameParentKey(), result); } miss(inodeFinder, result, "id", inodeId); } return result; } private INode findByNameAndParentId(INode.Finder inodeFinder, Object[] params) throws TransactionContextException, StorageException { INode result = null; final String name = (String) params[0]; final Integer parentId = (Integer) params[1]; Integer possibleInodeId = null; if (params.length == 3) { possibleInodeId = (Integer) params[2]; } final String nameParentKey = INode.nameParentKey(parentId, name); if (inodesNameParentIndex.containsKey(nameParentKey)) { result = inodesNameParentIndex.get(nameParentKey); if (!preventStorageCalls() && (currentLockMode.get() == LockMode.WRITE_LOCK)) { //trying to upgrade lock. re-read the row from DB aboutToAccessStorage(inodeFinder, params); result = dataAccess.pkLookUpFindInodeByNameAndParentId(name, parentId); gotFromDBWithPossibleInodeId(result, possibleInodeId); inodesNameParentIndex.put(nameParentKey, result); missUpgrade(inodeFinder, result, "name", name, "pid", parentId); } else { hit(inodeFinder, result, "name", name, "pid", parentId); } } else { if (!isNewlyAdded(parentId) && !containsRemoved(parentId, name)) { aboutToAccessStorage(inodeFinder, params); result = dataAccess.pkLookUpFindInodeByNameAndParentId(name, parentId); gotFromDBWithPossibleInodeId(result, possibleInodeId); inodesNameParentIndex.put(nameParentKey, result); miss(inodeFinder, result, "name", name, "pid", parentId); } } return result; } private List<INode> findByParentId(INode.Finder inodeFinder, Object[] params) throws TransactionContextException, StorageException { final Integer parentId = (Integer) params[0]; List<INode> result = null; if (inodesParentIndex.containsKey(parentId)) { result = inodesParentIndex.get(parentId); hit(inodeFinder, result, "pid", parentId); } else { aboutToAccessStorage(inodeFinder, params); result = syncInodeInstances(dataAccess.indexScanFindInodesByParentId(parentId)); inodesParentIndex.put(parentId, result); miss(inodeFinder, result, "pid", parentId); } return result; } private List<INode> findBatch(INode.Finder inodeFinder, Object[] params) throws TransactionContextException, StorageException { final String[] names = (String[]) params[0]; final int[] parentIds = (int[]) params[1]; List<INode> batch = dataAccess.getINodesPkBatched(names, parentIds); miss(inodeFinder, batch, "name", Arrays.toString(names), "pid", Arrays.toString(parentIds)); return syncInodeInstances(batch); } private List<INode> syncInodeInstances(List<INode> newInodes) { List<INode> finalList = new ArrayList<INode>(newInodes.size()); for (INode inode : newInodes) { if (isRemoved(inode.getId())) { continue; } gotFromDB(inode); finalList.add(inode); String key = inode.nameParentKey(); if (inodesNameParentIndex.containsKey(key)) { if (inodesNameParentIndex.get(key) == null) { inodesNameParentIndex.put(key, inode); } } else { inodesNameParentIndex.put(key, inode); } } Collections.sort(finalList, INode.Order.ByName); return finalList; } private boolean containsRemoved(final Integer parentId, final String name) { return contains(new Predicate<ContextEntity>() { @Override public boolean apply(ContextEntity input) { INode iNode = input.getEntity(); return input.getState() == State.REMOVED && iNode.getParentId() == parentId && iNode.getLocalName().equals(name); } }); } private void gotFromDBWithPossibleInodeId(INode result, Integer possibleInodeId) { if (result == null && possibleInodeId != null) { gotFromDB(possibleInodeId, result); } else { gotFromDB(result); } } }