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.KeyValue.Type;
31  import org.apache.hadoop.hbase.util.ByteRange;
32  import org.apache.hadoop.hbase.util.Bytes;
33  
34  /**
35   * Utility methods helpful slinging {@link Cell} instances.
36   */
37  @InterfaceAudience.Public
38  @InterfaceStability.Evolving
39  public final class CellUtil {
40  
41    /******************* ByteRange *******************************/
42  
43    public static ByteRange fillRowRange(Cell cell, ByteRange range) {
44      return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
45    }
46  
47    public static ByteRange fillFamilyRange(Cell cell, ByteRange range) {
48      return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
49    }
50  
51    public static ByteRange fillQualifierRange(Cell cell, ByteRange range) {
52      return range.set(cell.getQualifierArray(), cell.getQualifierOffset(),
53        cell.getQualifierLength());
54    }
55  
56  
57    /***************** get individual arrays for tests ************/
58  
59    public static byte[] cloneRow(Cell cell){
60      byte[] output = new byte[cell.getRowLength()];
61      copyRowTo(cell, output, 0);
62      return output;
63    }
64  
65    public static byte[] cloneFamily(Cell cell){
66      byte[] output = new byte[cell.getFamilyLength()];
67      copyFamilyTo(cell, output, 0);
68      return output;
69    }
70  
71    public static byte[] cloneQualifier(Cell cell){
72      byte[] output = new byte[cell.getQualifierLength()];
73      copyQualifierTo(cell, output, 0);
74      return output;
75    }
76  
77    public static byte[] cloneValue(Cell cell){
78      byte[] output = new byte[cell.getValueLength()];
79      copyValueTo(cell, output, 0);
80      return output;
81    }
82  
83  
84    /******************** copyTo **********************************/
85  
86    public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) {
87      System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset,
88        cell.getRowLength());
89      return destinationOffset + cell.getRowLength();
90    }
91  
92    public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) {
93      System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination, destinationOffset,
94        cell.getFamilyLength());
95      return destinationOffset + cell.getFamilyLength();
96    }
97  
98    public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) {
99      System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination,
100       destinationOffset, cell.getQualifierLength());
101     return destinationOffset + cell.getQualifierLength();
102   }
103 
104   public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) {
105     System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset,
106       cell.getValueLength());
107     return destinationOffset + cell.getValueLength();
108   }
109 
110 
111   /********************* misc *************************************/
112 
113   public static byte getRowByte(Cell cell, int index) {
114     return cell.getRowArray()[cell.getRowOffset() + index];
115   }
116 
117   public static ByteBuffer getValueBufferShallowCopy(Cell cell) {
118     ByteBuffer buffer = ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(),
119       cell.getValueLength());
120     return buffer;
121   }
122 
123   public static ByteBuffer getQualifierBufferShallowCopy(Cell cell) {
124     ByteBuffer buffer = ByteBuffer.wrap(cell.getQualifierArray(), cell.getQualifierOffset(),
125         cell.getQualifierLength());
126     return buffer;
127   }
128 
129   public static Cell createCell(final byte [] row, final byte [] family, final byte [] qualifier,
130       final long timestamp, final byte type, final byte [] value) {
131     // I need a Cell Factory here.  Using KeyValue for now. TODO.
132     // TODO: Make a new Cell implementation that just carries these
133     // byte arrays.
134     return new KeyValue(row, family, qualifier, timestamp,
135       KeyValue.Type.codeToType(type), value);
136   }
137 
138   /**
139    * @param cellScannerables
140    * @return CellScanner interface over <code>cellIterables</code>
141    */
142   public static CellScanner createCellScanner(final List<? extends CellScannable> cellScannerables) {
143     return new CellScanner() {
144       private final Iterator<? extends CellScannable> iterator = cellScannerables.iterator();
145       private CellScanner cellScanner = null;
146 
147       @Override
148       public Cell current() {
149         return this.cellScanner != null? this.cellScanner.current(): null;
150       }
151 
152       @Override
153       public boolean advance() throws IOException {
154         if (this.cellScanner == null) {
155           if (!this.iterator.hasNext()) return false;
156           this.cellScanner = this.iterator.next().cellScanner();
157         }
158         if (this.cellScanner.advance()) return true;
159         this.cellScanner = null;
160         return advance();
161       }
162     };
163   }
164 
165   /**
166    * @param cellIterable
167    * @return CellScanner interface over <code>cellIterable</code>
168    */
169   public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) {
170     if (cellIterable == null) return null;
171     return createCellScanner(cellIterable.iterator());
172   }
173 
174   /**
175    * @param cells
176    * @return CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is
177    * null
178    */
179   public static CellScanner createCellScanner(final Iterator<Cell> cells) {
180     if (cells == null) return null;
181     return new CellScanner() {
182       private final Iterator<Cell> iterator = cells;
183       private Cell current = null;
184 
185       @Override
186       public Cell current() {
187         return this.current;
188       }
189 
190       @Override
191       public boolean advance() {
192         boolean hasNext = this.iterator.hasNext();
193         this.current = hasNext? this.iterator.next(): null;
194         return hasNext;
195       }
196     };
197   }
198 
199   /**
200    * @param cellArray
201    * @return CellScanner interface over <code>cellArray</code>
202    */
203   public static CellScanner createCellScanner(final Cell[] cellArray) {
204     return new CellScanner() {
205       private final Cell [] cells = cellArray;
206       private int index = -1;
207 
208       @Override
209       public Cell current() {
210         if (cells == null) return null;
211         return (index < 0)? null: this.cells[index];
212       }
213 
214       @Override
215       public boolean advance() {
216         if (cells == null) return false;
217         return ++index < this.cells.length;
218       }
219     };
220   }
221 
222   /**
223    * Flatten the map of cells out under the CellScanner
224    * @param map Map of Cell Lists; for example, the map of families to Cells that is used
225    * inside Put, etc., keeping Cells organized by family.
226    * @return CellScanner interface over <code>cellIterable</code>
227    */
228   public static CellScanner createCellScanner(final NavigableMap<byte [],
229       List<Cell>> map) {
230     return new CellScanner() {
231       private final Iterator<Entry<byte[], List<Cell>>> entries =
232           map.entrySet().iterator();
233       private Iterator<Cell> currentIterator = null;
234       private Cell currentCell;
235 
236       @Override
237       public Cell current() {
238         return this.currentCell;
239       }
240 
241       @Override
242       public boolean advance() {
243         if (this.currentIterator == null) {
244           if (!this.entries.hasNext()) return false;
245           this.currentIterator = this.entries.next().getValue().iterator();
246         }
247         if (this.currentIterator.hasNext()) {
248           this.currentCell = this.currentIterator.next();
249           return true;
250         }
251         this.currentCell = null;
252         this.currentIterator = null;
253         return advance();
254       }
255     };
256   }
257 
258   /**
259    * @param left
260    * @param right
261    * @return True if the rows in <code>left</code> and <code>right</code> Cells match
262    */
263   public static boolean matchingRow(final Cell left, final Cell right) {
264     return Bytes.equals(left.getRowArray(),  left.getRowOffset(), left.getRowLength(),
265       right.getRowArray(), right.getRowOffset(), right.getRowLength());
266   }
267 
268   public static boolean matchingRow(final Cell left, final byte[] buf) {
269     return Bytes.equals(left.getRowArray(),  left.getRowOffset(), left.getRowLength(),
270       buf, 0, buf.length);
271   }
272 
273   public static boolean matchingFamily(final Cell left, final Cell right) {
274     return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
275         right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
276   }
277 
278   public static boolean matchingFamily(final Cell left, final byte[] buf) {
279     return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
280         buf, 0, buf.length);
281   }
282 
283   public static boolean matchingQualifier(final Cell left, final Cell right) {
284     return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), left.getQualifierLength(),
285         right.getQualifierArray(), right.getQualifierOffset(), right.getQualifierLength());
286   }
287 
288   public static boolean matchingQualifier(final Cell left, final byte[] buf) {
289     return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), left.getQualifierLength(),
290         buf, 0, buf.length);
291   }
292 
293 
294   public static boolean matchingValue(final Cell left, final Cell right) {
295     return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(),
296         right.getValueArray(), right.getValueOffset(), right.getValueLength());
297   }
298 
299   public static boolean matchingValue(final Cell left, final byte[] buf) {
300     return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(),
301         buf, 0, buf.length);
302   }
303   /**
304    * @return True if a delete type, a {@link KeyValue.Type#Delete} or
305    * a {KeyValue.Type#DeleteFamily} or a {@link KeyValue.Type#DeleteColumn}
306    * KeyValue type.
307    */
308   public static boolean isDelete(final Cell cell) {
309     return KeyValue.isDelete(cell.getTypeByte());
310   }
311 
312   public static boolean isDeleteFamily(final Cell cell) {
313     return cell.getTypeByte() == Type.DeleteFamily.getCode();
314   }
315 
316   /**
317    * @param cell
318    * @return Estimate of the <code>cell</code> size in bytes.
319    */
320   public static int estimatedSizeOf(final Cell cell) {
321     // If a KeyValue, we can give a good estimate of size.
322     if (cell instanceof KeyValue) {
323       return ((KeyValue)cell).getLength() + Bytes.SIZEOF_INT;
324     }
325     // TODO: Should we add to Cell a sizeOf?  Would it help? Does it make sense if Cell is
326     // prefix encoded or compressed?
327     return cell.getRowLength() + cell.getFamilyLength() +
328       cell.getQualifierLength() +
329       cell.getValueLength() +
330       // Use the KeyValue's infrastructure size presuming that another implementation would have
331       // same basic cost.
332       KeyValue.KEY_INFRASTRUCTURE_SIZE +
333       // Serialization is probably preceded by a length (it is in the KeyValueCodec at least).
334       Bytes.SIZEOF_INT;
335   }
336 }