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