View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase;
20  
21  import java.io.IOException;
22  import java.nio.ByteBuffer;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map.Entry;
26  import java.util.NavigableMap;
27  
28  import org.apache.hadoop.classification.InterfaceAudience;
29  import org.apache.hadoop.classification.InterfaceStability;
30  import org.apache.hadoop.hbase.util.ByteRange;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  /**
34   * Utility methods helpful slinging {@link Cell} instances.
35   */
36  @InterfaceAudience.Private
37  @InterfaceStability.Evolving
38  public final class CellUtil {
39  
40    /******************* ByteRange *******************************/
41  
42    public static ByteRange fillRowRange(Cell cell, ByteRange range) {
43      return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
44    }
45  
46    public static ByteRange fillFamilyRange(Cell cell, ByteRange range) {
47      return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
48    }
49  
50    public static ByteRange fillQualifierRange(Cell cell, ByteRange range) {
51      return range.set(cell.getQualifierArray(), cell.getQualifierOffset(),
52        cell.getQualifierLength());
53    }
54  
55  
56    /***************** get individual arrays for tests ************/
57  
58    public static byte[] getRowArray(Cell cell){
59      byte[] output = new byte[cell.getRowLength()];
60      copyRowTo(cell, output, 0);
61      return output;
62    }
63  
64    public static byte[] getFamilyArray(Cell cell){
65      byte[] output = new byte[cell.getFamilyLength()];
66      copyFamilyTo(cell, output, 0);
67      return output;
68    }
69  
70    public static byte[] getQualifierArray(Cell cell){
71      byte[] output = new byte[cell.getQualifierLength()];
72      copyQualifierTo(cell, output, 0);
73      return output;
74    }
75  
76    public static byte[] getValueArray(Cell cell){
77      byte[] output = new byte[cell.getValueLength()];
78      copyValueTo(cell, output, 0);
79      return output;
80    }
81  
82  
83    /******************** copyTo **********************************/
84  
85    public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) {
86      System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset,
87        cell.getRowLength());
88      return destinationOffset + cell.getRowLength();
89    }
90  
91    public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) {
92      System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination, destinationOffset,
93        cell.getFamilyLength());
94      return destinationOffset + cell.getFamilyLength();
95    }
96  
97    public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) {
98      System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination,
99        destinationOffset, cell.getQualifierLength());
100     return destinationOffset + cell.getQualifierLength();
101   }
102 
103   public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) {
104     System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset,
105       cell.getValueLength());
106     return destinationOffset + cell.getValueLength();
107   }
108 
109 
110   /********************* misc *************************************/
111 
112   public static byte getRowByte(Cell cell, int index) {
113     return cell.getRowArray()[cell.getRowOffset() + index];
114   }
115 
116   public static ByteBuffer getValueBufferShallowCopy(Cell cell) {
117     ByteBuffer buffer = ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(),
118       cell.getValueLength());
119 //    buffer.position(buffer.limit());//make it look as if value was appended
120     return buffer;
121   }
122 
123   public static Cell createCell(final byte [] row, final byte [] family, final byte [] qualifier,
124       final long timestamp, final byte type, final byte [] value) {
125     // I need a Cell Factory here.  Using KeyValue for now. TODO.
126     // TODO: Make a new Cell implementation that just carries these
127     // byte arrays.
128     return new KeyValue(row, family, qualifier, timestamp,
129       KeyValue.Type.codeToType(type), value);
130   }
131 
132   /**
133    * @param cellScannerables
134    * @return CellScanner interface over <code>cellIterables</code>
135    */
136   public static CellScanner createCellScanner(final List<CellScannable> cellScannerables) {
137     return new CellScanner() {
138       private final Iterator<CellScannable> iterator = cellScannerables.iterator();
139       private CellScanner cellScanner = null;
140 
141       @Override
142       public Cell current() {
143         return this.cellScanner != null? this.cellScanner.current(): null;
144       }
145 
146       @Override
147       public boolean advance() throws IOException {
148         if (this.cellScanner == null) {
149           if (!this.iterator.hasNext()) return false;
150           this.cellScanner = this.iterator.next().cellScanner();
151         }
152         if (this.cellScanner.advance()) return true;
153         this.cellScanner = null;
154         return advance();
155       }
156     };
157   }
158 
159   /**
160    * @param cellIterable
161    * @return CellScanner interface over <code>cellIterable</code>
162    */
163   public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) {
164     return createCellScanner(cellIterable.iterator());
165   }
166 
167   /**
168    * @param cells
169    * @return CellScanner interface over <code>cellIterable</code>
170    */
171   public static CellScanner createCellScanner(final Iterator<Cell> cells) {
172     return new CellScanner() {
173       private final Iterator<Cell> iterator = cells;
174       private Cell current = null;
175 
176       @Override
177       public Cell current() {
178         return this.current;
179       }
180 
181       @Override
182       public boolean advance() {
183         boolean hasNext = this.iterator.hasNext();
184         this.current = hasNext? this.iterator.next(): null;
185         return hasNext;
186       }
187     };
188   }
189 
190   /**
191    * @param cellArray
192    * @return CellScanner interface over <code>cellArray</code>
193    */
194   public static CellScanner createCellScanner(final Cell[] cellArray) {
195     return new CellScanner() {
196       private final Cell [] cells = cellArray;
197       private int index = -1;
198 
199       @Override
200       public Cell current() {
201         return (index < 0)? null: this.cells[index];
202       }
203 
204       @Override
205       public boolean advance() {
206         return ++index < this.cells.length;
207       }
208     };
209   }
210 
211   /**
212    * Flatten the map of cells out under the CellScanner
213    * @param map Map of Cell Lists; for example, the map of families to Cells that is used
214    * inside Put, etc., keeping Cells organized by family.
215    * @return CellScanner interface over <code>cellIterable</code>
216    */
217   public static CellScanner createCellScanner(final NavigableMap<byte [],
218       List<Cell>> map) {
219     return new CellScanner() {
220       private final Iterator<Entry<byte[], List<Cell>>> entries =
221           map.entrySet().iterator();
222       private Iterator<Cell> currentIterator = null;
223       private Cell currentCell;
224 
225       @Override
226       public Cell current() {
227         return this.currentCell;
228       }
229 
230       @Override
231       public boolean advance() {
232         if (this.currentIterator == null) {
233           if (!this.entries.hasNext()) return false;
234           this.currentIterator = this.entries.next().getValue().iterator();
235         }
236         if (this.currentIterator.hasNext()) {
237           this.currentCell = this.currentIterator.next();
238           return true;
239         }
240         this.currentCell = null;
241         this.currentIterator = null;
242         return advance();
243       }
244     };
245   }
246 
247   /**
248    * @param left
249    * @param right
250    * @return True if the rows in <code>left</code> and <code>right</code> Cells match
251    */
252   public static boolean matchingRow(final Cell left, final Cell right) {
253     return Bytes.equals(left.getRowArray(),  left.getRowOffset(), left.getRowLength(),
254       right.getRowArray(), right.getRowOffset(), right.getRowLength());
255   }
256 
257   /**
258    * @return True if a delete type, a {@link KeyValue.Type#Delete} or
259    * a {KeyValue.Type#DeleteFamily} or a {@link KeyValue.Type#DeleteColumn}
260    * KeyValue type.
261    */
262   public static boolean isDelete(final Cell cell) {
263     return KeyValue.isDelete(cell.getTypeByte());
264   }
265 
266   /**
267    * @param cell
268    * @return Estimate of the <code>cell</code> size in bytes.
269    */
270   public static int estimatedSizeOf(final Cell cell) {
271     // If a KeyValue, we can give a good estimate of size.
272     if (cell instanceof KeyValue) {
273       return ((KeyValue)cell).getLength() + Bytes.SIZEOF_INT;
274     }
275     // TODO: Should we add to Cell a sizeOf?  Would it help? Does it make sense if Cell is
276     // prefix encoded or compressed?
277     return cell.getRowLength() + cell.getFamilyLength() +
278       cell.getQualifierLength() +
279       cell.getValueLength() +
280       // Use the KeyValue's infrastructure size presuming that another implementation would have
281       // same basic cost.
282       KeyValue.KEY_INFRASTRUCTURE_SIZE +
283       // Serialization is probably preceded by a length (it is in the KeyValueCodec at least).
284       Bytes.SIZEOF_INT;
285   }
286 }