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.getQualifierLength() == 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   /**
1510    * Create a Cell that is smaller than all other possible Cells for the given Cell's row.
1511    *
1512    * @param cell
1513    * @return First possible Cell on passed Cell's row.
1514    */
1515   public static Cell createFirstOnRowCol(final Cell cell) {
1516     if (cell instanceof ByteBufferedCell) {
1517       return new FirstOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1518           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1519           HConstants.EMPTY_BYTE_BUFFER, 0, (byte) 0,
1520           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1521           ((ByteBufferedCell) cell).getQualifierPosition(), cell.getQualifierLength());
1522     }
1523     return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(),
1524         cell.getRowLength(), HConstants.EMPTY_BYTE_ARRAY, 0, (byte)0, cell.getQualifierArray(),
1525         cell.getQualifierOffset(), cell.getQualifierLength());
1526   }
1527   /**
1528    * Create a Cell that is smaller than all other possible Cells for the given Cell row's next row.
1529    * Makes the next row's rowkey by appending single byte 0x00 to the end of current row key.
1530    */
1531   public static Cell createFirstOnNextRow(final Cell cell) {
1532     byte[] nextRow = new byte[cell.getRowLength() + 1];
1533     copyRowTo(cell, nextRow, 0);
1534     nextRow[nextRow.length - 1] = 0;// maybe not necessary
1535     return new FirstOnRowCell(nextRow, 0, (short) nextRow.length);
1536   }
1537 
1538   /**
1539    * Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and
1540    * passed qualifier.
1541    *
1542    * @param cell
1543    * @param qArray
1544    * @param qoffest
1545    * @param qlength
1546    * @return Last possible Cell on passed Cell's rk:cf and passed qualifier.
1547    */
1548   public static Cell createFirstOnRowCol(final Cell cell, byte[] qArray, int qoffest, int qlength) {
1549     if(cell instanceof ByteBufferedCell) {
1550       return new FirstOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1551           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1552           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1553           ((ByteBufferedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
1554           ByteBuffer.wrap(qArray), qoffest, qlength);
1555     }
1556     return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(),
1557         cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1558         qArray, qoffest, qlength);
1559   }
1560 
1561   /**
1562    * Creates the first cell with the row/family/qualifier of this cell and the given timestamp.
1563    * Uses the "maximum" type that guarantees that the new cell is the lowest possible for this
1564    * combination of row, family, qualifier, and timestamp. This cell's own timestamp is ignored.
1565    *
1566    * @param cell - cell
1567    * @param ts
1568    */
1569   public static Cell createFirstOnRowColTS(Cell cell, long ts) {
1570     if(cell instanceof ByteBufferedCell) {
1571       return new FirstOnRowColTSByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1572           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1573           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1574           ((ByteBufferedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
1575           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1576           ((ByteBufferedCell) cell).getQualifierPosition(), cell.getQualifierLength(),
1577           ts);
1578     }
1579     return new FirstOnRowColTSCell(cell.getRowArray(), cell.getRowOffset(),
1580         cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1581         cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), ts);
1582   }
1583 
1584   /**
1585    * Create a Cell that is larger than all other possible Cells for the given Cell's row.
1586    *
1587    * @param cell
1588    * @return Last possible Cell on passed Cell's row.
1589    */
1590   public static Cell createLastOnRow(final Cell cell) {
1591     if (cell instanceof ByteBufferedCell) {
1592       return new LastOnRowByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1593         ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength());
1594     }
1595     return new LastOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1596   }
1597 
1598   /**
1599    * Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q. Used
1600    * in creating "fake keys" for the multi-column Bloom filter optimization to skip the row/column
1601    * we already know is not in the file.
1602    *
1603    * @param cell
1604    * @return Last possible Cell on passed Cell's rk:cf:q.
1605    */
1606   public static Cell createLastOnRowCol(final Cell cell) {
1607     if (cell instanceof ByteBufferedCell) {
1608       return new LastOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1609           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1610           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1611           ((ByteBufferedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
1612           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1613           ((ByteBufferedCell) cell).getQualifierPosition(), cell.getQualifierLength());
1614     }
1615     return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
1616         cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1617         cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
1618   }
1619 
1620   /**
1621    * Create a Delete Family Cell for the specified row and family that would
1622    * be smaller than all other possible Delete Family KeyValues that have the
1623    * same row and family.
1624    * Used for seeking.
1625    * @param row - row key (arbitrary byte array)
1626    * @param fam - family name
1627    * @return First Delete Family possible key on passed <code>row</code>.
1628    */
1629   public static Cell createFirstDeleteFamilyCellOnRow(final byte[] row, final byte[] fam) {
1630     return new FirstOnRowDeleteFamilyCell(row, fam);
1631   }
1632 
1633   /**
1634    * Compresses the tags to the given outputstream using the TagcompressionContext
1635    * @param out the outputstream to which the compression should happen
1636    * @param cell the cell which has tags
1637    * @param tagCompressionContext the TagCompressionContext
1638    * @throws IOException can throw IOException if the compression encounters issue
1639    */
1640   public static void compressTags(DataOutputStream out, Cell cell,
1641       TagCompressionContext tagCompressionContext) throws IOException {
1642     if (cell instanceof ByteBufferedCell) {
1643       tagCompressionContext.compressTags(out, ((ByteBufferedCell) cell).getTagsByteBuffer(),
1644           ((ByteBufferedCell) cell).getTagsPosition(), cell.getTagsLength());
1645     } else {
1646       tagCompressionContext.compressTags(out, cell.getTagsArray(), cell.getTagsOffset(),
1647           cell.getTagsLength());
1648     }
1649   }
1650 
1651   @InterfaceAudience.Private
1652   /**
1653    * These cells are used in reseeks/seeks to improve the read performance.
1654    * They are not real cells that are returned back to the clients
1655    */
1656   private static abstract class EmptyCell implements Cell {
1657 
1658     @Override
1659     public byte[] getRowArray() {
1660       return EMPTY_BYTE_ARRAY;
1661     }
1662 
1663     @Override
1664     public int getRowOffset() {
1665       return 0;
1666     }
1667 
1668     @Override
1669     public short getRowLength() {
1670       return 0;
1671     }
1672 
1673     @Override
1674     public byte[] getFamilyArray() {
1675       return EMPTY_BYTE_ARRAY;
1676     }
1677 
1678     @Override
1679     public int getFamilyOffset() {
1680       return 0;
1681     }
1682 
1683     @Override
1684     public byte getFamilyLength() {
1685       return 0;
1686     }
1687 
1688     @Override
1689     public byte[] getQualifierArray() {
1690       return EMPTY_BYTE_ARRAY;
1691     }
1692 
1693     @Override
1694     public int getQualifierOffset() {
1695       return 0;
1696     }
1697 
1698     @Override
1699     public int getQualifierLength() {
1700       return 0;
1701     }
1702 
1703     @Override
1704     public long getSequenceId() {
1705       return 0;
1706     }
1707 
1708     @Override
1709     public byte[] getValueArray() {
1710       return EMPTY_BYTE_ARRAY;
1711     }
1712 
1713     @Override
1714     public int getValueOffset() {
1715       return 0;
1716     }
1717 
1718     @Override
1719     public int getValueLength() {
1720       return 0;
1721     }
1722 
1723     @Override
1724     public byte[] getTagsArray() {
1725       return EMPTY_BYTE_ARRAY;
1726     }
1727 
1728     @Override
1729     public int getTagsOffset() {
1730       return 0;
1731     }
1732 
1733     @Override
1734     public int getTagsLength() {
1735       return 0;
1736     }
1737   }
1738 
1739   @InterfaceAudience.Private
1740   /**
1741    * These cells are used in reseeks/seeks to improve the read performance.
1742    * They are not real cells that are returned back to the clients
1743    */
1744   private static abstract class EmptyByteBufferedCell extends ByteBufferedCell {
1745 
1746     @Override
1747     public byte[] getRowArray() {
1748       return CellUtil.cloneRow(this);
1749     }
1750 
1751     @Override
1752     public int getRowOffset() {
1753       return 0;
1754     }
1755 
1756     @Override
1757     public short getRowLength() {
1758       return 0;
1759     }
1760 
1761     @Override
1762     public byte[] getFamilyArray() {
1763       return CellUtil.cloneFamily(this);
1764     }
1765 
1766     @Override
1767     public int getFamilyOffset() {
1768       return 0;
1769     }
1770 
1771     @Override
1772     public byte getFamilyLength() {
1773       return 0;
1774     }
1775 
1776     @Override
1777     public byte[] getQualifierArray() {
1778       return CellUtil.cloneQualifier(this);
1779     }
1780 
1781     @Override
1782     public int getQualifierOffset() {
1783       return 0;
1784     }
1785 
1786     @Override
1787     public int getQualifierLength() {
1788       return 0;
1789     }
1790 
1791     @Override
1792     public long getSequenceId() {
1793       return 0;
1794     }
1795 
1796     @Override
1797     public byte[] getValueArray() {
1798       return CellUtil.cloneValue(this);
1799     }
1800 
1801     @Override
1802     public int getValueOffset() {
1803       return 0;
1804     }
1805 
1806     @Override
1807     public int getValueLength() {
1808       return 0;
1809     }
1810 
1811     @Override
1812     public byte[] getTagsArray() {
1813       return CellUtil.cloneTags(this);
1814     }
1815 
1816     @Override
1817     public int getTagsOffset() {
1818       return 0;
1819     }
1820 
1821     @Override
1822     public int getTagsLength() {
1823       return 0;
1824     }
1825 
1826     @Override
1827     public ByteBuffer getRowByteBuffer() {
1828       return HConstants.EMPTY_BYTE_BUFFER;
1829     }
1830 
1831     @Override
1832     public int getRowPosition() {
1833       return 0;
1834     }
1835 
1836     @Override
1837     public ByteBuffer getFamilyByteBuffer() {
1838       return HConstants.EMPTY_BYTE_BUFFER;
1839     }
1840 
1841     @Override
1842     public int getFamilyPosition() {
1843       return 0;
1844     }
1845 
1846     @Override
1847     public ByteBuffer getQualifierByteBuffer() {
1848       return HConstants.EMPTY_BYTE_BUFFER;
1849     }
1850 
1851     @Override
1852     public int getQualifierPosition() {
1853       return 0;
1854     }
1855 
1856     @Override
1857     public ByteBuffer getTagsByteBuffer() {
1858       return HConstants.EMPTY_BYTE_BUFFER;
1859     }
1860 
1861     @Override
1862     public int getTagsPosition() {
1863       return 0;
1864     }
1865 
1866     @Override
1867     public ByteBuffer getValueByteBuffer() {
1868       return HConstants.EMPTY_BYTE_BUFFER;
1869     }
1870 
1871     @Override
1872     public int getValuePosition() {
1873       return 0;
1874     }
1875   }
1876 
1877   @InterfaceAudience.Private
1878   private static class FirstOnRowCell extends EmptyCell {
1879     private final byte[] rowArray;
1880     private final int roffset;
1881     private final short rlength;
1882 
1883     public FirstOnRowCell(final byte[] row, int roffset, short rlength) {
1884       this.rowArray = row;
1885       this.roffset = roffset;
1886       this.rlength = rlength;
1887     }
1888 
1889     @Override
1890     public byte[] getRowArray() {
1891       return this.rowArray;
1892     }
1893 
1894     @Override
1895     public int getRowOffset() {
1896       return this.roffset;
1897     }
1898 
1899     @Override
1900     public short getRowLength() {
1901       return this.rlength;
1902     }
1903 
1904     @Override
1905     public long getTimestamp() {
1906       return HConstants.LATEST_TIMESTAMP;
1907     }
1908 
1909     @Override
1910     public byte getTypeByte() {
1911       return Type.Maximum.getCode();
1912     }
1913   }
1914 
1915   @InterfaceAudience.Private
1916   private static class FirstOnRowByteBufferedCell extends EmptyByteBufferedCell {
1917     private final ByteBuffer rowBuff;
1918     private final int roffset;
1919     private final short rlength;
1920 
1921     public FirstOnRowByteBufferedCell(final ByteBuffer row, int roffset, short rlength) {
1922       this.rowBuff = row;
1923       this.roffset = roffset;
1924       this.rlength = rlength;
1925     }
1926 
1927     @Override
1928     public ByteBuffer getRowByteBuffer() {
1929       return this.rowBuff;
1930     }
1931 
1932     @Override
1933     public int getRowPosition() {
1934       return this.roffset;
1935     }
1936 
1937     @Override
1938     public short getRowLength() {
1939       return this.rlength;
1940     }
1941 
1942     @Override
1943     public long getTimestamp() {
1944       return HConstants.LATEST_TIMESTAMP;
1945     }
1946 
1947     @Override
1948     public byte getTypeByte() {
1949       return Type.Maximum.getCode();
1950     }
1951   }
1952 
1953   @InterfaceAudience.Private
1954   private static class LastOnRowByteBufferedCell extends EmptyByteBufferedCell {
1955     private final ByteBuffer rowBuff;
1956     private final int roffset;
1957     private final short rlength;
1958 
1959     public LastOnRowByteBufferedCell(final ByteBuffer row, int roffset, short rlength) {
1960       this.rowBuff = row;
1961       this.roffset = roffset;
1962       this.rlength = rlength;
1963     }
1964 
1965     @Override
1966     public ByteBuffer getRowByteBuffer() {
1967       return this.rowBuff;
1968     }
1969 
1970     @Override
1971     public int getRowPosition() {
1972       return this.roffset;
1973     }
1974 
1975     @Override
1976     public short getRowLength() {
1977       return this.rlength;
1978     }
1979 
1980     @Override
1981     public long getTimestamp() {
1982       return HConstants.OLDEST_TIMESTAMP;
1983     }
1984 
1985     @Override
1986     public byte getTypeByte() {
1987       return Type.Minimum.getCode();
1988     }
1989   }
1990 
1991   @InterfaceAudience.Private
1992   private static class FirstOnRowColByteBufferedCell extends FirstOnRowByteBufferedCell {
1993     private final ByteBuffer famBuff;
1994     private final int famOffset;
1995     private final byte famLength;
1996     private final ByteBuffer colBuff;
1997     private final int colOffset;
1998     private final int colLength;
1999 
2000     public FirstOnRowColByteBufferedCell(final ByteBuffer row, int roffset, short rlength,
2001         final ByteBuffer famBuff, final int famOffset, final byte famLength, final ByteBuffer col,
2002         final int colOffset, final int colLength) {
2003       super(row, roffset, rlength);
2004       this.famBuff = famBuff;
2005       this.famOffset = famOffset;
2006       this.famLength = famLength;
2007       this.colBuff = col;
2008       this.colOffset = colOffset;
2009       this.colLength = colLength;
2010     }
2011 
2012     @Override
2013     public ByteBuffer getFamilyByteBuffer() {
2014       return this.famBuff;
2015     }
2016 
2017     @Override
2018     public int getFamilyPosition() {
2019       return this.famOffset;
2020     }
2021 
2022     @Override
2023     public byte getFamilyLength() {
2024       return famLength;
2025     }
2026 
2027     @Override
2028     public ByteBuffer getQualifierByteBuffer() {
2029       return this.colBuff;
2030     }
2031 
2032     @Override
2033     public int getQualifierPosition() {
2034       return this.colOffset;
2035     }
2036 
2037     @Override
2038     public int getQualifierLength() {
2039       return this.colLength;
2040     }
2041   }
2042 
2043   @InterfaceAudience.Private
2044   private static class FirstOnRowColCell extends FirstOnRowCell {
2045     private final byte[] fArray;
2046     private final int foffset;
2047     private final byte flength;
2048     private final byte[] qArray;
2049     private final int qoffset;
2050     private final int qlength;
2051 
2052     public FirstOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
2053         int foffset, byte flength, byte[] qArray, int qoffset, int qlength) {
2054       super(rArray, roffset, rlength);
2055       this.fArray = fArray;
2056       this.foffset = foffset;
2057       this.flength = flength;
2058       this.qArray = qArray;
2059       this.qoffset = qoffset;
2060       this.qlength = qlength;
2061     }
2062 
2063     @Override
2064     public byte[] getFamilyArray() {
2065       return this.fArray;
2066     }
2067 
2068     @Override
2069     public int getFamilyOffset() {
2070       return this.foffset;
2071     }
2072 
2073     @Override
2074     public byte getFamilyLength() {
2075       return this.flength;
2076     }
2077 
2078     @Override
2079     public byte[] getQualifierArray() {
2080       return this.qArray;
2081     }
2082 
2083     @Override
2084     public int getQualifierOffset() {
2085       return this.qoffset;
2086     }
2087 
2088     @Override
2089     public int getQualifierLength() {
2090       return this.qlength;
2091     }
2092   }
2093 
2094   @InterfaceAudience.Private
2095   private static class FirstOnRowColTSCell extends FirstOnRowColCell {
2096 
2097     private long ts;
2098 
2099     public FirstOnRowColTSCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
2100         int foffset, byte flength, byte[] qArray, int qoffset, int qlength, long ts) {
2101       super(rArray, roffset, rlength, fArray, foffset, flength, qArray, qoffset, qlength);
2102       this.ts = ts;
2103     }
2104 
2105     @Override
2106     public long getTimestamp() {
2107       return this.ts;
2108     }
2109   }
2110 
2111   @InterfaceAudience.Private
2112   private static class FirstOnRowColTSByteBufferedCell extends FirstOnRowColByteBufferedCell {
2113 
2114     private long ts;
2115 
2116     public FirstOnRowColTSByteBufferedCell(ByteBuffer rBuffer, int roffset, short rlength,
2117         ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset, int qlength,
2118         long ts) {
2119       super(rBuffer, roffset, rlength, fBuffer, foffset, flength, qBuffer, qoffset, qlength);
2120       this.ts = ts;
2121     }
2122 
2123     @Override
2124     public long getTimestamp() {
2125       return this.ts;
2126     }
2127   }
2128 
2129   @InterfaceAudience.Private
2130   private static class LastOnRowCell extends EmptyCell {
2131     private final byte[] rowArray;
2132     private final int roffset;
2133     private final short rlength;
2134 
2135     public LastOnRowCell(byte[] row, int roffset, short rlength) {
2136       this.rowArray = row;
2137       this.roffset = roffset;
2138       this.rlength = rlength;
2139     }
2140 
2141     @Override
2142     public byte[] getRowArray() {
2143       return this.rowArray;
2144     }
2145 
2146     @Override
2147     public int getRowOffset() {
2148       return this.roffset;
2149     }
2150 
2151     @Override
2152     public short getRowLength() {
2153       return this.rlength;
2154     }
2155 
2156     @Override
2157     public long getTimestamp() {
2158       return HConstants.OLDEST_TIMESTAMP;
2159     }
2160 
2161     @Override
2162     public byte getTypeByte() {
2163       return Type.Minimum.getCode();
2164     }
2165   }
2166 
2167   @InterfaceAudience.Private
2168   private static class LastOnRowColCell extends LastOnRowCell {
2169     private final byte[] fArray;
2170     private final int foffset;
2171     private final byte flength;
2172     private final byte[] qArray;
2173     private final int qoffset;
2174     private final int qlength;
2175 
2176     public LastOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
2177         int foffset, byte flength, byte[] qArray, int qoffset, int qlength) {
2178       super(rArray, roffset, rlength);
2179       this.fArray = fArray;
2180       this.foffset = foffset;
2181       this.flength = flength;
2182       this.qArray = qArray;
2183       this.qoffset = qoffset;
2184       this.qlength = qlength;
2185     }
2186 
2187     @Override
2188     public byte[] getFamilyArray() {
2189       return this.fArray;
2190     }
2191 
2192     @Override
2193     public int getFamilyOffset() {
2194       return this.foffset;
2195     }
2196 
2197     @Override
2198     public byte getFamilyLength() {
2199       return this.flength;
2200     }
2201 
2202     @Override
2203     public byte[] getQualifierArray() {
2204       return this.qArray;
2205     }
2206 
2207     @Override
2208     public int getQualifierOffset() {
2209       return this.qoffset;
2210     }
2211 
2212     @Override
2213     public int getQualifierLength() {
2214       return this.qlength;
2215     }
2216   }
2217 
2218   @InterfaceAudience.Private
2219   private static class LastOnRowColByteBufferedCell extends LastOnRowByteBufferedCell {
2220     private final ByteBuffer fBuffer;
2221     private final int foffset;
2222     private final byte flength;
2223     private final ByteBuffer qBuffer;
2224     private final int qoffset;
2225     private final int qlength;
2226 
2227     public LastOnRowColByteBufferedCell(ByteBuffer rBuffer, int roffset, short rlength,
2228         ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset,
2229         int qlength) {
2230       super(rBuffer, roffset, rlength);
2231       this.fBuffer = fBuffer;
2232       this.foffset = foffset;
2233       this.flength = flength;
2234       this.qBuffer = qBuffer;
2235       this.qoffset = qoffset;
2236       this.qlength = qlength;
2237     }
2238 
2239     @Override
2240     public ByteBuffer getFamilyByteBuffer() {
2241       return this.fBuffer;
2242     }
2243 
2244     @Override
2245     public int getFamilyPosition() {
2246       return this.foffset;
2247     }
2248 
2249     @Override
2250     public byte getFamilyLength() {
2251       return this.flength;
2252     }
2253 
2254     @Override
2255     public ByteBuffer getQualifierByteBuffer() {
2256       return this.qBuffer;
2257     }
2258 
2259     @Override
2260     public int getQualifierPosition() {
2261       return this.qoffset;
2262     }
2263 
2264     @Override
2265     public int getQualifierLength() {
2266       return this.qlength;
2267     }
2268   }
2269 
2270   @InterfaceAudience.Private
2271   private static class FirstOnRowDeleteFamilyCell extends EmptyCell {
2272     private final byte[] row;
2273     private final byte[] fam;
2274 
2275     public FirstOnRowDeleteFamilyCell(byte[] row, byte[] fam) {
2276       this.row = row;
2277       this.fam = fam;
2278     }
2279 
2280     @Override
2281     public byte[] getRowArray() {
2282       return this.row;
2283     }
2284 
2285     @Override
2286     public short getRowLength() {
2287       return (short) this.row.length;
2288     }
2289 
2290     @Override
2291     public byte[] getFamilyArray() {
2292       return this.fam;
2293     }
2294 
2295     @Override
2296     public byte getFamilyLength() {
2297       return (byte) this.fam.length;
2298     }
2299 
2300     @Override
2301     public long getTimestamp() {
2302       return HConstants.LATEST_TIMESTAMP;
2303     }
2304 
2305     @Override
2306     public byte getTypeByte() {
2307       return Type.DeleteFamily.getCode();
2308     }
2309   }
2310 }