/** * 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 io.hops.exception.TransactionContextException; import io.hops.metadata.hdfs.entity.INodeCandidatePrimaryKey; import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo; import org.apache.hadoop.hdfs.server.namenode.INode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; abstract class BaseReplicaContext<Key extends BlockPK, Entity> extends BaseEntityContext<Key, Entity> { private Map<Long, Map<Key, Entity>> blocksToReplicas = new HashMap<Long, Map<Key, Entity>>(); private Map<Integer, Map<Key, Entity>> inodesToReplicas = new HashMap<Integer, Map<Key, Entity>>(); @Override public void update(Entity entity) throws TransactionContextException { super.update(entity); addInternal(entity); } @Override public void remove(Entity entity) throws TransactionContextException { super.remove(entity); BlockPK key = getKey(entity); Map<Key, Entity> entityMap = blocksToReplicas.get(key.getBlockId()); if (entityMap != null) { entityMap.remove(key); } entityMap = inodesToReplicas.get(key.getBlockId()); if (entityMap != null) { entityMap.remove(key); } } @Override public void clear() throws TransactionContextException { super.clear(); blocksToReplicas.clear(); inodesToReplicas.clear(); } @Override final void gotFromDB(Key entityKey, Entity entity) { super.gotFromDB(entityKey, entity); addInternal(entityKey, entity); } private void addInternal(Entity entity) { addInternal(getKey(entity), entity); } private void addInternal(Key key, Entity entity) { Map<Key, Entity> entityMap; if (key.hasBlockId()) { entityMap = blocksToReplicas.get(key.getBlockId()); if (entityMap == null) { entityMap = new HashMap<Key, Entity>(); blocksToReplicas.put(key.getBlockId(), entityMap); } entityMap.put(key, entity); } if (key.hasINodeId()) { entityMap = inodesToReplicas.get(key.getInodeId()); if (entityMap == null) { entityMap = new HashMap<Key, Entity>(); inodesToReplicas.put(key.getInodeId(), entityMap); } entityMap.put(key, entity); } } final void gotFromDB(BlockPK key, List<Entity> entities) { if (key.hasBlockId()) { Map<Key, Entity> entityMap = blocksToReplicas.get(key.getBlockId()); if (entityMap == null) { blocksToReplicas.put(key.getBlockId(), null); } } if (key.hasINodeId()) { Map<Key, Entity> entityMap = inodesToReplicas.get(key.getInodeId()); if (entityMap == null) { inodesToReplicas.put(key.getInodeId(), null); } } if (entities != null) { for (Entity entity : entities) { gotFromDB(entity); } } } final void gotFromDB(List<Key> keys, List<Entity> entities) { if (entities != null) { for (Entity entity : entities) { Key key = getKey(entity); gotFromDB(key, entity); keys.remove(key); } } for (Key key : keys) { gotFromDB(key, (Entity) null); } } final boolean containsByBlock(long blockId) { return blocksToReplicas.containsKey(blockId); } final boolean containsByINode(int inodeId) { return inodesToReplicas.containsKey(inodeId); } final List<Entity> getByBlock(long blockId) { Map<Key, Entity> entityMap = blocksToReplicas.get(blockId); if (entityMap == null) { return null; } return new ArrayList<Entity>(entityMap.values()); } final List<Entity> getByINode(int inodeId) { Map<Key, Entity> entityMap = inodesToReplicas.get(inodeId); if (entityMap == null) { return null; } return new ArrayList<Entity>(entityMap.values()); } @Override public final void snapshotMaintenance(TransactionContextMaintenanceCmds cmds, Object... params) throws TransactionContextException { HdfsTransactionContextMaintenanceCmds hopCmds = (HdfsTransactionContextMaintenanceCmds) cmds; switch (hopCmds) { case INodePKChanged: // need to update the rows with updated inodeId or partKey checkForSnapshotChange(); INode inodeBeforeChange = (INode) params[0]; INode inodeAfterChange = (INode) params[1]; break; case Concat: checkForSnapshotChange(); INodeCandidatePrimaryKey trg_param = (INodeCandidatePrimaryKey) params[0]; List<INodeCandidatePrimaryKey> srcs_param = (List<INodeCandidatePrimaryKey>) params[1]; List<BlockInfo> oldBlks = (List<BlockInfo>) params[2]; updateReplicas(trg_param, srcs_param); break; case BlockDoesNotExist: blockDoesNotExist((Long) params[0], (Integer) params[1]); break; case EmptyFile: emptyFile((Integer) params[0]); break; } } private void checkForSnapshotChange() { if (snapshotChanged()) // during // the // tx no // replica // should have been changed {// renaming to existing file will put replicas in the deleted list throw new IllegalStateException( "No replica should have been changed during the Tx ( " + this.getClass() + ")"); } } protected boolean snapshotChanged() { return !getAdded().isEmpty() || !getModified().isEmpty() || !getRemoved().isEmpty(); } private void updateReplicas(INodeCandidatePrimaryKey trg_param, List<INodeCandidatePrimaryKey> toBeDeletedSrcs) throws TransactionContextException { toBeDeletedSrcs.remove(trg_param); for (INodeCandidatePrimaryKey src : toBeDeletedSrcs) { List<Entity> replicas = getByINode(src.getInodeId()); if (replicas == null) { continue; } for (Entity replica : replicas) { Entity toBeDeleted = cloneEntity(replica); Entity toBeAdded = cloneEntity(replica, trg_param.getInodeId()); Key toBeDeletedKey = getKey(toBeDeleted); Key toBeAddedKey = getKey(toBeAdded); remove(toBeDeleted); if(isLogDebugEnabled()) { log("snapshot-maintenance-removed-replica", "bid", toBeDeletedKey.getBlockId(), "inodeId", toBeDeletedKey.getInodeId()); } add(toBeAdded); if(isLogDebugEnabled()) { log("snapshot-maintenance-added-replica", "bid", toBeAddedKey.getBlockId(), "inodeId", toBeAddedKey.getInodeId()); } } } } private void blockDoesNotExist(long blockId, int inodeId){ emptyFile(inodeId); if (!containsByBlock(blockId)) { blocksToReplicas.put(blockId, null); } } private void emptyFile(int inodeId){ if(!containsByINode(inodeId)){ inodesToReplicas.put(inodeId, null); } } abstract Entity cloneEntity(Entity entity); abstract Entity cloneEntity(Entity entity, int inodeId); }