1919
2020import  java .io .IOException ;
2121import  java .util .Iterator ;
22+ import  java .util .LinkedList ;
2223import  java .util .List ;
23- import  java .util .NoSuchElementException ;
2424
2525import  com .google .common .base .Preconditions ;
2626import  org .apache .hadoop .classification .InterfaceAudience ;
@@ -56,9 +56,19 @@ public abstract class BlockInfo extends Block
5656  /** For implementing {@link LightWeightGSet.LinkedElement} interface. */ 
5757  private  LightWeightGSet .LinkedElement  nextLinkedElement ;
5858
59- 
60-   // Storages this block is replicated on 
61-   protected  DatanodeStorageInfo [] storages ;
59+   /** 
60+    * This array contains triplets of references. For each i-th storage, the 
61+    * block belongs to triplets[3*i] is the reference to the 
62+    * {@link DatanodeStorageInfo} and triplets[3*i+1] and triplets[3*i+2] are 
63+    * references to the previous and the next blocks, respectively, in the list 
64+    * of blocks belonging to this storage. 
65+    * 
66+    * Using previous and next in Object triplets is done instead of a 
67+    * {@link LinkedList} list to efficiently use memory. With LinkedList the cost 
68+    * per replica is 42 bytes (LinkedList#Entry object per replica) versus 16 
69+    * bytes using the triplets. 
70+    */ 
71+   protected  Object [] triplets ;
6272
6373  private  BlockUnderConstructionFeature  uc ;
6474
@@ -68,14 +78,14 @@ public abstract class BlockInfo extends Block
6878   *             in the block group 
6979   */ 
7080  public  BlockInfo (short  size ) {
71-     this .storages  = new  DatanodeStorageInfo [ size ];
81+     this .triplets  = new  Object [ 3  *  size ];
7282    this .bcId  = INVALID_INODE_ID ;
7383    this .replication  = isStriped () ? 0  : size ;
7484  }
7585
7686  public  BlockInfo (Block  blk , short  size ) {
7787    super (blk );
78-     this .storages  = new  DatanodeStorageInfo [ size ];
88+     this .triplets  = new  Object [ 3 * size ];
7989    this .bcId  = INVALID_INODE_ID ;
8090    this .replication  = isStriped () ? 0  : size ;
8191  }
@@ -105,31 +115,7 @@ public boolean isDeleted() {
105115  }
106116
107117  public  Iterator <DatanodeStorageInfo > getStorageInfos () {
108-     return  new  Iterator <DatanodeStorageInfo >() {
109- 
110-       private  int  index  = 0 ;
111- 
112-       @ Override 
113-       public  boolean  hasNext () {
114-         while  (index  < storages .length  && storages [index ] == null ) {
115-           index ++;
116-         }
117-         return  index  < storages .length ;
118-       }
119- 
120-       @ Override 
121-       public  DatanodeStorageInfo  next () {
122-         if  (!hasNext ()) {
123-           throw  new  NoSuchElementException ();
124-         }
125-         return  storages [index ++];
126-       }
127- 
128-       @ Override 
129-       public  void  remove () {
130-         throw  new  UnsupportedOperationException ("Sorry. can't remove." );
131-       }
132-     };
118+     return  new  BlocksMap .StorageIterator (this );
133119  }
134120
135121  public  DatanodeDescriptor  getDatanode (int  index ) {
@@ -138,18 +124,73 @@ public DatanodeDescriptor getDatanode(int index) {
138124  }
139125
140126  DatanodeStorageInfo  getStorageInfo (int  index ) {
141-     assert  this .storages  != null  : "BlockInfo is not initialized" ;
142-     return  storages [index ];
127+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
128+     assert  index  >= 0  && index *3  < triplets .length  : "Index is out of bound" ;
129+     return  (DatanodeStorageInfo )triplets [index *3 ];
130+   }
131+ 
132+   BlockInfo  getPrevious (int  index ) {
133+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
134+     assert  index  >= 0  && index *3 +1  < triplets .length  : "Index is out of bound" ;
135+     BlockInfo  info  = (BlockInfo )triplets [index *3 +1 ];
136+     assert  info  == null  ||
137+         info .getClass ().getName ().startsWith (BlockInfo .class .getName ()) :
138+         "BlockInfo is expected at "  + index *3 ;
139+     return  info ;
140+   }
141+ 
142+   BlockInfo  getNext (int  index ) {
143+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
144+     assert  index  >= 0  && index *3 +2  < triplets .length  : "Index is out of bound" ;
145+     BlockInfo  info  = (BlockInfo )triplets [index *3 +2 ];
146+     assert  info  == null  || info .getClass ().getName ().startsWith (
147+         BlockInfo .class .getName ()) :
148+         "BlockInfo is expected at "  + index *3 ;
149+     return  info ;
143150  }
144151
145152  void  setStorageInfo (int  index , DatanodeStorageInfo  storage ) {
146-     assert  this .storages  != null  : "BlockInfo is not initialized" ;
147-     this .storages [index ] = storage ;
153+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
154+     assert  index  >= 0  && index *3  < triplets .length  : "Index is out of bound" ;
155+     triplets [index *3 ] = storage ;
156+   }
157+ 
158+   /** 
159+    * Return the previous block on the block list for the datanode at 
160+    * position index. Set the previous block on the list to "to". 
161+    * 
162+    * @param index - the datanode index 
163+    * @param to - block to be set to previous on the list of blocks 
164+    * @return current previous block on the list of blocks 
165+    */ 
166+   BlockInfo  setPrevious (int  index , BlockInfo  to ) {
167+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
168+     assert  index  >= 0  && index *3 +1  < triplets .length  : "Index is out of bound" ;
169+     BlockInfo  info  = (BlockInfo ) triplets [index *3 +1 ];
170+     triplets [index *3 +1 ] = to ;
171+     return  info ;
172+   }
173+ 
174+   /** 
175+    * Return the next block on the block list for the datanode at 
176+    * position index. Set the next block on the list to "to". 
177+    * 
178+    * @param index - the datanode index 
179+    * @param to - block to be set to next on the list of blocks 
180+    * @return current next block on the list of blocks 
181+    */ 
182+   BlockInfo  setNext (int  index , BlockInfo  to ) {
183+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
184+     assert  index  >= 0  && index *3 +2  < triplets .length  : "Index is out of bound" ;
185+     BlockInfo  info  = (BlockInfo ) triplets [index *3 +2 ];
186+     triplets [index *3 +2 ] = to ;
187+     return  info ;
148188  }
149189
150190  public  int  getCapacity () {
151-     assert  this .storages  != null  : "BlockInfo is not initialized" ;
152-     return  storages .length ;
191+     assert  this .triplets  != null  : "BlockInfo is not initialized" ;
192+     assert  triplets .length  % 3  == 0  : "Malformed BlockInfo" ;
193+     return  triplets .length  / 3 ;
153194  }
154195
155196  /** 
@@ -210,6 +251,80 @@ int findStorageInfo(DatanodeStorageInfo storageInfo) {
210251    return  -1 ;
211252  }
212253
254+   /** 
255+    * Insert this block into the head of the list of blocks 
256+    * related to the specified DatanodeStorageInfo. 
257+    * If the head is null then form a new list. 
258+    * @return current block as the new head of the list. 
259+    */ 
260+   BlockInfo  listInsert (BlockInfo  head , DatanodeStorageInfo  storage ) {
261+     int  dnIndex  = this .findStorageInfo (storage );
262+     assert  dnIndex  >= 0  : "Data node is not found: current" ;
263+     assert  getPrevious (dnIndex ) == null  && getNext (dnIndex ) == null  :
264+         "Block is already in the list and cannot be inserted." ;
265+     this .setPrevious (dnIndex , null );
266+     this .setNext (dnIndex , head );
267+     if  (head  != null ) {
268+       head .setPrevious (head .findStorageInfo (storage ), this );
269+     }
270+     return  this ;
271+   }
272+ 
273+   /** 
274+    * Remove this block from the list of blocks 
275+    * related to the specified DatanodeStorageInfo. 
276+    * If this block is the head of the list then return the next block as 
277+    * the new head. 
278+    * @return the new head of the list or null if the list becomes 
279+    * empy after deletion. 
280+    */ 
281+   BlockInfo  listRemove (BlockInfo  head , DatanodeStorageInfo  storage ) {
282+     if  (head  == null ) {
283+       return  null ;
284+     }
285+     int  dnIndex  = this .findStorageInfo (storage );
286+     if  (dnIndex  < 0 ) { // this block is not on the data-node list 
287+       return  head ;
288+     }
289+ 
290+     BlockInfo  next  = this .getNext (dnIndex );
291+     BlockInfo  prev  = this .getPrevious (dnIndex );
292+     this .setNext (dnIndex , null );
293+     this .setPrevious (dnIndex , null );
294+     if  (prev  != null ) {
295+       prev .setNext (prev .findStorageInfo (storage ), next );
296+     }
297+     if  (next  != null ) {
298+       next .setPrevious (next .findStorageInfo (storage ), prev );
299+     }
300+     if  (this  == head ) { // removing the head 
301+       head  = next ;
302+     }
303+     return  head ;
304+   }
305+ 
306+   /** 
307+    * Remove this block from the list of blocks related to the specified 
308+    * DatanodeDescriptor. Insert it into the head of the list of blocks. 
309+    * 
310+    * @return the new head of the list. 
311+    */ 
312+   public  BlockInfo  moveBlockToHead (BlockInfo  head , DatanodeStorageInfo  storage ,
313+       int  curIndex , int  headIndex ) {
314+     if  (head  == this ) {
315+       return  this ;
316+     }
317+     BlockInfo  next  = this .setNext (curIndex , head );
318+     BlockInfo  prev  = this .setPrevious (curIndex , null );
319+ 
320+     head .setPrevious (headIndex , this );
321+     prev .setNext (prev .findStorageInfo (storage ), next );
322+     if  (next  != null ) {
323+       next .setPrevious (next .findStorageInfo (storage ), prev );
324+     }
325+     return  this ;
326+   }
327+ 
213328  @ Override 
214329  public  int  hashCode () {
215330    // Super implementation is sufficient 
0 commit comments