blob: 165096f24bbf3b9e4bf37d1674fb68a2fd8cb2be [file] [log] [blame]
/**
* 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.HdfsConstants.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;
}
}