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 static org.apache.hadoop.hbase.HConstants.EMPTY_BYTE_ARRAY;
22  
23  import java.io.DataOutputStream;
24  import java.io.IOException;
25  import java.math.BigDecimal;
26  import java.nio.ByteBuffer;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map.Entry;
30  import java.util.NavigableMap;
31  
32  import org.apache.hadoop.hbase.KeyValue.Type;
33  import org.apache.hadoop.hbase.classification.InterfaceAudience;
34  import org.apache.hadoop.hbase.classification.InterfaceStability;
35  import org.apache.hadoop.hbase.io.HeapSize;
36  import org.apache.hadoop.hbase.util.ByteBufferUtils;
37  import org.apache.hadoop.hbase.util.ByteRange;
38  import org.apache.hadoop.hbase.util.Bytes;
39  
40  /**
41   * Utility methods helpful slinging {@link Cell} instances.
42   * Some methods below are for internal use only and are marked InterfaceAudience.Private at the
43   * method level.
44   */
45  @InterfaceAudience.Public
46  @InterfaceStability.Evolving
47  public final class CellUtil {
48  
49    /**
50     * Private constructor to keep this class from being instantiated.
51     */
52    private CellUtil(){}
53  
54    /******************* ByteRange *******************************/
55  
56    public static ByteRange fillRowRange(Cell cell, ByteRange range) {
57      return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
58    }
59  
60    public static ByteRange fillFamilyRange(Cell cell, ByteRange range) {
61      return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
62    }
63  
64    public static ByteRange fillQualifierRange(Cell cell, ByteRange range) {
65      return range.set(cell.getQualifierArray(), cell.getQualifierOffset(),
66        cell.getQualifierLength());
67    }
68  
69    public static ByteRange fillValueRange(Cell cell, ByteRange range) {
70      return range.set(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
71    }
72  
73    public static ByteRange fillTagRange(Cell cell, ByteRange range) {
74      return range.set(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
75    }
76  
77    /***************** get individual arrays for tests ************/
78  
79    public static byte[] cloneRow(Cell cell){
80      byte[] output = new byte[cell.getRowLength()];
81      copyRowTo(cell, output, 0);
82      return output;
83    }
84  
85    public static byte[] cloneFamily(Cell cell){
86      byte[] output = new byte[cell.getFamilyLength()];
87      copyFamilyTo(cell, output, 0);
88      return output;
89    }
90  
91    public static byte[] cloneQualifier(Cell cell){
92      byte[] output = new byte[cell.getQualifierLength()];
93      copyQualifierTo(cell, output, 0);
94      return output;
95    }
96  
97    public static byte[] cloneValue(Cell cell){
98      byte[] output = new byte[cell.getValueLength()];
99      copyValueTo(cell, output, 0);
100     return output;
101   }
102 
103   public static byte[] cloneTags(Cell cell) {
104     byte[] output = new byte[cell.getTagsLength()];
105     copyTagTo(cell, output, 0);
106     return output;
107   }
108 
109   /**
110    * Returns tag value in a new byte array. If server-side, use
111    * {@link Tag#getBuffer()} with appropriate {@link Tag#getTagOffset()} and
112    * {@link Tag#getTagLength()} instead to save on allocations.
113    * @param cell
114    * @return tag value in a new byte array.
115    */
116   public static byte[] getTagArray(Cell cell){
117     byte[] output = new byte[cell.getTagsLength()];
118     copyTagTo(cell, output, 0);
119     return output;
120   }
121 
122 
123   /******************** copyTo **********************************/
124 
125   public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) {
126     short rowLen = cell.getRowLength();
127     if (cell instanceof ByteBufferedCell) {
128       ByteBufferUtils.copyFromBufferToArray(destination,
129           ((ByteBufferedCell) cell).getRowByteBuffer(),
130           ((ByteBufferedCell) cell).getRowPositionInByteBuffer(), destinationOffset, rowLen);
131     } else {
132       System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset,
133           rowLen);
134     }
135     return destinationOffset + rowLen;
136   }
137 
138   public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) {
139     byte fLen = cell.getFamilyLength();
140     if (cell instanceof ByteBufferedCell) {
141       ByteBufferUtils.copyFromBufferToArray(destination,
142           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
143           ((ByteBufferedCell) cell).getFamilyPositionInByteBuffer(), destinationOffset, fLen);
144     } else {
145       System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination,
146           destinationOffset, fLen);
147     }
148     return destinationOffset + fLen;
149   }
150 
151   public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) {
152     int qlen = cell.getQualifierLength();
153     if (cell instanceof ByteBufferedCell) {
154       ByteBufferUtils.copyFromBufferToArray(destination,
155           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
156           ((ByteBufferedCell) cell).getQualifierPositionInByteBuffer(), destinationOffset, qlen);
157     } else {
158       System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination,
159           destinationOffset, qlen);
160     }
161     return destinationOffset + qlen;
162   }
163 
164   public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) {
165     int vlen = cell.getValueLength();
166     if (cell instanceof ByteBufferedCell) {
167       ByteBufferUtils.copyFromBufferToArray(destination,
168           ((ByteBufferedCell) cell).getValueByteBuffer(),
169           ((ByteBufferedCell) cell).getValuePositionInByteBuffer(), destinationOffset, vlen);
170     } else {
171       System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset,
172           vlen);
173     }
174     return destinationOffset + vlen;
175   }
176 
177   /**
178    * Copies the tags info into the tag portion of the cell
179    * @param cell
180    * @param destination
181    * @param destinationOffset
182    * @return position after tags
183    */
184   public static int copyTagTo(Cell cell, byte[] destination, int destinationOffset) {
185     int tlen = cell.getTagsLength();
186     if (cell instanceof ByteBufferedCell) {
187       ByteBufferUtils.copyFromBufferToArray(destination,
188           ((ByteBufferedCell) cell).getTagsByteBuffer(),
189           ((ByteBufferedCell) cell).getTagsPositionInByteBuffer(), destinationOffset, tlen);
190     } else {
191       System.arraycopy(cell.getTagsArray(), cell.getTagsOffset(), destination, destinationOffset,
192           tlen);
193     }
194     return destinationOffset + tlen;
195   }
196 
197   /********************* misc *************************************/
198 
199   public static byte getRowByte(Cell cell, int index) {
200     if (cell instanceof ByteBufferedCell) {
201       return ((ByteBufferedCell) cell).getRowByteBuffer().get(
202           ((ByteBufferedCell) cell).getRowPositionInByteBuffer() + index);
203     }
204     return cell.getRowArray()[cell.getRowOffset() + index];
205   }
206 
207   public static ByteBuffer getValueBufferShallowCopy(Cell cell) {
208     ByteBuffer buffer = ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(),
209       cell.getValueLength());
210     return buffer;
211   }
212 
213   /**
214    * @param cell
215    * @return cell's qualifier wrapped into a ByteBuffer.
216    * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
217    */
218   @Deprecated
219   public static ByteBuffer getQualifierBufferShallowCopy(Cell cell) {
220     // No usage of this in code.
221     ByteBuffer buffer = ByteBuffer.wrap(cell.getQualifierArray(), cell.getQualifierOffset(),
222         cell.getQualifierLength());
223     return buffer;
224   }
225 
226   public static Cell createCell(final byte [] row, final byte [] family, final byte [] qualifier,
227       final long timestamp, final byte type, final byte [] value) {
228     // I need a Cell Factory here.  Using KeyValue for now. TODO.
229     // TODO: Make a new Cell implementation that just carries these
230     // byte arrays.
231     // TODO: Call factory to create Cell
232     return new KeyValue(row, family, qualifier, timestamp, KeyValue.Type.codeToType(type), value);
233   }
234 
235   public static Cell createCell(final byte [] rowArray, final int rowOffset, final int rowLength,
236       final byte [] familyArray, final int familyOffset, final int familyLength,
237       final byte [] qualifierArray, final int qualifierOffset, final int qualifierLength) {
238     // See createCell(final byte [] row, final byte [] value) for why we default Maximum type.
239     return new KeyValue(rowArray, rowOffset, rowLength,
240         familyArray, familyOffset, familyLength,
241         qualifierArray, qualifierOffset, qualifierLength,
242         HConstants.LATEST_TIMESTAMP,
243         KeyValue.Type.Maximum,
244         HConstants.EMPTY_BYTE_ARRAY, 0, HConstants.EMPTY_BYTE_ARRAY.length);
245   }
246 
247   /**
248    * Marked as audience Private as of 1.2.0.
249    * Creating a Cell with a memstoreTS/mvcc is an internal implementation detail not for
250    * public use.
251    */
252   @InterfaceAudience.Private
253   public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
254       final long timestamp, final byte type, final byte[] value, final long memstoreTS) {
255     KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
256         KeyValue.Type.codeToType(type), value);
257     keyValue.setSequenceId(memstoreTS);
258     return keyValue;
259   }
260 
261   /**
262    * Marked as audience Private as of 1.2.0.
263    * Creating a Cell with tags and a memstoreTS/mvcc is an internal implementation detail not for
264    * public use.
265    */
266   @InterfaceAudience.Private
267   public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
268       final long timestamp, final byte type, final byte[] value, byte[] tags,
269       final long memstoreTS) {
270     KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
271         KeyValue.Type.codeToType(type), value, tags);
272     keyValue.setSequenceId(memstoreTS);
273     return keyValue;
274   }
275 
276   /**
277    * Marked as audience Private as of 1.2.0.
278    * Creating a Cell with tags is an internal implementation detail not for
279    * public use.
280    */
281   @InterfaceAudience.Private
282   public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
283       final long timestamp, Type type, final byte[] value, byte[] tags) {
284     KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp, type, value, tags);
285     return keyValue;
286   }
287 
288   /**
289    * Create a Cell with specific row.  Other fields defaulted.
290    * @param row
291    * @return Cell with passed row but all other fields are arbitrary
292    */
293   public static Cell createCell(final byte [] row) {
294     return createCell(row, HConstants.EMPTY_BYTE_ARRAY);
295   }
296 
297   /**
298    * Create a Cell with specific row and value.  Other fields are defaulted.
299    * @param row
300    * @param value
301    * @return Cell with passed row and value but all other fields are arbitrary
302    */
303   public static Cell createCell(final byte [] row, final byte [] value) {
304     // An empty family + empty qualifier + Type.Minimum is used as flag to indicate last on row.
305     // See the CellComparator and KeyValue comparator.  Search for compareWithoutRow.
306     // Lets not make a last-on-row key as default but at same time, if you are making a key
307     // without specifying type, etc., flag it as weird by setting type to be Maximum.
308     return createCell(row, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
309       HConstants.LATEST_TIMESTAMP, KeyValue.Type.Maximum.getCode(), value);
310   }
311 
312   /**
313    * Create a Cell with specific row.  Other fields defaulted.
314    * @param row
315    * @param family
316    * @param qualifier
317    * @return Cell with passed row but all other fields are arbitrary
318    */
319   public static Cell createCell(final byte [] row, final byte [] family, final byte [] qualifier) {
320     // See above in createCell(final byte [] row, final byte [] value) why we set type to Maximum.
321     return createCell(row, family, qualifier,
322         HConstants.LATEST_TIMESTAMP, KeyValue.Type.Maximum.getCode(), HConstants.EMPTY_BYTE_ARRAY);
323   }
324 
325   /**
326    * @param cellScannerables
327    * @return CellScanner interface over <code>cellIterables</code>
328    */
329   public static CellScanner createCellScanner(
330       final List<? extends CellScannable> cellScannerables) {
331     return new CellScanner() {
332       private final Iterator<? extends CellScannable> iterator = cellScannerables.iterator();
333       private CellScanner cellScanner = null;
334 
335       @Override
336       public Cell current() {
337         return this.cellScanner != null? this.cellScanner.current(): null;
338       }
339 
340       @Override
341       public boolean advance() throws IOException {
342         while (true) {
343           if (this.cellScanner == null) {
344             if (!this.iterator.hasNext()) return false;
345             this.cellScanner = this.iterator.next().cellScanner();
346           }
347           if (this.cellScanner.advance()) return true;
348           this.cellScanner = null;
349         }
350       }
351     };
352   }
353 
354   /**
355    * @param cellIterable
356    * @return CellScanner interface over <code>cellIterable</code>
357    */
358   public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) {
359     if (cellIterable == null) return null;
360     return createCellScanner(cellIterable.iterator());
361   }
362 
363   /**
364    * @param cells
365    * @return CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is
366    * null
367    */
368   public static CellScanner createCellScanner(final Iterator<Cell> cells) {
369     if (cells == null) return null;
370     return new CellScanner() {
371       private final Iterator<Cell> iterator = cells;
372       private Cell current = null;
373 
374       @Override
375       public Cell current() {
376         return this.current;
377       }
378 
379       @Override
380       public boolean advance() {
381         boolean hasNext = this.iterator.hasNext();
382         this.current = hasNext? this.iterator.next(): null;
383         return hasNext;
384       }
385     };
386   }
387 
388   /**
389    * @param cellArray
390    * @return CellScanner interface over <code>cellArray</code>
391    */
392   public static CellScanner createCellScanner(final Cell[] cellArray) {
393     return new CellScanner() {
394       private final Cell [] cells = cellArray;
395       private int index = -1;
396 
397       @Override
398       public Cell current() {
399         if (cells == null) return null;
400         return (index < 0)? null: this.cells[index];
401       }
402 
403       @Override
404       public boolean advance() {
405         if (cells == null) return false;
406         return ++index < this.cells.length;
407       }
408     };
409   }
410 
411   /**
412    * Flatten the map of cells out under the CellScanner
413    * @param map Map of Cell Lists; for example, the map of families to Cells that is used
414    * inside Put, etc., keeping Cells organized by family.
415    * @return CellScanner interface over <code>cellIterable</code>
416    */
417   public static CellScanner createCellScanner(final NavigableMap<byte [], List<Cell>> map) {
418     return new CellScanner() {
419       private final Iterator<Entry<byte[], List<Cell>>> entries = map.entrySet().iterator();
420       private Iterator<Cell> currentIterator = null;
421       private Cell currentCell;
422 
423       @Override
424       public Cell current() {
425         return this.currentCell;
426       }
427 
428       @Override
429       public boolean advance() {
430         while(true) {
431           if (this.currentIterator == null) {
432             if (!this.entries.hasNext()) return false;
433             this.currentIterator = this.entries.next().getValue().iterator();
434           }
435           if (this.currentIterator.hasNext()) {
436             this.currentCell = this.currentIterator.next();
437             return true;
438           }
439           this.currentCell = null;
440           this.currentIterator = null;
441         }
442       }
443     };
444   }
445 
446   /**
447    * @param left
448    * @param right
449    * @return True if the rows in <code>left</code> and <code>right</code> Cells match
450    * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
451    *             Instead use {@link #matchingRows(Cell, Cell)}
452    */
453   @Deprecated
454   public static boolean matchingRow(final Cell left, final Cell right) {
455     return matchingRows(left, right);
456   }
457 
458   public static boolean matchingRow(final Cell left, final byte[] buf) {
459     if (buf == null) {
460       return left.getQualifierLength() == 0;
461     }
462     return matchingRow(left, buf, 0, buf.length);
463   }
464 
465   public static boolean matchingRow(final Cell left, final byte[] buf, final int offset,
466       final int length) {
467     if (left instanceof ByteBufferedCell) {
468       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getRowByteBuffer(),
469           ((ByteBufferedCell) left).getRowPositionInByteBuffer(), left.getRowLength(), buf, offset,
470           length) == 0;
471     }
472     return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, offset,
473         length);
474   }
475 
476   public static boolean matchingFamily(final Cell left, final Cell right) {
477     byte lfamlength = left.getFamilyLength();
478     byte rfamlength = right.getFamilyLength();
479     if (lfamlength != rfamlength) return false;
480     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
481       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getFamilyByteBuffer(),
482           ((ByteBufferedCell) left).getFamilyPositionInByteBuffer(), lfamlength,
483           ((ByteBufferedCell) right).getFamilyByteBuffer(),
484           ((ByteBufferedCell) right).getFamilyPositionInByteBuffer(), rfamlength) == 0;
485     }
486     if (left instanceof ByteBufferedCell) {
487       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getFamilyByteBuffer(),
488           ((ByteBufferedCell) left).getFamilyPositionInByteBuffer(), lfamlength,
489           right.getFamilyArray(), right.getFamilyOffset(), rfamlength) == 0;
490     }
491     if (right instanceof ByteBufferedCell) {
492       return ByteBufferUtils.compareTo(((ByteBufferedCell) right).getFamilyByteBuffer(),
493           ((ByteBufferedCell) right).getFamilyPositionInByteBuffer(), rfamlength,
494           left.getFamilyArray(), left.getFamilyOffset(), lfamlength) == 0;
495     }
496     return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
497         right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
498   }
499 
500   public static boolean matchingFamily(final Cell left, final byte[] buf) {
501     if (buf == null) {
502       return left.getFamilyLength() == 0;
503     }
504     return matchingFamily(left, buf, 0, buf.length);
505   }
506 
507   public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset,
508       final int length) {
509     if (left instanceof ByteBufferedCell) {
510       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getFamilyByteBuffer(),
511           ((ByteBufferedCell) left).getFamilyPositionInByteBuffer(), left.getFamilyLength(), buf,
512           offset, length) == 0;
513     }
514     return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf,
515         offset, length);
516   }
517 
518   public static boolean matchingQualifier(final Cell left, final Cell right) {
519     int lqlength = left.getQualifierLength();
520     int rqlength = right.getQualifierLength();
521     if (lqlength != rqlength) return false;
522     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
523       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getQualifierByteBuffer(),
524           ((ByteBufferedCell) left).getQualifierPositionInByteBuffer(), lqlength,
525           ((ByteBufferedCell) right).getQualifierByteBuffer(),
526           ((ByteBufferedCell) right).getQualifierPositionInByteBuffer(), rqlength) == 0;
527     }
528     if (left instanceof ByteBufferedCell) {
529       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getQualifierByteBuffer(),
530           ((ByteBufferedCell) left).getQualifierPositionInByteBuffer(), lqlength,
531           right.getQualifierArray(), right.getQualifierOffset(), rqlength) == 0;
532     }
533     if (right instanceof ByteBufferedCell) {
534       return ByteBufferUtils.compareTo(((ByteBufferedCell) right).getQualifierByteBuffer(),
535           ((ByteBufferedCell) right).getQualifierPositionInByteBuffer(), rqlength,
536           left.getQualifierArray(), left.getQualifierOffset(), lqlength) == 0;
537     }
538     return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
539         left.getQualifierLength(), right.getQualifierArray(), right.getQualifierOffset(),
540         right.getQualifierLength());
541   }
542 
543   /**
544    * Finds if the qualifier part of the cell and the KV serialized
545    * byte[] are equal
546    * @param left
547    * @param buf the serialized keyvalue format byte[]
548    * @return true if the qualifier matches, false otherwise
549    */
550   public static boolean matchingQualifier(final Cell left, final byte[] buf) {
551     if (buf == null) {
552       return left.getQualifierLength() == 0;
553     }
554     return matchingQualifier(left, buf, 0, buf.length);
555   }
556 
557   /**
558    * Finds if the qualifier part of the cell and the KV serialized
559    * byte[] are equal
560    * @param left
561    * @param buf the serialized keyvalue format byte[]
562    * @param offset the offset of the qualifier in the byte[]
563    * @param length the length of the qualifier in the byte[]
564    * @return true if the qualifier matches, false otherwise
565    */
566   public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset,
567       final int length) {
568     if (buf == null) {
569       return left.getQualifierLength() == 0;
570     }
571     if (left instanceof ByteBufferedCell) {
572       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getQualifierByteBuffer(),
573           ((ByteBufferedCell) left).getQualifierPositionInByteBuffer(), left.getQualifierLength(),
574           buf, offset, length) == 0;
575     }
576     return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
577         left.getQualifierLength(), buf, offset, length);
578   }
579 
580   public static boolean matchingColumn(final Cell left, final byte[] fam, final byte[] qual) {
581     if (!matchingFamily(left, fam))
582       return false;
583     return matchingQualifier(left, qual);
584   }
585 
586   public static boolean matchingColumn(final Cell left, final byte[] fam, final int foffset,
587       final int flength, final byte[] qual, final int qoffset, final int qlength) {
588     if (!matchingFamily(left, fam, foffset, flength))
589       return false;
590     return matchingQualifier(left, qual, qoffset, qlength);
591   }
592 
593   public static boolean matchingColumn(final Cell left, final Cell right) {
594     if (!matchingFamily(left, right))
595       return false;
596     return matchingQualifier(left, right);
597   }
598 
599   public static boolean matchingValue(final Cell left, final Cell right) {
600     int lvlength = left.getValueLength();
601     int rvlength = right.getValueLength();
602     if (lvlength != rvlength) return false;
603     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
604       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getValueByteBuffer(),
605           ((ByteBufferedCell) left).getValuePositionInByteBuffer(), lvlength,
606           ((ByteBufferedCell) right).getValueByteBuffer(),
607           ((ByteBufferedCell) right).getValuePositionInByteBuffer(), rvlength) == 0;
608     }
609     if (left instanceof ByteBufferedCell) {
610       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getValueByteBuffer(),
611           ((ByteBufferedCell) left).getValuePositionInByteBuffer(), lvlength,
612           right.getValueArray(), right.getValueOffset(), rvlength) == 0;
613     }
614     if (right instanceof ByteBufferedCell) {
615       return ByteBufferUtils.compareTo(((ByteBufferedCell) right).getValueByteBuffer(),
616           ((ByteBufferedCell) right).getValuePositionInByteBuffer(), rvlength,
617           left.getValueArray(), left.getValueOffset(), lvlength) == 0;
618     }
619     return Bytes.equals(left.getValueArray(), left.getValueOffset(), lvlength,
620         right.getValueArray(), right.getValueOffset(), rvlength);
621   }
622 
623   public static boolean matchingValue(final Cell left, final byte[] buf) {
624     if (left instanceof ByteBufferedCell) {
625       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getValueByteBuffer(),
626           ((ByteBufferedCell) left).getValuePositionInByteBuffer(), left.getValueLength(), buf, 0,
627           buf.length) == 0;
628     }
629     return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(), buf, 0,
630         buf.length);
631   }
632 
633   /**
634    * @return True if a delete type, a {@link KeyValue.Type#Delete} or a
635    *         {KeyValue.Type#DeleteFamily} or a
636    *         {@link KeyValue.Type#DeleteColumn} KeyValue type.
637    */
638   public static boolean isDelete(final Cell cell) {
639     return isDelete(cell.getTypeByte());
640   }
641 
642   /**
643    * @return True if a delete type, a {@link KeyValue.Type#Delete} or a
644    *         {KeyValue.Type#DeleteFamily} or a
645    *         {@link KeyValue.Type#DeleteColumn} KeyValue type.
646    */
647   public static boolean isDelete(final byte type) {
648     return Type.Delete.getCode() <= type
649         && type <= Type.DeleteFamily.getCode();
650   }
651 
652   /**
653    * @return True if this cell is a {@link KeyValue.Type#Delete} type.
654    */
655   public static boolean isDeleteType(Cell cell) {
656     return cell.getTypeByte() == Type.Delete.getCode();
657   }
658 
659   public static boolean isDeleteFamily(final Cell cell) {
660     return cell.getTypeByte() == Type.DeleteFamily.getCode();
661   }
662 
663   public static boolean isDeleteFamilyVersion(final Cell cell) {
664     return cell.getTypeByte() == Type.DeleteFamilyVersion.getCode();
665   }
666 
667   public static boolean isDeleteColumns(final Cell cell) {
668     return cell.getTypeByte() == Type.DeleteColumn.getCode();
669   }
670 
671   public static boolean isDeleteColumnVersion(final Cell cell) {
672     return cell.getTypeByte() == Type.Delete.getCode();
673   }
674 
675   /**
676    *
677    * @return True if this cell is a delete family or column type.
678    */
679   public static boolean isDeleteColumnOrFamily(Cell cell) {
680     int t = cell.getTypeByte();
681     return t == Type.DeleteColumn.getCode() || t == Type.DeleteFamily.getCode();
682   }
683 
684   /**
685    * @param cell
686    * @return Estimate of the <code>cell</code> size in bytes.
687    */
688   public static int estimatedSerializedSizeOf(final Cell cell) {
689     // If a KeyValue, we can give a good estimate of size.
690     if (cell instanceof KeyValue) {
691       return ((KeyValue)cell).getLength() + Bytes.SIZEOF_INT;
692     }
693     // TODO: Should we add to Cell a sizeOf?  Would it help? Does it make sense if Cell is
694     // prefix encoded or compressed?
695     return getSumOfCellElementLengths(cell) +
696       // Use the KeyValue's infrastructure size presuming that another implementation would have
697       // same basic cost.
698       KeyValue.KEY_INFRASTRUCTURE_SIZE +
699       // Serialization is probably preceded by a length (it is in the KeyValueCodec at least).
700       Bytes.SIZEOF_INT;
701   }
702 
703   /**
704    * @param cell
705    * @return Sum of the lengths of all the elements in a Cell; does not count in any infrastructure
706    */
707   private static int getSumOfCellElementLengths(final Cell cell) {
708     return getSumOfCellKeyElementLengths(cell) + cell.getValueLength() + cell.getTagsLength();
709   }
710 
711   /**
712    * @param cell
713    * @return Sum of all elements that make up a key; does not include infrastructure, tags or
714    * values.
715    */
716   private static int getSumOfCellKeyElementLengths(final Cell cell) {
717     return cell.getRowLength() + cell.getFamilyLength() +
718     cell.getQualifierLength() +
719     KeyValue.TIMESTAMP_TYPE_SIZE;
720   }
721 
722   public static int estimatedSerializedSizeOfKey(final Cell cell) {
723     if (cell instanceof KeyValue) return ((KeyValue)cell).getKeyLength();
724     // This will be a low estimate.  Will do for now.
725     return getSumOfCellKeyElementLengths(cell);
726   }
727 
728   /**
729    * This is an estimate of the heap space occupied by a cell. When the cell is of type
730    * {@link HeapSize} we call {@link HeapSize#heapSize()} so cell can give a correct value. In other
731    * cases we just consider the bytes occupied by the cell components ie. row, CF, qualifier,
732    * timestamp, type, value and tags.
733    * @param cell
734    * @return estimate of the heap space
735    */
736   public static long estimatedHeapSizeOf(final Cell cell) {
737     if (cell instanceof HeapSize) {
738       return ((HeapSize) cell).heapSize();
739     }
740     // TODO: Add sizing of references that hold the row, family, etc., arrays.
741     return estimatedSerializedSizeOf(cell);
742   }
743 
744   /********************* tags *************************************/
745   /**
746    * Util method to iterate through the tags
747    *
748    * @param tags
749    * @param offset
750    * @param length
751    * @return iterator for the tags
752    */
753   public static Iterator<Tag> tagsIterator(final byte[] tags, final int offset, final int length) {
754     return new Iterator<Tag>() {
755       private int pos = offset;
756       private int endOffset = offset + length - 1;
757 
758       @Override
759       public boolean hasNext() {
760         return this.pos < endOffset;
761       }
762 
763       @Override
764       public Tag next() {
765         if (hasNext()) {
766           int curTagLen = Bytes.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE);
767           Tag tag = new Tag(tags, pos, curTagLen + Tag.TAG_LENGTH_SIZE);
768           this.pos += Bytes.SIZEOF_SHORT + curTagLen;
769           return tag;
770         }
771         return null;
772       }
773 
774       @Override
775       public void remove() {
776         throw new UnsupportedOperationException();
777       }
778     };
779   }
780 
781   /**
782    * Returns true if the first range start1...end1 overlaps with the second range
783    * start2...end2, assuming the byte arrays represent row keys
784    */
785   public static boolean overlappingKeys(final byte[] start1, final byte[] end1,
786       final byte[] start2, final byte[] end2) {
787     return (end2.length == 0 || start1.length == 0 || Bytes.compareTo(start1,
788         end2) < 0)
789         && (end1.length == 0 || start2.length == 0 || Bytes.compareTo(start2,
790             end1) < 0);
791   }
792 
793   /**
794    * Sets the given seqId to the cell.
795    * Marked as audience Private as of 1.2.0.
796    * Setting a Cell sequenceid is an internal implementation detail not for general public use.
797    * @param cell
798    * @param seqId
799    * @throws IOException when the passed cell is not of type {@link SettableSequenceId}
800    */
801   @InterfaceAudience.Private
802   public static void setSequenceId(Cell cell, long seqId) throws IOException {
803     if (cell instanceof SettableSequenceId) {
804       ((SettableSequenceId) cell).setSequenceId(seqId);
805     } else {
806       throw new IOException(new UnsupportedOperationException("Cell is not of type "
807           + SettableSequenceId.class.getName()));
808     }
809   }
810 
811   /**
812    * Sets the given timestamp to the cell.
813    * @param cell
814    * @param ts
815    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
816    */
817   public static void setTimestamp(Cell cell, long ts) throws IOException {
818     if (cell instanceof SettableTimestamp) {
819       ((SettableTimestamp) cell).setTimestamp(ts);
820     } else {
821       throw new IOException(new UnsupportedOperationException("Cell is not of type "
822           + SettableTimestamp.class.getName()));
823     }
824   }
825 
826   /**
827    * Sets the given timestamp to the cell.
828    * @param cell
829    * @param ts buffer containing the timestamp value
830    * @param tsOffset offset to the new timestamp
831    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
832    */
833   public static void setTimestamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
834     if (cell instanceof SettableTimestamp) {
835       ((SettableTimestamp) cell).setTimestamp(ts, tsOffset);
836     } else {
837       throw new IOException(new UnsupportedOperationException("Cell is not of type "
838           + SettableTimestamp.class.getName()));
839     }
840   }
841 
842   /**
843    * Sets the given timestamp to the cell iff current timestamp is
844    * {@link HConstants#LATEST_TIMESTAMP}.
845    * @param cell
846    * @param ts
847    * @return True if cell timestamp is modified.
848    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
849    */
850   public static boolean updateLatestStamp(Cell cell, long ts) throws IOException {
851     if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
852       setTimestamp(cell, ts);
853       return true;
854     }
855     return false;
856   }
857 
858   /**
859    * Sets the given timestamp to the cell iff current timestamp is
860    * {@link HConstants#LATEST_TIMESTAMP}.
861    * @param cell
862    * @param ts buffer containing the timestamp value
863    * @param tsOffset offset to the new timestamp
864    * @return True if cell timestamp is modified.
865    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
866    */
867   public static boolean updateLatestStamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
868     if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
869       setTimestamp(cell, ts, tsOffset);
870       return true;
871     }
872     return false;
873   }
874 
875   /**
876    * Writes the Cell's key part as it would have serialized in a KeyValue. The format is &lt;2 bytes
877    * rk len&gt;&lt;rk&gt;&lt;1 byte cf len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes
878    * timestamp&gt;&lt;1 byte type&gt;
879    * @param cell
880    * @param out
881    * @throws IOException
882    */
883   public static void writeFlatKey(Cell cell, DataOutputStream out) throws IOException {
884     short rowLen = cell.getRowLength();
885     out.writeShort(rowLen);
886     out.write(cell.getRowArray(), cell.getRowOffset(), rowLen);
887     byte fLen = cell.getFamilyLength();
888     out.writeByte(fLen);
889     out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen);
890     out.write(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
891     out.writeLong(cell.getTimestamp());
892     out.writeByte(cell.getTypeByte());
893   }
894 
895   /**
896    * @param cell
897    * @return The Key portion of the passed <code>cell</code> as a String.
898    */
899   public static String getCellKeyAsString(Cell cell) {
900     StringBuilder sb = new StringBuilder(Bytes.toStringBinary(
901       cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
902     sb.append('/');
903     sb.append(cell.getFamilyLength() == 0? "":
904       Bytes.toStringBinary(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
905     // KeyValue only added ':' if family is non-null.  Do same.
906     if (cell.getFamilyLength() > 0) sb.append(':');
907     sb.append(cell.getQualifierLength() == 0? "":
908       Bytes.toStringBinary(cell.getQualifierArray(), cell.getQualifierOffset(),
909         cell.getQualifierLength()));
910     sb.append('/');
911     sb.append(KeyValue.humanReadableTimestamp(cell.getTimestamp()));
912     sb.append('/');
913     sb.append(Type.codeToType(cell.getTypeByte()));
914     if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
915       sb.append("/vlen=");
916       sb.append(cell.getValueLength());
917     }
918     sb.append("/seqid=");
919     sb.append(cell.getSequenceId());
920     return sb.toString();
921   }
922 
923   /**
924    * This method exists just to encapsulate how we serialize keys.  To be replaced by a factory
925    * that we query to figure what the Cell implementation is and then, what serialization engine
926    * to use and further, how to serialize the key for inclusion in hfile index. TODO.
927    * @param cell
928    * @return The key portion of the Cell serialized in the old-school KeyValue way or null if
929    * passed a null <code>cell</code>
930    */
931   public static byte [] getCellKeySerializedAsKeyValueKey(final Cell cell) {
932     if (cell == null) return null;
933     byte [] b = new byte[KeyValueUtil.keyLength(cell)];
934     KeyValueUtil.appendKeyTo(cell, b, 0);
935     return b;
936   }
937 
938   /**
939    * Write rowkey excluding the common part.
940    * @param cell
941    * @param rLen
942    * @param commonPrefix
943    * @param out
944    * @throws IOException
945    */
946   public static void writeRowKeyExcludingCommon(Cell cell, short rLen, int commonPrefix,
947       DataOutputStream out) throws IOException {
948     if (commonPrefix == 0) {
949       out.writeShort(rLen);
950     } else if (commonPrefix == 1) {
951       out.writeByte((byte) rLen);
952       commonPrefix--;
953     } else {
954       commonPrefix -= KeyValue.ROW_LENGTH_SIZE;
955     }
956     if (rLen > commonPrefix) {
957       out.write(cell.getRowArray(), cell.getRowOffset() + commonPrefix, rLen - commonPrefix);
958     }
959   }
960 
961   /**
962    * Find length of common prefix in keys of the cells, considering key as byte[] if serialized in
963    * {@link KeyValue}. The key format is &lt;2 bytes rk len&gt;&lt;rk&gt;&lt;1 byte cf
964    * len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes timestamp&gt;&lt;1 byte type&gt;
965    * @param c1
966    *          the cell
967    * @param c2
968    *          the cell
969    * @param bypassFamilyCheck
970    *          when true assume the family bytes same in both cells. Pass it as true when dealing
971    *          with Cells in same CF so as to avoid some checks
972    * @param withTsType
973    *          when true check timestamp and type bytes also.
974    * @return length of common prefix
975    */
976   public static int findCommonPrefixInFlatKey(Cell c1, Cell c2, boolean bypassFamilyCheck,
977       boolean withTsType) {
978     // Compare the 2 bytes in RK length part
979     short rLen1 = c1.getRowLength();
980     short rLen2 = c2.getRowLength();
981     int commonPrefix = KeyValue.ROW_LENGTH_SIZE;
982     if (rLen1 != rLen2) {
983       // early out when the RK length itself is not matching
984       return ByteBufferUtils.findCommonPrefix(Bytes.toBytes(rLen1), 0, KeyValue.ROW_LENGTH_SIZE,
985           Bytes.toBytes(rLen2), 0, KeyValue.ROW_LENGTH_SIZE);
986     }
987     // Compare the RKs
988     int rkCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getRowArray(), c1.getRowOffset(),
989         rLen1, c2.getRowArray(), c2.getRowOffset(), rLen2);
990     commonPrefix += rkCommonPrefix;
991     if (rkCommonPrefix != rLen1) {
992       // Early out when RK is not fully matching.
993       return commonPrefix;
994     }
995     // Compare 1 byte CF length part
996     byte fLen1 = c1.getFamilyLength();
997     if (bypassFamilyCheck) {
998       // This flag will be true when caller is sure that the family will be same for both the cells
999       // Just make commonPrefix to increment by the family part
1000       commonPrefix += KeyValue.FAMILY_LENGTH_SIZE + fLen1;
1001     } else {
1002       byte fLen2 = c2.getFamilyLength();
1003       if (fLen1 != fLen2) {
1004         // early out when the CF length itself is not matching
1005         return commonPrefix;
1006       }
1007       // CF lengths are same so there is one more byte common in key part
1008       commonPrefix += KeyValue.FAMILY_LENGTH_SIZE;
1009       // Compare the CF names
1010       int fCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getFamilyArray(),
1011           c1.getFamilyOffset(), fLen1, c2.getFamilyArray(), c2.getFamilyOffset(), fLen2);
1012       commonPrefix += fCommonPrefix;
1013       if (fCommonPrefix != fLen1) {
1014         return commonPrefix;
1015       }
1016     }
1017     // Compare the Qualifiers
1018     int qLen1 = c1.getQualifierLength();
1019     int qLen2 = c2.getQualifierLength();
1020     int qCommon = ByteBufferUtils.findCommonPrefix(c1.getQualifierArray(), c1.getQualifierOffset(),
1021         qLen1, c2.getQualifierArray(), c2.getQualifierOffset(), qLen2);
1022     commonPrefix += qCommon;
1023     if (!withTsType || Math.max(qLen1, qLen2) != qCommon) {
1024       return commonPrefix;
1025     }
1026     // Compare the timestamp parts
1027     int tsCommonPrefix = ByteBufferUtils.findCommonPrefix(Bytes.toBytes(c1.getTimestamp()), 0,
1028         KeyValue.TIMESTAMP_SIZE, Bytes.toBytes(c2.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE);
1029     commonPrefix += tsCommonPrefix;
1030     if (tsCommonPrefix != KeyValue.TIMESTAMP_SIZE) {
1031       return commonPrefix;
1032     }
1033     // Compare the type
1034     if (c1.getTypeByte() == c2.getTypeByte()) {
1035       commonPrefix += KeyValue.TYPE_SIZE;
1036     }
1037     return commonPrefix;
1038   }
1039 
1040   /** Returns a string representation of the cell */
1041   public static String toString(Cell cell, boolean verbose) {
1042     if (cell == null) {
1043       return "";
1044     }
1045     StringBuilder builder = new StringBuilder();
1046     String keyStr = getCellKeyAsString(cell);
1047 
1048     String tag = null;
1049     String value = null;
1050     if (verbose) {
1051       // TODO: pretty print tags as well
1052       if (cell.getTagsLength() > 0) {
1053         tag = Bytes.toStringBinary(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
1054       }
1055       if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
1056         value = Bytes.toStringBinary(cell.getValueArray(), cell.getValueOffset(),
1057             cell.getValueLength());
1058       }
1059     }
1060 
1061     builder
1062       .append(keyStr);
1063     if (tag != null && !tag.isEmpty()) {
1064       builder.append("/").append(tag);
1065     }
1066     if (value != null) {
1067       builder.append("/").append(value);
1068     }
1069 
1070     return builder.toString();
1071   }
1072 
1073   /***************** special cases ****************************/
1074 
1075   /**
1076    * special case for Cell.equals
1077    */
1078   public static boolean equalsIgnoreMvccVersion(Cell a, Cell b) {
1079     // row
1080     boolean res = matchingRow(a, b);
1081     if (!res)
1082       return res;
1083 
1084     // family
1085     res = matchingColumn(a, b);
1086     if (!res)
1087       return res;
1088 
1089     // timestamp: later sorts first
1090     if (!matchingTimestamp(a, b))
1091       return false;
1092 
1093     // type
1094     int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
1095     if (c != 0)
1096       return false;
1097     else return true;
1098   }
1099 
1100   /**************** equals ****************************/
1101 
1102   public static boolean equals(Cell a, Cell b) {
1103     return matchingRow(a, b) && matchingFamily(a, b) && matchingQualifier(a, b)
1104         && matchingTimestamp(a, b) && matchingType(a, b);
1105   }
1106 
1107   public static boolean matchingTimestamp(Cell a, Cell b) {
1108     return CellComparator.compareTimestamps(a.getTimestamp(), b.getTimestamp()) == 0;
1109   }
1110 
1111   public static boolean matchingType(Cell a, Cell b) {
1112     return a.getTypeByte() == b.getTypeByte();
1113   }
1114 
1115   /**
1116    * Compares the row of two keyvalues for equality
1117    * 
1118    * @param left
1119    * @param right
1120    * @return True if rows match.
1121    */
1122   public static boolean matchingRows(final Cell left, final Cell right) {
1123     short lrowlength = left.getRowLength();
1124     short rrowlength = right.getRowLength();
1125     if (lrowlength != rrowlength) return false;
1126     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
1127       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getRowByteBuffer(),
1128           ((ByteBufferedCell) left).getRowPositionInByteBuffer(), lrowlength,
1129           ((ByteBufferedCell) right).getRowByteBuffer(),
1130           ((ByteBufferedCell) right).getRowPositionInByteBuffer(), rrowlength) == 0;
1131     }
1132     if (left instanceof ByteBufferedCell) {
1133       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getRowByteBuffer(),
1134           ((ByteBufferedCell) left).getRowPositionInByteBuffer(), lrowlength, right.getRowArray(),
1135           right.getRowOffset(), rrowlength) == 0;
1136     }
1137     if (right instanceof ByteBufferedCell) {
1138       return ByteBufferUtils.compareTo(((ByteBufferedCell) right).getRowByteBuffer(),
1139           ((ByteBufferedCell) right).getRowPositionInByteBuffer(), rrowlength, left.getRowArray(),
1140           left.getRowOffset(), lrowlength) == 0;
1141     }
1142     return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(),
1143         right.getRowArray(), right.getRowOffset(), right.getRowLength());
1144   }
1145 
1146   /**
1147    * Compares the row and column of two keyvalues for equality
1148    *
1149    * @param left
1150    * @param right
1151    * @return True if same row and column.
1152    */
1153   public static boolean matchingRowColumn(final Cell left, final Cell right) {
1154     if ((left.getRowLength() + left.getFamilyLength() + left.getQualifierLength()) != (right
1155         .getRowLength() + right.getFamilyLength() + right.getQualifierLength())) {
1156       return false;
1157     }
1158 
1159     if (!matchingRows(left, right)) {
1160       return false;
1161     }
1162     return matchingColumn(left, right);
1163   }
1164 
1165   /**
1166    * Converts the rowkey bytes of the given cell into an int value
1167    *
1168    * @param cell
1169    * @return rowkey as int
1170    */
1171   public static int getRowAsInt(Cell cell) {
1172     if (cell instanceof ByteBufferedCell) {
1173       return ByteBufferUtils.toInt(((ByteBufferedCell) cell).getRowByteBuffer(),
1174           ((ByteBufferedCell) cell).getRowPositionInByteBuffer());
1175     }
1176     return Bytes.toInt(cell.getRowArray(), cell.getRowOffset());
1177   }
1178 
1179   /**
1180    * Converts the value bytes of the given cell into a long value
1181    *
1182    * @param cell
1183    * @return value as long
1184    */
1185   public static long getValueAsLong(Cell cell) {
1186     if (cell instanceof ByteBufferedCell) {
1187       return ByteBufferUtils.toLong(((ByteBufferedCell) cell).getValueByteBuffer(),
1188           ((ByteBufferedCell) cell).getValuePositionInByteBuffer());
1189     }
1190     return Bytes.toLong(cell.getValueArray(), cell.getValueOffset());
1191   }
1192 
1193   /**
1194    * Converts the value bytes of the given cell into a double value
1195    *
1196    * @param cell
1197    * @return value as double
1198    */
1199   public static double getValueAsDouble(Cell cell) {
1200     if (cell instanceof ByteBufferedCell) {
1201       return ByteBufferUtils.toDouble(((ByteBufferedCell) cell).getValueByteBuffer(),
1202           ((ByteBufferedCell) cell).getValuePositionInByteBuffer());
1203     }
1204     return Bytes.toDouble(cell.getValueArray(), cell.getValueOffset());
1205   }
1206 
1207   /**
1208    * Converts the value bytes of the given cell into a BigDecimal
1209    *
1210    * @param cell
1211    * @return value as BigDecimal
1212    */
1213   public static BigDecimal getValueAsBigDecimal(Cell cell) {
1214     if (cell instanceof ByteBufferedCell) {
1215       return ByteBufferUtils.toBigDecimal(((ByteBufferedCell) cell).getValueByteBuffer(),
1216           ((ByteBufferedCell) cell).getValuePositionInByteBuffer(), cell.getValueLength());
1217     }
1218     return Bytes.toBigDecimal(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
1219   }
1220 
1221   /**
1222    * Create a Cell that is smaller than all other possible Cells for the given Cell's row.
1223    *
1224    * @param cell
1225    * @return First possible Cell on passed Cell's row.
1226    */
1227   public static Cell createFirstOnRow(final Cell cell) {
1228     if (cell instanceof ByteBufferedCell) {
1229       return new FirstOnRowByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1230         ((ByteBufferedCell) cell).getRowPositionInByteBuffer(), cell.getRowLength());
1231     }
1232     return new FirstOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1233   }
1234 
1235   /**
1236    * Create a Cell that is smaller than all other possible Cells for the given Cell's row.
1237    *
1238    * @param cell
1239    * @return First possible Cell on passed Cell's row.
1240    */
1241   public static Cell createFirstOnRowCol(final Cell cell) {
1242     if (cell instanceof ByteBufferedCell) {
1243       return new FirstOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1244         ((ByteBufferedCell) cell).getRowPositionInByteBuffer(), cell.getRowLength(),
1245           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1246           ((ByteBufferedCell) cell).getQualifierPositionInByteBuffer(), cell.getQualifierLength());
1247     }
1248     return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(),
1249         cell.getRowLength(), HConstants.EMPTY_BYTE_ARRAY, 0, (byte)0, cell.getQualifierArray(),
1250         cell.getQualifierOffset(), cell.getQualifierLength());
1251   }
1252   /**
1253    * Create a Cell that is smaller than all other possible Cells for the given Cell row's next row.
1254    * Makes the next row's rowkey by appending single byte 0x00 to the end of current row key.
1255    */
1256   public static Cell createFirstOnNextRow(final Cell cell) {
1257     byte[] nextRow = new byte[cell.getRowLength() + 1];
1258     copyRowTo(cell, nextRow, 0);
1259     nextRow[nextRow.length - 1] = 0;// maybe not necessary
1260     return new FirstOnRowCell(nextRow, 0, (short) nextRow.length);
1261   }
1262 
1263   /**
1264    * Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and
1265    * passed qualifier.
1266    *
1267    * @param cell
1268    * @param qArray
1269    * @param qoffest
1270    * @param qlength
1271    * @return Last possible Cell on passed Cell's rk:cf and passed qualifier.
1272    */
1273   public static Cell createFirstOnRowCol(final Cell cell, byte[] qArray, int qoffest, int qlength) {
1274     return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(),
1275         cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1276         qArray, qoffest, qlength);
1277   }
1278 
1279   /**
1280    * Creates the first cell with the row/family/qualifier of this cell and the given timestamp.
1281    * Uses the "maximum" type that guarantees that the new cell is the lowest possible for this
1282    * combination of row, family, qualifier, and timestamp. This cell's own timestamp is ignored.
1283    *
1284    * @param cell - cell
1285    * @param ts
1286    */
1287   public static Cell createFirstOnRowColTS(Cell cell, long ts) {
1288     return new FirstOnRowColTSCell(cell.getRowArray(), cell.getRowOffset(),
1289         cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1290         cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), ts);
1291   }
1292 
1293   /**
1294    * Create a Cell that is larger than all other possible Cells for the given Cell's row.
1295    *
1296    * @param cell
1297    * @return Last possible Cell on passed Cell's row.
1298    */
1299   public static Cell createLastOnRow(final Cell cell) {
1300     return new LastOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1301   }
1302 
1303   /**
1304    * Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q. Used
1305    * in creating "fake keys" for the multi-column Bloom filter optimization to skip the row/column
1306    * we already know is not in the file.
1307    *
1308    * @param cell
1309    * @return Last possible Cell on passed Cell's rk:cf:q.
1310    */
1311   public static Cell createLastOnRowCol(final Cell cell) {
1312     return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
1313         cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1314         cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
1315   }
1316 
1317   /**
1318    * Create a Delete Family Cell for the specified row and family that would
1319    * be smaller than all other possible Delete Family KeyValues that have the
1320    * same row and family.
1321    * Used for seeking.
1322    * @param row - row key (arbitrary byte array)
1323    * @param fam - family name
1324    * @return First Delete Family possible key on passed <code>row</code>.
1325    */
1326   public static Cell createFirstDeleteFamilyCellOnRow(final byte[] row, final byte[] fam) {
1327     return new FirstOnRowDeleteFamilyCell(row, fam);
1328   }
1329 
1330   @InterfaceAudience.Private
1331   /**
1332    * These cells are used in reseeks/seeks to improve the read performance.
1333    * They are not real cells that are returned back to the clients
1334    */
1335   private static abstract class EmptyCell implements Cell {
1336 
1337     @Override
1338     public byte[] getRowArray() {
1339       return EMPTY_BYTE_ARRAY;
1340     }
1341 
1342     @Override
1343     public int getRowOffset() {
1344       return 0;
1345     }
1346 
1347     @Override
1348     public short getRowLength() {
1349       return 0;
1350     }
1351 
1352     @Override
1353     public byte[] getFamilyArray() {
1354       return EMPTY_BYTE_ARRAY;
1355     }
1356 
1357     @Override
1358     public int getFamilyOffset() {
1359       return 0;
1360     }
1361 
1362     @Override
1363     public byte getFamilyLength() {
1364       return 0;
1365     }
1366 
1367     @Override
1368     public byte[] getQualifierArray() {
1369       return EMPTY_BYTE_ARRAY;
1370     }
1371 
1372     @Override
1373     public int getQualifierOffset() {
1374       return 0;
1375     }
1376 
1377     @Override
1378     public int getQualifierLength() {
1379       return 0;
1380     }
1381 
1382     @Override
1383     public long getSequenceId() {
1384       return 0;
1385     }
1386 
1387     @Override
1388     public byte[] getValueArray() {
1389       return EMPTY_BYTE_ARRAY;
1390     }
1391 
1392     @Override
1393     public int getValueOffset() {
1394       return 0;
1395     }
1396 
1397     @Override
1398     public int getValueLength() {
1399       return 0;
1400     }
1401 
1402     @Override
1403     public byte[] getTagsArray() {
1404       return EMPTY_BYTE_ARRAY;
1405     }
1406 
1407     @Override
1408     public int getTagsOffset() {
1409       return 0;
1410     }
1411 
1412     @Override
1413     public int getTagsLength() {
1414       return 0;
1415     }
1416   }
1417 
1418   @InterfaceAudience.Private
1419   /**
1420    * These cells are used in reseeks/seeks to improve the read performance.
1421    * They are not real cells that are returned back to the clients
1422    */
1423   private static abstract class EmptyByteBufferedCell extends ByteBufferedCell {
1424 
1425     @Override
1426     public byte[] getRowArray() {
1427       return CellUtil.cloneRow(this);
1428     }
1429 
1430     @Override
1431     public int getRowOffset() {
1432       return 0;
1433     }
1434 
1435     @Override
1436     public short getRowLength() {
1437       return 0;
1438     }
1439 
1440     @Override
1441     public byte[] getFamilyArray() {
1442       return CellUtil.cloneFamily(this);
1443     }
1444 
1445     @Override
1446     public int getFamilyOffset() {
1447       return 0;
1448     }
1449 
1450     @Override
1451     public byte getFamilyLength() {
1452       return 0;
1453     }
1454 
1455     @Override
1456     public byte[] getQualifierArray() {
1457       return CellUtil.cloneQualifier(this);
1458     }
1459 
1460     @Override
1461     public int getQualifierOffset() {
1462       return 0;
1463     }
1464 
1465     @Override
1466     public int getQualifierLength() {
1467       return 0;
1468     }
1469 
1470     @Override
1471     public long getSequenceId() {
1472       return 0;
1473     }
1474 
1475     @Override
1476     public byte[] getValueArray() {
1477       return CellUtil.cloneValue(this);
1478     }
1479 
1480     @Override
1481     public int getValueOffset() {
1482       return 0;
1483     }
1484 
1485     @Override
1486     public int getValueLength() {
1487       return 0;
1488     }
1489 
1490     @Override
1491     public byte[] getTagsArray() {
1492       return CellUtil.cloneTags(this);
1493     }
1494 
1495     @Override
1496     public int getTagsOffset() {
1497       return 0;
1498     }
1499 
1500     @Override
1501     public int getTagsLength() {
1502       return 0;
1503     }
1504 
1505     @Override
1506     public ByteBuffer getRowByteBuffer() {
1507       return HConstants.EMPTY_BYTE_BUFFER;
1508     }
1509 
1510     @Override
1511     public int getRowPositionInByteBuffer() {
1512       return 0;
1513     }
1514 
1515     @Override
1516     public ByteBuffer getFamilyByteBuffer() {
1517       return HConstants.EMPTY_BYTE_BUFFER;
1518     }
1519 
1520     @Override
1521     public int getFamilyPositionInByteBuffer() {
1522       return 0;
1523     }
1524 
1525     @Override
1526     public ByteBuffer getQualifierByteBuffer() {
1527       return HConstants.EMPTY_BYTE_BUFFER;
1528     }
1529 
1530     @Override
1531     public int getQualifierPositionInByteBuffer() {
1532       return 0;
1533     }
1534 
1535     @Override
1536     public ByteBuffer getTagsByteBuffer() {
1537       return HConstants.EMPTY_BYTE_BUFFER;
1538     }
1539 
1540     @Override
1541     public int getTagsPositionInByteBuffer() {
1542       return 0;
1543     }
1544 
1545     @Override
1546     public ByteBuffer getValueByteBuffer() {
1547       return HConstants.EMPTY_BYTE_BUFFER;
1548     }
1549 
1550     @Override
1551     public int getValuePositionInByteBuffer() {
1552       return 0;
1553     }
1554   }
1555 
1556   @InterfaceAudience.Private
1557   private static class FirstOnRowCell extends EmptyCell {
1558     private final byte[] rowArray;
1559     private final int roffset;
1560     private final short rlength;
1561 
1562     public FirstOnRowCell(final byte[] row, int roffset, short rlength) {
1563       this.rowArray = row;
1564       this.roffset = roffset;
1565       this.rlength = rlength;
1566     }
1567 
1568     @Override
1569     public byte[] getRowArray() {
1570       return this.rowArray;
1571     }
1572 
1573     @Override
1574     public int getRowOffset() {
1575       return this.roffset;
1576     }
1577 
1578     @Override
1579     public short getRowLength() {
1580       return this.rlength;
1581     }
1582 
1583     @Override
1584     public long getTimestamp() {
1585       return HConstants.LATEST_TIMESTAMP;
1586     }
1587 
1588     @Override
1589     public byte getTypeByte() {
1590       return Type.Maximum.getCode();
1591     }
1592   }
1593 
1594   @InterfaceAudience.Private
1595   private static class FirstOnRowByteBufferedCell extends EmptyByteBufferedCell {
1596     private final ByteBuffer rowBuff;
1597     private final int roffset;
1598     private final short rlength;
1599 
1600     public FirstOnRowByteBufferedCell(final ByteBuffer row, int roffset, short rlength) {
1601       this.rowBuff = row;
1602       this.roffset = roffset;
1603       this.rlength = rlength;
1604     }
1605 
1606     @Override
1607     public ByteBuffer getRowByteBuffer() {
1608       return this.rowBuff;
1609     }
1610 
1611     @Override
1612     public int getRowPositionInByteBuffer() {
1613       return this.roffset;
1614     }
1615 
1616     @Override
1617     public short getRowLength() {
1618       return this.rlength;
1619     }
1620 
1621     @Override
1622     public long getTimestamp() {
1623       return HConstants.LATEST_TIMESTAMP;
1624     }
1625 
1626     @Override
1627     public byte getTypeByte() {
1628       return Type.Maximum.getCode();
1629     }
1630   }
1631 
1632   @InterfaceAudience.Private
1633   private static class FirstOnRowColByteBufferedCell extends FirstOnRowByteBufferedCell {
1634     private final ByteBuffer colBuff;
1635     private final int colOffset;
1636     private final int colLength;
1637 
1638     public FirstOnRowColByteBufferedCell(final ByteBuffer row, int roffset, short rlength,
1639         final ByteBuffer col, final int colOffset, final int colLength) {
1640       super(row, roffset, rlength);
1641       this.colBuff = col;
1642       this.colOffset = colOffset;
1643       this.colLength = colLength;
1644     }
1645 
1646     @Override
1647     public ByteBuffer getQualifierByteBuffer() {
1648       return this.colBuff;
1649     }
1650 
1651     @Override
1652     public int getQualifierPositionInByteBuffer() {
1653       return this.colOffset;
1654     }
1655 
1656     @Override
1657     public int getQualifierLength() {
1658       return this.colLength;
1659     }
1660 
1661     @Override
1662     public long getTimestamp() {
1663       return HConstants.LATEST_TIMESTAMP;
1664     }
1665 
1666     @Override
1667     public byte getTypeByte() {
1668       return Type.Maximum.getCode();
1669     }
1670   }
1671 
1672   @InterfaceAudience.Private
1673   private static class FirstOnRowColCell extends FirstOnRowCell {
1674     private final byte[] fArray;
1675     private final int foffset;
1676     private final byte flength;
1677     private final byte[] qArray;
1678     private final int qoffset;
1679     private final int qlength;
1680 
1681     public FirstOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
1682         int foffset, byte flength, byte[] qArray, int qoffset, int qlength) {
1683       super(rArray, roffset, rlength);
1684       this.fArray = fArray;
1685       this.foffset = foffset;
1686       this.flength = flength;
1687       this.qArray = qArray;
1688       this.qoffset = qoffset;
1689       this.qlength = qlength;
1690     }
1691 
1692     @Override
1693     public byte[] getFamilyArray() {
1694       return this.fArray;
1695     }
1696 
1697     @Override
1698     public int getFamilyOffset() {
1699       return this.foffset;
1700     }
1701 
1702     @Override
1703     public byte getFamilyLength() {
1704       return this.flength;
1705     }
1706 
1707     @Override
1708     public byte[] getQualifierArray() {
1709       return this.qArray;
1710     }
1711 
1712     @Override
1713     public int getQualifierOffset() {
1714       return this.qoffset;
1715     }
1716 
1717     @Override
1718     public int getQualifierLength() {
1719       return this.qlength;
1720     }
1721   }
1722 
1723   @InterfaceAudience.Private
1724   private static class FirstOnRowColTSCell extends FirstOnRowColCell {
1725 
1726     private long ts;
1727 
1728     public FirstOnRowColTSCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
1729         int foffset, byte flength, byte[] qArray, int qoffset, int qlength, long ts) {
1730       super(rArray, roffset, rlength, fArray, foffset, flength, qArray, qoffset, qlength);
1731       this.ts = ts;
1732     }
1733 
1734     @Override
1735     public long getTimestamp() {
1736       return this.ts;
1737     }
1738   }
1739 
1740   @InterfaceAudience.Private
1741   private static class LastOnRowCell extends EmptyCell {
1742     private final byte[] rowArray;
1743     private final int roffset;
1744     private final short rlength;
1745 
1746     public LastOnRowCell(byte[] row, int roffset, short rlength) {
1747       this.rowArray = row;
1748       this.roffset = roffset;
1749       this.rlength = rlength;
1750     }
1751 
1752     @Override
1753     public byte[] getRowArray() {
1754       return this.rowArray;
1755     }
1756 
1757     @Override
1758     public int getRowOffset() {
1759       return this.roffset;
1760     }
1761 
1762     @Override
1763     public short getRowLength() {
1764       return this.rlength;
1765     }
1766 
1767     @Override
1768     public long getTimestamp() {
1769       return HConstants.OLDEST_TIMESTAMP;
1770     }
1771 
1772     @Override
1773     public byte getTypeByte() {
1774       return Type.Minimum.getCode();
1775     }
1776   }
1777 
1778   @InterfaceAudience.Private
1779   private static class LastOnRowColCell extends LastOnRowCell {
1780     private final byte[] fArray;
1781     private final int foffset;
1782     private final byte flength;
1783     private final byte[] qArray;
1784     private final int qoffset;
1785     private final int qlength;
1786 
1787     public LastOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
1788         int foffset, byte flength, byte[] qArray, int qoffset, int qlength) {
1789       super(rArray, roffset, rlength);
1790       this.fArray = fArray;
1791       this.foffset = foffset;
1792       this.flength = flength;
1793       this.qArray = qArray;
1794       this.qoffset = qoffset;
1795       this.qlength = qlength;
1796     }
1797 
1798     @Override
1799     public byte[] getFamilyArray() {
1800       return this.fArray;
1801     }
1802 
1803     @Override
1804     public int getFamilyOffset() {
1805       return this.foffset;
1806     }
1807 
1808     @Override
1809     public byte getFamilyLength() {
1810       return this.flength;
1811     }
1812 
1813     @Override
1814     public byte[] getQualifierArray() {
1815       return this.qArray;
1816     }
1817 
1818     @Override
1819     public int getQualifierOffset() {
1820       return this.qoffset;
1821     }
1822 
1823     @Override
1824     public int getQualifierLength() {
1825       return this.qlength;
1826     }
1827   }
1828 
1829   @InterfaceAudience.Private
1830   private static class FirstOnRowDeleteFamilyCell extends EmptyCell {
1831     private final byte[] row;
1832     private final byte[] fam;
1833 
1834     public FirstOnRowDeleteFamilyCell(byte[] row, byte[] fam) {
1835       this.row = row;
1836       this.fam = fam;
1837     }
1838 
1839     @Override
1840     public byte[] getRowArray() {
1841       return this.row;
1842     }
1843 
1844     @Override
1845     public short getRowLength() {
1846       return (short) this.row.length;
1847     }
1848 
1849     @Override
1850     public byte[] getFamilyArray() {
1851       return this.fam;
1852     }
1853 
1854     @Override
1855     public byte getFamilyLength() {
1856       return (byte) this.fam.length;
1857     }
1858 
1859     @Override
1860     public long getTimestamp() {
1861       return HConstants.LATEST_TIMESTAMP;
1862     }
1863 
1864     @Override
1865     public byte getTypeByte() {
1866       return Type.DeleteFamily.getCode();
1867     }
1868   }
1869 }