| /** |
| * 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 org.apache.hadoop.hdfs.protocol; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.hadoop.classification.InterfaceAudience; |
| import org.apache.hadoop.classification.InterfaceStability; |
| import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.ReplicaState; |
| import org.apache.hadoop.hdfs.server.datanode.ReplicaInfo; |
| |
| /** |
| * This class provides an interface for accessing list of blocks that |
| * has been implemented as long[]. |
| * This class is useful for block report. Rather than send block reports |
| * as a Block[] we can send it as a long[]. |
| * |
| * The structure of the array is as follows: |
| * 0: the length of the finalized replica list; |
| * 1: the length of the under-construction replica list; |
| * - followed by finalized replica list where each replica is represented by |
| * 3 longs: one for the blockId, one for the block length, and one for |
| * the generation stamp; |
| * - followed by the invalid replica represented with three -1s; |
| * - followed by the under-construction replica list where each replica is |
| * represented by 4 longs: three for the block id, length, generation |
| * stamp, and the forth for the replica state. |
| */ |
| @InterfaceAudience.Private |
| @InterfaceStability.Evolving |
| public class BlockListAsLongs implements Iterable<Block> { |
| /** |
| * A finalized block as 3 longs |
| * block-id and block length and generation stamp |
| */ |
| private static final int LONGS_PER_FINALIZED_BLOCK = 3; |
| |
| /** |
| * An under-construction block as 4 longs |
| * block-id and block length, generation stamp and replica state |
| */ |
| private static final int LONGS_PER_UC_BLOCK = 4; |
| |
| /** Number of longs in the header */ |
| private static final int HEADER_SIZE = 2; |
| |
| /** |
| * Returns the index of the first long in blockList |
| * belonging to the specified block. |
| * The first long contains the block id. |
| */ |
| private int index2BlockId(int blockIndex) { |
| if(blockIndex < 0 || blockIndex > getNumberOfBlocks()) |
| return -1; |
| int finalizedSize = getNumberOfFinalizedReplicas(); |
| if(blockIndex < finalizedSize) |
| return HEADER_SIZE + blockIndex * LONGS_PER_FINALIZED_BLOCK; |
| return HEADER_SIZE + (finalizedSize + 1) * LONGS_PER_FINALIZED_BLOCK |
| + (blockIndex - finalizedSize) * LONGS_PER_UC_BLOCK; |
| } |
| |
| private long[] blockList; |
| |
| /** |
| * Create block report from finalized and under construction lists of blocks. |
| * |
| * @param finalized - list of finalized blocks |
| * @param uc - list of under construction blocks |
| */ |
| public BlockListAsLongs(final List<? extends Block> finalized, |
| final List<ReplicaInfo> uc) { |
| int finalizedSize = finalized == null ? 0 : finalized.size(); |
| int ucSize = uc == null ? 0 : uc.size(); |
| int len = HEADER_SIZE |
| + (finalizedSize + 1) * LONGS_PER_FINALIZED_BLOCK |
| + ucSize * LONGS_PER_UC_BLOCK; |
| |
| blockList = new long[len]; |
| |
| // set the header |
| blockList[0] = finalizedSize; |
| blockList[1] = ucSize; |
| |
| // set finalized blocks |
| for (int i = 0; i < finalizedSize; i++) { |
| setBlock(i, finalized.get(i)); |
| } |
| |
| // set invalid delimiting block |
| setDelimitingBlock(finalizedSize); |
| |
| // set under construction blocks |
| for (int i = 0; i < ucSize; i++) { |
| setBlock(finalizedSize + i, uc.get(i)); |
| } |
| } |
| |
| public BlockListAsLongs() { |
| this(null); |
| } |
| |
| /** |
| * Constructor |
| * @param iBlockList - BlockListALongs create from this long[] parameter |
| */ |
| public BlockListAsLongs(final long[] iBlockList) { |
| if (iBlockList == null) { |
| blockList = new long[HEADER_SIZE]; |
| return; |
| } |
| blockList = iBlockList; |
| } |
| |
| public long[] getBlockListAsLongs() { |
| return blockList; |
| } |
| |
| /** |
| * Iterates over blocks in the block report. |
| * Avoids object allocation on each iteration. |
| */ |
| @InterfaceAudience.Private |
| @InterfaceStability.Evolving |
| public class BlockReportIterator implements Iterator<Block> { |
| private int currentBlockIndex; |
| private Block block; |
| private ReplicaState currentReplicaState; |
| |
| BlockReportIterator() { |
| this.currentBlockIndex = 0; |
| this.block = new Block(); |
| this.currentReplicaState = null; |
| } |
| |
| public boolean hasNext() { |
| return currentBlockIndex < getNumberOfBlocks(); |
| } |
| |
| public Block next() { |
| block.set(blockId(currentBlockIndex), |
| blockLength(currentBlockIndex), |
| blockGenerationStamp(currentBlockIndex)); |
| currentReplicaState = blockReplicaState(currentBlockIndex); |
| currentBlockIndex++; |
| return block; |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException("Sorry. can't remove."); |
| } |
| |
| /** |
| * Get the state of the current replica. |
| * The state corresponds to the replica returned |
| * by the latest {@link #next()}. |
| */ |
| public ReplicaState getCurrentReplicaState() { |
| return currentReplicaState; |
| } |
| } |
| |
| /** |
| * Returns an iterator over blocks in the block report. |
| */ |
| public Iterator<Block> iterator() { |
| return getBlockReportIterator(); |
| } |
| |
| /** |
| * Returns {@link BlockReportIterator}. |
| */ |
| public BlockReportIterator getBlockReportIterator() { |
| return new BlockReportIterator(); |
| } |
| |
| /** |
| * The number of blocks |
| * @return - the number of blocks |
| */ |
| public int getNumberOfBlocks() { |
| assert blockList.length == HEADER_SIZE + |
| (blockList[0] + 1) * LONGS_PER_FINALIZED_BLOCK + |
| blockList[1] * LONGS_PER_UC_BLOCK : |
| "Number of blocks is inconcistent with the array length"; |
| return getNumberOfFinalizedReplicas() + getNumberOfUCReplicas(); |
| } |
| |
| /** |
| * Returns the number of finalized replicas in the block report. |
| */ |
| private int getNumberOfFinalizedReplicas() { |
| return (int)blockList[0]; |
| } |
| |
| /** |
| * Returns the number of under construction replicas in the block report. |
| */ |
| private int getNumberOfUCReplicas() { |
| return (int)blockList[1]; |
| } |
| |
| /** |
| * Returns the id of the specified replica of the block report. |
| */ |
| private long blockId(int index) { |
| return blockList[index2BlockId(index)]; |
| } |
| |
| /** |
| * Returns the length of the specified replica of the block report. |
| */ |
| private long blockLength(int index) { |
| return blockList[index2BlockId(index) + 1]; |
| } |
| |
| /** |
| * Returns the generation stamp of the specified replica of the block report. |
| */ |
| private long blockGenerationStamp(int index) { |
| return blockList[index2BlockId(index) + 2]; |
| } |
| |
| /** |
| * Returns the state of the specified replica of the block report. |
| */ |
| private ReplicaState blockReplicaState(int index) { |
| if(index < getNumberOfFinalizedReplicas()) |
| return ReplicaState.FINALIZED; |
| return ReplicaState.getState((int)blockList[index2BlockId(index) + 3]); |
| } |
| |
| /** |
| * The block-id of the indexTh block |
| * @param index - the block whose block-id is desired |
| * @return the block-id |
| */ |
| @Deprecated |
| public long getBlockId(final int index) { |
| return blockId(index); |
| } |
| |
| /** |
| * The block-len of the indexTh block |
| * @param index - the block whose block-len is desired |
| * @return - the block-len |
| */ |
| @Deprecated |
| public long getBlockLen(final int index) { |
| return blockLength(index); |
| } |
| |
| /** |
| * The generation stamp of the indexTh block |
| * @param index - the block whose block-len is desired |
| * @return - the generation stamp |
| */ |
| @Deprecated |
| public long getBlockGenStamp(final int index) { |
| return blockGenerationStamp(index); |
| } |
| |
| /** |
| * Set the indexTh block |
| * @param index - the index of the block to set |
| * @param b - the block is set to the value of the this block |
| */ |
| private <T extends Block> void setBlock(final int index, final T b) { |
| int pos = index2BlockId(index); |
| blockList[pos] = b.getBlockId(); |
| blockList[pos + 1] = b.getNumBytes(); |
| blockList[pos + 2] = b.getGenerationStamp(); |
| if(index < getNumberOfFinalizedReplicas()) |
| return; |
| assert ((ReplicaInfo)b).getState() != ReplicaState.FINALIZED : |
| "Must be under-construction replica."; |
| blockList[pos + 3] = ((ReplicaInfo)b).getState().getValue(); |
| } |
| |
| /** |
| * Set the invalid delimiting block between the finalized and |
| * the under-construction lists. |
| * The invalid block has all three fields set to -1. |
| * @param finalizedSzie - the size of the finalized list |
| */ |
| private void setDelimitingBlock(final int finalizedSzie) { |
| int idx = HEADER_SIZE + finalizedSzie * LONGS_PER_FINALIZED_BLOCK; |
| blockList[idx] = -1; |
| blockList[idx+1] = -1; |
| blockList[idx+2] = -1; |
| } |
| } |