001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hdfs.server.blockmanagement; 019 020import org.apache.hadoop.hdfs.protocol.Block; 021import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState; 022import org.apache.hadoop.hdfs.server.namenode.INodeFile; 023import org.apache.hadoop.hdfs.util.LightWeightGSet; 024 025/** 026 * Internal class for block metadata. 027 */ 028public class BlockInfo extends Block implements LightWeightGSet.LinkedElement { 029 private INodeFile inode; 030 031 /** For implementing {@link LightWeightGSet.LinkedElement} interface */ 032 private LightWeightGSet.LinkedElement nextLinkedElement; 033 034 /** 035 * This array contains triplets of references. 036 * For each i-th datanode the block belongs to 037 * triplets[3*i] is the reference to the DatanodeDescriptor 038 * and triplets[3*i+1] and triplets[3*i+2] are references 039 * to the previous and the next blocks, respectively, in the 040 * list of blocks belonging to this data-node. 041 */ 042 private Object[] triplets; 043 044 /** 045 * Construct an entry for blocksmap 046 * @param replication the block's replication factor 047 */ 048 public BlockInfo(int replication) { 049 this.triplets = new Object[3*replication]; 050 this.inode = null; 051 } 052 053 public BlockInfo(Block blk, int replication) { 054 super(blk); 055 this.triplets = new Object[3*replication]; 056 this.inode = null; 057 } 058 059 /** 060 * Copy construction. 061 * This is used to convert BlockInfoUnderConstruction 062 * @param from BlockInfo to copy from. 063 */ 064 protected BlockInfo(BlockInfo from) { 065 this(from, from.inode.getReplication()); 066 this.inode = from.inode; 067 } 068 069 public INodeFile getINode() { 070 return inode; 071 } 072 073 public void setINode(INodeFile inode) { 074 this.inode = inode; 075 } 076 077 DatanodeDescriptor getDatanode(int index) { 078 assert this.triplets != null : "BlockInfo is not initialized"; 079 assert index >= 0 && index*3 < triplets.length : "Index is out of bound"; 080 return (DatanodeDescriptor)triplets[index*3]; 081 } 082 083 BlockInfo getPrevious(int index) { 084 assert this.triplets != null : "BlockInfo is not initialized"; 085 assert index >= 0 && index*3+1 < triplets.length : "Index is out of bound"; 086 BlockInfo info = (BlockInfo)triplets[index*3+1]; 087 assert info == null || 088 info.getClass().getName().startsWith(BlockInfo.class.getName()) : 089 "BlockInfo is expected at " + index*3; 090 return info; 091 } 092 093 BlockInfo getNext(int index) { 094 assert this.triplets != null : "BlockInfo is not initialized"; 095 assert index >= 0 && index*3+2 < triplets.length : "Index is out of bound"; 096 BlockInfo info = (BlockInfo)triplets[index*3+2]; 097 assert info == null || 098 info.getClass().getName().startsWith(BlockInfo.class.getName()) : 099 "BlockInfo is expected at " + index*3; 100 return info; 101 } 102 103 void setDatanode(int index, DatanodeDescriptor node) { 104 assert this.triplets != null : "BlockInfo is not initialized"; 105 assert index >= 0 && index*3 < triplets.length : "Index is out of bound"; 106 triplets[index*3] = node; 107 } 108 109 void setPrevious(int index, BlockInfo to) { 110 assert this.triplets != null : "BlockInfo is not initialized"; 111 assert index >= 0 && index*3+1 < triplets.length : "Index is out of bound"; 112 triplets[index*3+1] = to; 113 } 114 115 void setNext(int index, BlockInfo to) { 116 assert this.triplets != null : "BlockInfo is not initialized"; 117 assert index >= 0 && index*3+2 < triplets.length : "Index is out of bound"; 118 triplets[index*3+2] = to; 119 } 120 121 /** 122 * Return the previous block on the block list for the datanode at 123 * position index. Set the previous block on the list to "to". 124 * 125 * @param index - the datanode index 126 * @param to - block to be set to previous on the list of blocks 127 * @return current previous block on the list of blocks 128 */ 129 BlockInfo getSetPrevious(int index, BlockInfo to) { 130 assert this.triplets != null : "BlockInfo is not initialized"; 131 assert index >= 0 && index*3+1 < triplets.length : "Index is out of bound"; 132 BlockInfo info = (BlockInfo)triplets[index*3+1]; 133 triplets[index*3+1] = to; 134 return info; 135 } 136 137 /** 138 * Return the next block on the block list for the datanode at 139 * position index. Set the next block on the list to "to". 140 * 141 * @param index - the datanode index 142 * @param to - block to be set to next on the list of blocks 143 * * @return current next block on the list of blocks 144 */ 145 BlockInfo getSetNext(int index, BlockInfo to) { 146 assert this.triplets != null : "BlockInfo is not initialized"; 147 assert index >= 0 && index*3+2 < triplets.length : "Index is out of bound"; 148 BlockInfo info = (BlockInfo)triplets[index*3+2]; 149 triplets[index*3+2] = to; 150 return info; 151 } 152 153 int getCapacity() { 154 assert this.triplets != null : "BlockInfo is not initialized"; 155 assert triplets.length % 3 == 0 : "Malformed BlockInfo"; 156 return triplets.length / 3; 157 } 158 159 /** 160 * Ensure that there is enough space to include num more triplets. 161 * @return first free triplet index. 162 */ 163 private int ensureCapacity(int num) { 164 assert this.triplets != null : "BlockInfo is not initialized"; 165 int last = numNodes(); 166 if(triplets.length >= (last+num)*3) 167 return last; 168 /* Not enough space left. Create a new array. Should normally 169 * happen only when replication is manually increased by the user. */ 170 Object[] old = triplets; 171 triplets = new Object[(last+num)*3]; 172 System.arraycopy(old, 0, triplets, 0, last*3); 173 return last; 174 } 175 176 /** 177 * Count the number of data-nodes the block belongs to. 178 */ 179 int numNodes() { 180 assert this.triplets != null : "BlockInfo is not initialized"; 181 assert triplets.length % 3 == 0 : "Malformed BlockInfo"; 182 for(int idx = getCapacity()-1; idx >= 0; idx--) { 183 if(getDatanode(idx) != null) 184 return idx+1; 185 } 186 return 0; 187 } 188 189 /** 190 * Add data-node this block belongs to. 191 */ 192 public boolean addNode(DatanodeDescriptor node) { 193 if(findDatanode(node) >= 0) // the node is already there 194 return false; 195 // find the last null node 196 int lastNode = ensureCapacity(1); 197 setDatanode(lastNode, node); 198 setNext(lastNode, null); 199 setPrevious(lastNode, null); 200 return true; 201 } 202 203 /** 204 * Remove data-node from the block. 205 */ 206 public boolean removeNode(DatanodeDescriptor node) { 207 int dnIndex = findDatanode(node); 208 if(dnIndex < 0) // the node is not found 209 return false; 210 assert getPrevious(dnIndex) == null && getNext(dnIndex) == null : 211 "Block is still in the list and must be removed first."; 212 // find the last not null node 213 int lastNode = numNodes()-1; 214 // replace current node triplet by the lastNode one 215 setDatanode(dnIndex, getDatanode(lastNode)); 216 setNext(dnIndex, getNext(lastNode)); 217 setPrevious(dnIndex, getPrevious(lastNode)); 218 // set the last triplet to null 219 setDatanode(lastNode, null); 220 setNext(lastNode, null); 221 setPrevious(lastNode, null); 222 return true; 223 } 224 225 /** 226 * Find specified DatanodeDescriptor. 227 * @param dn 228 * @return index or -1 if not found. 229 */ 230 int findDatanode(DatanodeDescriptor dn) { 231 int len = getCapacity(); 232 for(int idx = 0; idx < len; idx++) { 233 DatanodeDescriptor cur = getDatanode(idx); 234 if(cur == dn) 235 return idx; 236 if(cur == null) 237 break; 238 } 239 return -1; 240 } 241 242 /** 243 * Insert this block into the head of the list of blocks 244 * related to the specified DatanodeDescriptor. 245 * If the head is null then form a new list. 246 * @return current block as the new head of the list. 247 */ 248 public BlockInfo listInsert(BlockInfo head, DatanodeDescriptor dn) { 249 int dnIndex = this.findDatanode(dn); 250 assert dnIndex >= 0 : "Data node is not found: current"; 251 assert getPrevious(dnIndex) == null && getNext(dnIndex) == null : 252 "Block is already in the list and cannot be inserted."; 253 this.setPrevious(dnIndex, null); 254 this.setNext(dnIndex, head); 255 if(head != null) 256 head.setPrevious(head.findDatanode(dn), this); 257 return this; 258 } 259 260 /** 261 * Remove this block from the list of blocks 262 * related to the specified DatanodeDescriptor. 263 * If this block is the head of the list then return the next block as 264 * the new head. 265 * @return the new head of the list or null if the list becomes 266 * empty after deletion. 267 */ 268 public BlockInfo listRemove(BlockInfo head, DatanodeDescriptor dn) { 269 if(head == null) 270 return null; 271 int dnIndex = this.findDatanode(dn); 272 if(dnIndex < 0) // this block is not on the data-node list 273 return head; 274 275 BlockInfo next = this.getNext(dnIndex); 276 BlockInfo prev = this.getPrevious(dnIndex); 277 this.setNext(dnIndex, null); 278 this.setPrevious(dnIndex, null); 279 if(prev != null) 280 prev.setNext(prev.findDatanode(dn), next); 281 if(next != null) 282 next.setPrevious(next.findDatanode(dn), prev); 283 if(this == head) // removing the head 284 head = next; 285 return head; 286 } 287 288 /** 289 * Remove this block from the list of blocks related to the specified 290 * DatanodeDescriptor. Insert it into the head of the list of blocks. 291 * 292 * @return the new head of the list. 293 */ 294 public BlockInfo moveBlockToHead(BlockInfo head, DatanodeDescriptor dn, 295 int curIndex, int headIndex) { 296 if (head == this) { 297 return this; 298 } 299 BlockInfo next = this.getSetNext(curIndex, head); 300 BlockInfo prev = this.getSetPrevious(curIndex, null); 301 302 head.setPrevious(headIndex, this); 303 prev.setNext(prev.findDatanode(dn), next); 304 if (next != null) 305 next.setPrevious(next.findDatanode(dn), prev); 306 return this; 307 } 308 309 /** 310 * BlockInfo represents a block that is not being constructed. 311 * In order to start modifying the block, the BlockInfo should be converted 312 * to {@link BlockInfoUnderConstruction}. 313 * @return {@link BlockUCState#COMPLETE} 314 */ 315 public BlockUCState getBlockUCState() { 316 return BlockUCState.COMPLETE; 317 } 318 319 /** 320 * Is this block complete? 321 * 322 * @return true if the state of the block is {@link BlockUCState#COMPLETE} 323 */ 324 public boolean isComplete() { 325 return getBlockUCState().equals(BlockUCState.COMPLETE); 326 } 327 328 /** 329 * Convert a complete block to an under construction block. 330 * 331 * @return BlockInfoUnderConstruction - an under construction block. 332 */ 333 public BlockInfoUnderConstruction convertToBlockUnderConstruction( 334 BlockUCState s, DatanodeDescriptor[] targets) { 335 if(isComplete()) { 336 return new BlockInfoUnderConstruction( 337 this, getINode().getReplication(), s, targets); 338 } 339 // the block is already under construction 340 BlockInfoUnderConstruction ucBlock = (BlockInfoUnderConstruction)this; 341 ucBlock.setBlockUCState(s); 342 ucBlock.setExpectedLocations(targets); 343 return ucBlock; 344 } 345 346 @Override 347 public int hashCode() { 348 // Super implementation is sufficient 349 return super.hashCode(); 350 } 351 352 @Override 353 public boolean equals(Object obj) { 354 // Sufficient to rely on super's implementation 355 return (this == obj) || super.equals(obj); 356 } 357 358 @Override 359 public LightWeightGSet.LinkedElement getNext() { 360 return nextLinkedElement; 361 } 362 363 @Override 364 public void setNext(LightWeightGSet.LinkedElement next) { 365 this.nextLinkedElement = next; 366 } 367}