001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIMITER;
021import static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIM_ARRAY;
022import static org.apache.hadoop.hbase.KeyValue.getDelimiter;
023import static org.apache.hadoop.hbase.Tag.TAG_LENGTH_SIZE;
024
025import java.io.DataOutput;
026import java.io.DataOutputStream;
027import java.io.IOException;
028import java.nio.ByteBuffer;
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.Iterator;
032import java.util.List;
033import java.util.Map.Entry;
034import java.util.NavigableMap;
035import java.util.Optional;
036import java.util.function.Function;
037import org.apache.hadoop.hbase.KeyValue.Type;
038import org.apache.hadoop.hbase.io.HeapSize;
039import org.apache.hadoop.hbase.util.ByteBufferUtils;
040import org.apache.hadoop.hbase.util.ByteRange;
041import org.apache.hadoop.hbase.util.Bytes;
042import org.apache.yetus.audience.InterfaceAudience;
043import org.apache.yetus.audience.InterfaceAudience.Private;
044
045/**
046 * Utility methods helpful for slinging {@link Cell} instances. Some methods below are for internal
047 * use only and are marked InterfaceAudience.Private at the method level. Note that all such methods
048 * have been marked deprecated in HBase-2.0 which will be subsequently removed in HBase-3.0
049 */
050@InterfaceAudience.Public
051public final class CellUtil {
052
053  /**
054   * Private constructor to keep this class from being instantiated.
055   */
056  private CellUtil() {
057  }
058
059  /******************* ByteRange *******************************/
060
061  /**
062   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
063   */
064  @Deprecated
065  public static ByteRange fillRowRange(Cell cell, ByteRange range) {
066    return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
067  }
068
069  /**
070   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
071   */
072  @Deprecated
073  public static ByteRange fillFamilyRange(Cell cell, ByteRange range) {
074    return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
075  }
076
077  /**
078   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
079   */
080  @Deprecated
081  public static ByteRange fillQualifierRange(Cell cell, ByteRange range) {
082    return range.set(cell.getQualifierArray(), cell.getQualifierOffset(),
083      cell.getQualifierLength());
084  }
085
086  /**
087   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
088   */
089  @Deprecated
090  public static ByteRange fillValueRange(Cell cell, ByteRange range) {
091    return range.set(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
092  }
093
094  /**
095   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
096   */
097  @Deprecated
098  public static ByteRange fillTagRange(Cell cell, ByteRange range) {
099    return range.set(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
100  }
101
102  /***************** get individual arrays for tests ************/
103
104  public static byte[] cloneRow(Cell cell) {
105    byte[] output = new byte[cell.getRowLength()];
106    copyRowTo(cell, output, 0);
107    return output;
108  }
109
110  public static byte[] cloneFamily(Cell cell) {
111    byte[] output = new byte[cell.getFamilyLength()];
112    copyFamilyTo(cell, output, 0);
113    return output;
114  }
115
116  public static byte[] cloneQualifier(Cell cell) {
117    byte[] output = new byte[cell.getQualifierLength()];
118    copyQualifierTo(cell, output, 0);
119    return output;
120  }
121
122  public static byte[] cloneValue(Cell cell) {
123    byte[] output = new byte[cell.getValueLength()];
124    copyValueTo(cell, output, 0);
125    return output;
126  }
127
128  /**
129   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. Use {@link RawCell#cloneTags()}
130   */
131  @Deprecated
132  public static byte[] cloneTags(Cell cell) {
133    byte[] output = new byte[cell.getTagsLength()];
134    PrivateCellUtil.copyTagsTo(cell, output, 0);
135    return output;
136  }
137
138  /**
139   * Returns tag value in a new byte array. If server-side, use {@link Tag#getValueArray()} with
140   * appropriate {@link Tag#getValueOffset()} and {@link Tag#getValueLength()} instead to save on
141   * allocations.
142   * @return tag value in a new byte array.
143   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
144   */
145  @Deprecated
146  public static byte[] getTagArray(Cell cell) {
147    byte[] output = new byte[cell.getTagsLength()];
148    PrivateCellUtil.copyTagsTo(cell, output, 0);
149    return output;
150  }
151
152  /**
153   * Makes a column in family:qualifier form from separate byte arrays.
154   * <p>
155   * Not recommended for usage as this is old-style API.
156   * @return family:qualifier
157   */
158  public static byte[] makeColumn(byte[] family, byte[] qualifier) {
159    return Bytes.add(family, COLUMN_FAMILY_DELIM_ARRAY, qualifier);
160  }
161
162  /**
163   * Splits a column in {@code family:qualifier} form into separate byte arrays. An empty qualifier
164   * (ie, {@code fam:}) is parsed as <code>{ fam, EMPTY_BYTE_ARRAY }</code> while no delimiter (ie,
165   * {@code fam}) is parsed as an array of one element, <code>{ fam }</code>.
166   * <p>
167   * Don't forget, HBase DOES support empty qualifiers. (see HBASE-9549)
168   * </p>
169   * <p>
170   * Not recommend to be used as this is old-style API.
171   * </p>
172   * @param c The column.
173   * @return The parsed column.
174   */
175  public static byte[][] parseColumn(byte[] c) {
176    final int index = getDelimiter(c, 0, c.length, COLUMN_FAMILY_DELIMITER);
177    if (index == -1) {
178      // If no delimiter, return array of size 1
179      return new byte[][] { c };
180    } else if (index == c.length - 1) {
181      // family with empty qualifier, return array size 2
182      byte[] family = new byte[c.length - 1];
183      System.arraycopy(c, 0, family, 0, family.length);
184      return new byte[][] { family, HConstants.EMPTY_BYTE_ARRAY };
185    }
186    // Family and column, return array size 2
187    final byte[][] result = new byte[2][];
188    result[0] = new byte[index];
189    System.arraycopy(c, 0, result[0], 0, index);
190    final int len = c.length - (index + 1);
191    result[1] = new byte[len];
192    System.arraycopy(c, index + 1 /* Skip delimiter */, result[1], 0, len);
193    return result;
194  }
195
196  /******************** copyTo **********************************/
197
198  /**
199   * Copies the row to the given byte[]
200   * @param cell              the cell whose row has to be copied
201   * @param destination       the destination byte[] to which the row has to be copied
202   * @param destinationOffset the offset in the destination byte[]
203   * @return the offset of the byte[] after the copy has happened
204   */
205  public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) {
206    short rowLen = cell.getRowLength();
207    if (cell instanceof ByteBufferExtendedCell) {
208      ByteBufferUtils.copyFromBufferToArray(destination,
209        ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
210        ((ByteBufferExtendedCell) cell).getRowPosition(), destinationOffset, rowLen);
211    } else {
212      System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset,
213        rowLen);
214    }
215    return destinationOffset + rowLen;
216  }
217
218  /**
219   * Copies the row to the given bytebuffer
220   * @param cell              cell the cell whose row has to be copied
221   * @param destination       the destination bytebuffer to which the row has to be copied
222   * @param destinationOffset the offset in the destination byte[]
223   * @return the offset of the bytebuffer after the copy has happened
224   */
225  public static int copyRowTo(Cell cell, ByteBuffer destination, int destinationOffset) {
226    short rowLen = cell.getRowLength();
227    if (cell instanceof ByteBufferExtendedCell) {
228      ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
229        destination, ((ByteBufferExtendedCell) cell).getRowPosition(), destinationOffset, rowLen);
230    } else {
231      ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getRowArray(),
232        cell.getRowOffset(), rowLen);
233    }
234    return destinationOffset + rowLen;
235  }
236
237  /**
238   * Copies the row to a new byte[]
239   * @param cell the cell from which row has to copied
240   * @return the byte[] containing the row
241   */
242  public static byte[] copyRow(Cell cell) {
243    if (cell instanceof ByteBufferExtendedCell) {
244      return ByteBufferUtils.copyOfRange(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
245        ((ByteBufferExtendedCell) cell).getRowPosition(),
246        ((ByteBufferExtendedCell) cell).getRowPosition() + cell.getRowLength());
247    } else {
248      return Arrays.copyOfRange(cell.getRowArray(), cell.getRowOffset(),
249        cell.getRowOffset() + cell.getRowLength());
250    }
251  }
252
253  /**
254   * Copies the family to the given byte[]
255   * @param cell              the cell whose family has to be copied
256   * @param destination       the destination byte[] to which the family has to be copied
257   * @param destinationOffset the offset in the destination byte[]
258   * @return the offset of the byte[] after the copy has happened
259   */
260  public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) {
261    byte fLen = cell.getFamilyLength();
262    if (cell instanceof ByteBufferExtendedCell) {
263      ByteBufferUtils.copyFromBufferToArray(destination,
264        ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
265        ((ByteBufferExtendedCell) cell).getFamilyPosition(), destinationOffset, fLen);
266    } else {
267      System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination,
268        destinationOffset, fLen);
269    }
270    return destinationOffset + fLen;
271  }
272
273  /**
274   * Copies the family to the given bytebuffer
275   * @param cell              the cell whose family has to be copied
276   * @param destination       the destination bytebuffer to which the family has to be copied
277   * @param destinationOffset the offset in the destination bytebuffer
278   * @return the offset of the bytebuffer after the copy has happened
279   */
280  public static int copyFamilyTo(Cell cell, ByteBuffer destination, int destinationOffset) {
281    byte fLen = cell.getFamilyLength();
282    if (cell instanceof ByteBufferExtendedCell) {
283      ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
284        destination, ((ByteBufferExtendedCell) cell).getFamilyPosition(), destinationOffset, fLen);
285    } else {
286      ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getFamilyArray(),
287        cell.getFamilyOffset(), fLen);
288    }
289    return destinationOffset + fLen;
290  }
291
292  /**
293   * Copies the qualifier to the given byte[]
294   * @param cell              the cell whose qualifier has to be copied
295   * @param destination       the destination byte[] to which the qualifier has to be copied
296   * @param destinationOffset the offset in the destination byte[]
297   * @return the offset of the byte[] after the copy has happened
298   */
299  public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) {
300    int qlen = cell.getQualifierLength();
301    if (cell instanceof ByteBufferExtendedCell) {
302      ByteBufferUtils.copyFromBufferToArray(destination,
303        ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
304        ((ByteBufferExtendedCell) cell).getQualifierPosition(), destinationOffset, qlen);
305    } else {
306      System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination,
307        destinationOffset, qlen);
308    }
309    return destinationOffset + qlen;
310  }
311
312  /**
313   * Copies the qualifier to the given bytebuffer
314   * @param cell              the cell whose qualifier has to be copied
315   * @param destination       the destination bytebuffer to which the qualifier has to be copied
316   * @param destinationOffset the offset in the destination bytebuffer
317   * @return the offset of the bytebuffer after the copy has happened
318   */
319  public static int copyQualifierTo(Cell cell, ByteBuffer destination, int destinationOffset) {
320    int qlen = cell.getQualifierLength();
321    if (cell instanceof ByteBufferExtendedCell) {
322      ByteBufferUtils.copyFromBufferToBuffer(
323        ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), destination,
324        ((ByteBufferExtendedCell) cell).getQualifierPosition(), destinationOffset, qlen);
325    } else {
326      ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset,
327        cell.getQualifierArray(), cell.getQualifierOffset(), qlen);
328    }
329    return destinationOffset + qlen;
330  }
331
332  /**
333   * Copies the value to the given byte[]
334   * @param cell              the cell whose value has to be copied
335   * @param destination       the destination byte[] to which the value has to be copied
336   * @param destinationOffset the offset in the destination byte[]
337   * @return the offset of the byte[] after the copy has happened
338   */
339  public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) {
340    int vlen = cell.getValueLength();
341    if (cell instanceof ByteBufferExtendedCell) {
342      ByteBufferUtils.copyFromBufferToArray(destination,
343        ((ByteBufferExtendedCell) cell).getValueByteBuffer(),
344        ((ByteBufferExtendedCell) cell).getValuePosition(), destinationOffset, vlen);
345    } else {
346      System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset,
347        vlen);
348    }
349    return destinationOffset + vlen;
350  }
351
352  /**
353   * Copies the value to the given bytebuffer
354   * @param cell              the cell whose value has to be copied
355   * @param destination       the destination bytebuffer to which the value has to be copied
356   * @param destinationOffset the offset in the destination bytebuffer
357   * @return the offset of the bytebuffer after the copy has happened
358   */
359  public static int copyValueTo(Cell cell, ByteBuffer destination, int destinationOffset) {
360    int vlen = cell.getValueLength();
361    if (cell instanceof ByteBufferExtendedCell) {
362      ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
363        destination, ((ByteBufferExtendedCell) cell).getValuePosition(), destinationOffset, vlen);
364    } else {
365      ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getValueArray(),
366        cell.getValueOffset(), vlen);
367    }
368    return destinationOffset + vlen;
369  }
370
371  /**
372   * Copies the tags info into the tag portion of the cell
373   * @return position after tags
374   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
375   */
376  @Deprecated
377  public static int copyTagTo(Cell cell, byte[] destination, int destinationOffset) {
378    int tlen = cell.getTagsLength();
379    if (cell instanceof ByteBufferExtendedCell) {
380      ByteBufferUtils.copyFromBufferToArray(destination,
381        ((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
382        ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen);
383    } else {
384      System.arraycopy(cell.getTagsArray(), cell.getTagsOffset(), destination, destinationOffset,
385        tlen);
386    }
387    return destinationOffset + tlen;
388  }
389
390  /**
391   * Copies the tags info into the tag portion of the cell
392   * @return position after tags
393   * @deprecated As of HBase-2.0. Will be removed in 3.0.
394   */
395  @Deprecated
396  public static int copyTagTo(Cell cell, ByteBuffer destination, int destinationOffset) {
397    int tlen = cell.getTagsLength();
398    if (cell instanceof ByteBufferExtendedCell) {
399      ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
400        destination, ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen);
401    } else {
402      ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getTagsArray(),
403        cell.getTagsOffset(), tlen);
404    }
405    return destinationOffset + tlen;
406  }
407
408  /********************* misc *************************************/
409
410  @Private
411  /**
412   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0.
413   */
414  @Deprecated
415  public static byte getRowByte(Cell cell, int index) {
416    if (cell instanceof ByteBufferExtendedCell) {
417      return ((ByteBufferExtendedCell) cell).getRowByteBuffer()
418        .get(((ByteBufferExtendedCell) cell).getRowPosition() + index);
419    }
420    return cell.getRowArray()[cell.getRowOffset() + index];
421  }
422
423  /**
424   * @deprecated As of HBase-2.0. Will be removed in 3.0.
425   */
426  @Deprecated
427  public static ByteBuffer getValueBufferShallowCopy(Cell cell) {
428    ByteBuffer buffer =
429      ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
430    return buffer;
431  }
432
433  /**
434   * @return cell's qualifier wrapped into a ByteBuffer.
435   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
436   */
437  @Deprecated
438  public static ByteBuffer getQualifierBufferShallowCopy(Cell cell) {
439    // No usage of this in code.
440    ByteBuffer buffer = ByteBuffer.wrap(cell.getQualifierArray(), cell.getQualifierOffset(),
441      cell.getQualifierLength());
442    return buffer;
443  }
444
445  /**
446   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder}
447   *             instead
448   */
449  @Deprecated
450  public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
451    final long timestamp, final byte type, final byte[] value) {
452    return ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY).setRow(row)
453      .setFamily(family).setQualifier(qualifier).setTimestamp(timestamp).setType(type)
454      .setValue(value).build();
455  }
456
457  /**
458   * Creates a cell with deep copy of all passed bytes.
459   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder}
460   *             instead
461   */
462  @Deprecated
463  public static Cell createCell(final byte[] rowArray, final int rowOffset, final int rowLength,
464    final byte[] familyArray, final int familyOffset, final int familyLength,
465    final byte[] qualifierArray, final int qualifierOffset, final int qualifierLength) {
466    // See createCell(final byte [] row, final byte [] value) for why we default Maximum type.
467    return ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY)
468      .setRow(rowArray, rowOffset, rowLength).setFamily(familyArray, familyOffset, familyLength)
469      .setQualifier(qualifierArray, qualifierOffset, qualifierLength)
470      .setTimestamp(HConstants.LATEST_TIMESTAMP).setType(KeyValue.Type.Maximum.getCode())
471      .setValue(HConstants.EMPTY_BYTE_ARRAY, 0, HConstants.EMPTY_BYTE_ARRAY.length).build();
472  }
473
474  /**
475   * Marked as audience Private as of 1.2.0. Creating a Cell with a memstoreTS/mvcc is an internal
476   * implementation detail not for public use.
477   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use
478   *             {@link ExtendedCellBuilder} instead
479   */
480  @InterfaceAudience.Private
481  @Deprecated
482  public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
483    final long timestamp, final byte type, final byte[] value, final long memstoreTS) {
484    return createCell(row, family, qualifier, timestamp, type, value, null, memstoreTS);
485  }
486
487  /**
488   * Marked as audience Private as of 1.2.0. Creating a Cell with tags and a memstoreTS/mvcc is an
489   * internal implementation detail not for public use.
490   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use
491   *             {@link ExtendedCellBuilder} instead
492   */
493  @InterfaceAudience.Private
494  @Deprecated
495  public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
496    final long timestamp, final byte type, final byte[] value, byte[] tags, final long memstoreTS) {
497    return ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY).setRow(row)
498      .setFamily(family).setQualifier(qualifier).setTimestamp(timestamp).setType(type)
499      .setValue(value).setTags(tags).setSequenceId(memstoreTS).build();
500  }
501
502  /**
503   * Marked as audience Private as of 1.2.0. Creating a Cell with tags is an internal implementation
504   * detail not for public use.
505   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use
506   *             {@link ExtendedCellBuilder} instead
507   */
508  @InterfaceAudience.Private
509  @Deprecated
510  public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
511    final long timestamp, Type type, final byte[] value, byte[] tags) {
512    return createCell(row, family, qualifier, timestamp, type.getCode(), value, tags, 0);
513  }
514
515  /**
516   * Create a Cell with specific row. Other fields defaulted.
517   * @return Cell with passed row but all other fields are arbitrary
518   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder}
519   *             instead
520   */
521  @Deprecated
522  public static Cell createCell(final byte[] row) {
523    return createCell(row, HConstants.EMPTY_BYTE_ARRAY);
524  }
525
526  /**
527   * Create a Cell with specific row and value. Other fields are defaulted.
528   * @return Cell with passed row and value but all other fields are arbitrary
529   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder}
530   *             instead
531   */
532  @Deprecated
533  public static Cell createCell(final byte[] row, final byte[] value) {
534    // An empty family + empty qualifier + Type.Minimum is used as flag to indicate last on row.
535    // See the CellComparator and KeyValue comparator. Search for compareWithoutRow.
536    // Lets not make a last-on-row key as default but at same time, if you are making a key
537    // without specifying type, etc., flag it as weird by setting type to be Maximum.
538    return createCell(row, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
539      HConstants.LATEST_TIMESTAMP, KeyValue.Type.Maximum.getCode(), value);
540  }
541
542  /**
543   * Create a Cell with specific row. Other fields defaulted.
544   * @return Cell with passed row but all other fields are arbitrary
545   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder}
546   *             instead
547   */
548  @Deprecated
549  public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier) {
550    // See above in createCell(final byte [] row, final byte [] value) why we set type to Maximum.
551    return createCell(row, family, qualifier, HConstants.LATEST_TIMESTAMP,
552      KeyValue.Type.Maximum.getCode(), HConstants.EMPTY_BYTE_ARRAY);
553  }
554
555  /**
556   * Note : Now only CPs can create cell with tags using the CP environment Within CP, use
557   * {@link RawCell#createCell(Cell, List)} method instead
558   * @return A new cell which is having the extra tags also added to it.
559   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
560   */
561  @Deprecated
562  public static Cell createCell(Cell cell, List<Tag> tags) {
563    return PrivateCellUtil.createCell(cell, tags);
564  }
565
566  /**
567   * Now only CPs can create cell with tags using the CP environment Within CP, use
568   * {@link RawCell#createCell(Cell, List)} method instead
569   * @return A new cell which is having the extra tags also added to it.
570   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
571   */
572  @Deprecated
573  public static Cell createCell(Cell cell, byte[] tags) {
574    return PrivateCellUtil.createCell(cell, tags);
575  }
576
577  /**
578   * Now only CPs can create cell with tags using the CP environment Within CP, use
579   * {@link RawCell#createCell(Cell, List)} method instead
580   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
581   */
582  @Deprecated
583  public static Cell createCell(Cell cell, byte[] value, byte[] tags) {
584    return PrivateCellUtil.createCell(cell, value, tags);
585  }
586
587  /** Returns CellScanner interface over <code>cellIterables</code> */
588  public static CellScanner
589    createCellScanner(final List<? extends CellScannable> cellScannerables) {
590    return new CellScanner() {
591      private final Iterator<? extends CellScannable> iterator = cellScannerables.iterator();
592      private CellScanner cellScanner = null;
593
594      @Override
595      public Cell current() {
596        return this.cellScanner != null ? this.cellScanner.current() : null;
597      }
598
599      @Override
600      public boolean advance() throws IOException {
601        while (true) {
602          if (this.cellScanner == null) {
603            if (!this.iterator.hasNext()) return false;
604            this.cellScanner = this.iterator.next().cellScanner();
605          }
606          if (this.cellScanner.advance()) return true;
607          this.cellScanner = null;
608        }
609      }
610    };
611  }
612
613  /** Returns CellScanner interface over <code>cellIterable</code> */
614  public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) {
615    if (cellIterable == null) return null;
616    return createCellScanner(cellIterable.iterator());
617  }
618
619  /**
620   * Returns CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is
621   * null
622   */
623  public static CellScanner createCellScanner(final Iterator<Cell> cells) {
624    if (cells == null) return null;
625    return new CellScanner() {
626      private final Iterator<Cell> iterator = cells;
627      private Cell current = null;
628
629      @Override
630      public Cell current() {
631        return this.current;
632      }
633
634      @Override
635      public boolean advance() {
636        boolean hasNext = this.iterator.hasNext();
637        this.current = hasNext ? this.iterator.next() : null;
638        return hasNext;
639      }
640    };
641  }
642
643  /** Returns CellScanner interface over <code>cellArray</code> */
644  public static CellScanner createCellScanner(final Cell[] cellArray) {
645    return new CellScanner() {
646      private final Cell[] cells = cellArray;
647      private int index = -1;
648
649      @Override
650      public Cell current() {
651        if (cells == null) return null;
652        return (index < 0) ? null : this.cells[index];
653      }
654
655      @Override
656      public boolean advance() {
657        if (cells == null) return false;
658        return ++index < this.cells.length;
659      }
660    };
661  }
662
663  /**
664   * Flatten the map of cells out under the CellScanner
665   * @param map Map of Cell Lists; for example, the map of families to Cells that is used inside
666   *            Put, etc., keeping Cells organized by family.
667   * @return CellScanner interface over <code>cellIterable</code>
668   */
669  public static CellScanner createCellScanner(final NavigableMap<byte[], List<Cell>> map) {
670    return new CellScanner() {
671      private final Iterator<Entry<byte[], List<Cell>>> entries = map.entrySet().iterator();
672      private Iterator<Cell> currentIterator = null;
673      private Cell currentCell;
674
675      @Override
676      public Cell current() {
677        return this.currentCell;
678      }
679
680      @Override
681      public boolean advance() {
682        while (true) {
683          if (this.currentIterator == null) {
684            if (!this.entries.hasNext()) return false;
685            this.currentIterator = this.entries.next().getValue().iterator();
686          }
687          if (this.currentIterator.hasNext()) {
688            this.currentCell = this.currentIterator.next();
689            return true;
690          }
691          this.currentCell = null;
692          this.currentIterator = null;
693        }
694      }
695    };
696  }
697
698  /**
699   * @return True if the rows in <code>left</code> and <code>right</code> Cells match
700   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Instead use
701   *             {@link #matchingRows(Cell, Cell)}
702   */
703  @Deprecated
704  public static boolean matchingRow(final Cell left, final Cell right) {
705    return matchingRows(left, right);
706  }
707
708  /**
709   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Instead use
710   *             {@link #matchingRows(Cell, byte[])}
711   */
712  @Deprecated
713  public static boolean matchingRow(final Cell left, final byte[] buf) {
714    return matchingRows(left, buf);
715  }
716
717  public static boolean matchingRows(final Cell left, final byte[] buf) {
718    if (buf == null) {
719      return left.getRowLength() == 0;
720    }
721    return PrivateCellUtil.matchingRows(left, buf, 0, buf.length);
722  }
723
724  /**
725   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Instead use
726   *             {@link #matchingRows(Cell, Cell)}
727   * @return true if the row is matching
728   */
729  @Deprecated
730  public static boolean matchingRow(final Cell left, final byte[] buf, final int offset,
731    final int length) {
732    if (left instanceof ByteBufferExtendedCell) {
733      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(),
734        ((ByteBufferExtendedCell) left).getRowPosition(), left.getRowLength(), buf, offset, length);
735    }
736    return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, offset,
737      length);
738  }
739
740  public static boolean matchingFamily(final Cell left, final Cell right) {
741    byte lfamlength = left.getFamilyLength();
742    byte rfamlength = right.getFamilyLength();
743    return matchingFamily(left, lfamlength, right, rfamlength);
744  }
745
746  public static boolean matchingFamily(final Cell left, final byte lfamlength, final Cell right,
747    final byte rfamlength) {
748    if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
749      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
750        ((ByteBufferExtendedCell) left).getFamilyPosition(), lfamlength,
751        ((ByteBufferExtendedCell) right).getFamilyByteBuffer(),
752        ((ByteBufferExtendedCell) right).getFamilyPosition(), rfamlength);
753    }
754    if (left instanceof ByteBufferExtendedCell) {
755      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
756        ((ByteBufferExtendedCell) left).getFamilyPosition(), lfamlength, right.getFamilyArray(),
757        right.getFamilyOffset(), rfamlength);
758    }
759    if (right instanceof ByteBufferExtendedCell) {
760      return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getFamilyByteBuffer(),
761        ((ByteBufferExtendedCell) right).getFamilyPosition(), rfamlength, left.getFamilyArray(),
762        left.getFamilyOffset(), lfamlength);
763    }
764    return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength,
765      right.getFamilyArray(), right.getFamilyOffset(), rfamlength);
766  }
767
768  public static boolean matchingFamily(final Cell left, final byte[] buf) {
769    if (buf == null) {
770      return left.getFamilyLength() == 0;
771    }
772    return PrivateCellUtil.matchingFamily(left, buf, 0, buf.length);
773  }
774
775  /**
776   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
777   */
778  @Deprecated
779  public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset,
780    final int length) {
781    if (left instanceof ByteBufferExtendedCell) {
782      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
783        ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(), buf, offset,
784        length);
785    }
786    return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf,
787      offset, length);
788  }
789
790  public static boolean matchingQualifier(final Cell left, final Cell right) {
791    int lqlength = left.getQualifierLength();
792    int rqlength = right.getQualifierLength();
793    return matchingQualifier(left, lqlength, right, rqlength);
794  }
795
796  private static boolean matchingQualifier(final Cell left, final int lqlength, final Cell right,
797    final int rqlength) {
798    if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
799      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
800        ((ByteBufferExtendedCell) left).getQualifierPosition(), lqlength,
801        ((ByteBufferExtendedCell) right).getQualifierByteBuffer(),
802        ((ByteBufferExtendedCell) right).getQualifierPosition(), rqlength);
803    }
804    if (left instanceof ByteBufferExtendedCell) {
805      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
806        ((ByteBufferExtendedCell) left).getQualifierPosition(), lqlength, right.getQualifierArray(),
807        right.getQualifierOffset(), rqlength);
808    }
809    if (right instanceof ByteBufferExtendedCell) {
810      return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getQualifierByteBuffer(),
811        ((ByteBufferExtendedCell) right).getQualifierPosition(), rqlength, left.getQualifierArray(),
812        left.getQualifierOffset(), lqlength);
813    }
814    return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), lqlength,
815      right.getQualifierArray(), right.getQualifierOffset(), rqlength);
816  }
817
818  /**
819   * Finds if the qualifier part of the cell and the KV serialized byte[] are equal
820   * @param buf the serialized keyvalue format byte[]
821   * @return true if the qualifier matches, false otherwise
822   */
823  public static boolean matchingQualifier(final Cell left, final byte[] buf) {
824    if (buf == null) {
825      return left.getQualifierLength() == 0;
826    }
827    return PrivateCellUtil.matchingQualifier(left, buf, 0, buf.length);
828  }
829
830  /**
831   * Finds if the qualifier part of the cell and the KV serialized byte[] are equal
832   * @param buf    the serialized keyvalue format byte[]
833   * @param offset the offset of the qualifier in the byte[]
834   * @param length the length of the qualifier in the byte[]
835   * @return true if the qualifier matches, false otherwise
836   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
837   */
838  @Deprecated
839  public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset,
840    final int length) {
841    if (buf == null) {
842      return left.getQualifierLength() == 0;
843    }
844    if (left instanceof ByteBufferExtendedCell) {
845      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
846        ((ByteBufferExtendedCell) left).getQualifierPosition(), left.getQualifierLength(), buf,
847        offset, length);
848    }
849    return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
850      left.getQualifierLength(), buf, offset, length);
851  }
852
853  public static boolean matchingColumn(final Cell left, final byte[] fam, final byte[] qual) {
854    return matchingFamily(left, fam) && matchingQualifier(left, qual);
855  }
856
857  /** Returns True if matching column family and the qualifier starts with <code>qual</code> */
858  public static boolean matchingColumnFamilyAndQualifierPrefix(final Cell left, final byte[] fam,
859    final byte[] qual) {
860    return matchingFamily(left, fam) && PrivateCellUtil.qualifierStartsWith(left, qual);
861  }
862
863  /**
864   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
865   */
866  @Deprecated
867  public static boolean matchingColumn(final Cell left, final byte[] fam, final int foffset,
868    final int flength, final byte[] qual, final int qoffset, final int qlength) {
869    if (!PrivateCellUtil.matchingFamily(left, fam, foffset, flength)) return false;
870    return PrivateCellUtil.matchingQualifier(left, qual, qoffset, qlength);
871  }
872
873  public static boolean matchingColumn(final Cell left, final Cell right) {
874    if (!matchingFamily(left, right)) return false;
875    return matchingQualifier(left, right);
876  }
877
878  private static boolean matchingColumn(final Cell left, final byte lFamLen, final int lQualLength,
879    final Cell right, final byte rFamLen, final int rQualLength) {
880    if (!matchingFamily(left, lFamLen, right, rFamLen)) {
881      return false;
882    }
883    return matchingQualifier(left, lQualLength, right, rQualLength);
884  }
885
886  public static boolean matchingValue(final Cell left, final Cell right) {
887    return PrivateCellUtil.matchingValue(left, right, left.getValueLength(),
888      right.getValueLength());
889  }
890
891  public static boolean matchingValue(final Cell left, final byte[] buf) {
892    if (left instanceof ByteBufferExtendedCell) {
893      return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getValueByteBuffer(),
894        ((ByteBufferExtendedCell) left).getValuePosition(), left.getValueLength(), buf, 0,
895        buf.length) == 0;
896    }
897    return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(), buf, 0,
898      buf.length);
899  }
900
901  public static boolean matchingTags(final Cell left, final Cell right) {
902    return PrivateCellUtil.matchingTags(left, right, left.getTagsLength(), right.getTagsLength());
903  }
904
905  /**
906   * @return True if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily}
907   *         or a {@link KeyValue.Type#DeleteColumn} KeyValue type.
908   */
909  @SuppressWarnings("deprecation")
910  public static boolean isDelete(final Cell cell) {
911    return PrivateCellUtil.isDelete(cell.getTypeByte());
912  }
913
914  /**
915   * @return True if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily}
916   *         or a {@link KeyValue.Type#DeleteColumn} KeyValue type.
917   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
918   */
919  @Deprecated
920  public static boolean isDelete(final byte type) {
921    return Type.Delete.getCode() <= type && type <= Type.DeleteFamily.getCode();
922  }
923
924  /**
925   * @return True if this cell is a {@link KeyValue.Type#Delete} type.
926   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
927   */
928  @Deprecated
929  public static boolean isDeleteType(Cell cell) {
930    return cell.getTypeByte() == Type.Delete.getCode();
931  }
932
933  /**
934   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
935   */
936  @Deprecated
937  public static boolean isDeleteFamily(final Cell cell) {
938    return cell.getTypeByte() == Type.DeleteFamily.getCode();
939  }
940
941  /**
942   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
943   */
944  @Deprecated
945  public static boolean isDeleteFamilyVersion(final Cell cell) {
946    return cell.getTypeByte() == Type.DeleteFamilyVersion.getCode();
947  }
948
949  /**
950   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
951   */
952  @Deprecated
953  public static boolean isDeleteColumns(final Cell cell) {
954    return cell.getTypeByte() == Type.DeleteColumn.getCode();
955  }
956
957  /**
958   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
959   */
960  @Deprecated
961  public static boolean isDeleteColumnVersion(final Cell cell) {
962    return cell.getTypeByte() == Type.Delete.getCode();
963  }
964
965  /**
966   * @return True if this cell is a delete family or column type.
967   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
968   */
969  @Deprecated
970  public static boolean isDeleteColumnOrFamily(Cell cell) {
971    int t = cell.getTypeByte();
972    return t == Type.DeleteColumn.getCode() || t == Type.DeleteFamily.getCode();
973  }
974
975  /** Returns True if this cell is a Put. */
976  @SuppressWarnings("deprecation")
977  public static boolean isPut(Cell cell) {
978    return cell.getTypeByte() == Type.Put.getCode();
979  }
980
981  /**
982   * Estimate based on keyvalue's serialization format in the RPC layer. Note that there is an extra
983   * SIZEOF_INT added to the size here that indicates the actual length of the cell for cases where
984   * cell's are serialized in a contiguous format (For eg in RPCs).
985   * @return Estimate of the <code>cell</code> size in bytes plus an extra SIZEOF_INT indicating the
986   *         actual cell length.
987   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
988   */
989  @Deprecated
990  public static int estimatedSerializedSizeOf(final Cell cell) {
991    if (cell instanceof ExtendedCell) {
992      return ((ExtendedCell) cell).getSerializedSize(true) + Bytes.SIZEOF_INT;
993    }
994
995    return getSumOfCellElementLengths(cell) +
996    // Use the KeyValue's infrastructure size presuming that another implementation would have
997    // same basic cost.
998      KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE +
999      // Serialization is probably preceded by a length (it is in the KeyValueCodec at least).
1000      Bytes.SIZEOF_INT;
1001  }
1002
1003  /**
1004   * Returns Sum of the lengths of all the elements in a Cell; does not count in any infrastructure
1005   */
1006  private static int getSumOfCellElementLengths(final Cell cell) {
1007    return getSumOfCellKeyElementLengths(cell) + cell.getValueLength() + cell.getTagsLength();
1008  }
1009
1010  /**
1011   * @return Sum of all elements that make up a key; does not include infrastructure, tags or
1012   *         values.
1013   */
1014  private static int getSumOfCellKeyElementLengths(final Cell cell) {
1015    return cell.getRowLength() + cell.getFamilyLength() + cell.getQualifierLength()
1016      + KeyValue.TIMESTAMP_TYPE_SIZE;
1017  }
1018
1019  /**
1020   * Calculates the serialized key size. We always serialize in the KeyValue's serialization format.
1021   * @param cell the cell for which the key size has to be calculated.
1022   * @return the key size
1023   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
1024   */
1025  @Deprecated
1026  public static int estimatedSerializedSizeOfKey(final Cell cell) {
1027    if (cell instanceof KeyValue) return ((KeyValue) cell).getKeyLength();
1028    return cell.getRowLength() + cell.getFamilyLength() + cell.getQualifierLength()
1029      + KeyValue.KEY_INFRASTRUCTURE_SIZE;
1030  }
1031
1032  /**
1033   * This is an estimate of the heap space occupied by a cell. When the cell is of type
1034   * {@link HeapSize} we call {@link HeapSize#heapSize()} so cell can give a correct value. In other
1035   * cases we just consider the bytes occupied by the cell components ie. row, CF, qualifier,
1036   * timestamp, type, value and tags.
1037   * @return estimate of the heap space
1038   * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use
1039   *             {@link RawCell#getTags()}
1040   */
1041  @Deprecated
1042  public static long estimatedHeapSizeOf(final Cell cell) {
1043    return cell.heapSize();
1044  }
1045
1046  /********************* tags *************************************/
1047  /**
1048   * Util method to iterate through the tags
1049   * @return iterator for the tags
1050   * @deprecated As of 2.0.0 and will be removed in 3.0.0 Instead use
1051   *             {@link PrivateCellUtil#tagsIterator(Cell)}
1052   */
1053  @Deprecated
1054  public static Iterator<Tag> tagsIterator(final byte[] tags, final int offset, final int length) {
1055    return new Iterator<Tag>() {
1056      private int pos = offset;
1057      private int endOffset = offset + length - 1;
1058
1059      @Override
1060      public boolean hasNext() {
1061        return this.pos < endOffset;
1062      }
1063
1064      @Override
1065      public Tag next() {
1066        if (hasNext()) {
1067          int curTagLen = Bytes.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE);
1068          Tag tag = new ArrayBackedTag(tags, pos, curTagLen + TAG_LENGTH_SIZE);
1069          this.pos += Bytes.SIZEOF_SHORT + curTagLen;
1070          return tag;
1071        }
1072        return null;
1073      }
1074
1075      @Override
1076      public void remove() {
1077        throw new UnsupportedOperationException();
1078      }
1079    };
1080  }
1081
1082  /**
1083   * @param cell The Cell
1084   * @return Tags in the given Cell as a List
1085   * @deprecated As of 2.0.0 and will be removed in 3.0.0
1086   */
1087  @Deprecated
1088  public static List<Tag> getTags(Cell cell) {
1089    List<Tag> tags = new ArrayList<>();
1090    Iterator<Tag> tagsItr = PrivateCellUtil.tagsIterator(cell);
1091    while (tagsItr.hasNext()) {
1092      tags.add(tagsItr.next());
1093    }
1094    return tags;
1095  }
1096
1097  /**
1098   * Retrieve Cell's first tag, matching the passed in type
1099   * @param cell The Cell
1100   * @param type Type of the Tag to retrieve
1101   * @return null if there is no tag of the passed in tag type
1102   * @deprecated As of 2.0.0 and will be removed in HBase-3.0.0 Use {@link RawCell#getTag(byte)}
1103   */
1104  @Deprecated
1105  public static Tag getTag(Cell cell, byte type) {
1106    Optional<Tag> tag = PrivateCellUtil.getTag(cell, type);
1107    if (tag.isPresent()) {
1108      return tag.get();
1109    } else {
1110      return null;
1111    }
1112  }
1113
1114  /**
1115   * Returns true if the first range start1...end1 overlaps with the second range start2...end2,
1116   * assuming the byte arrays represent row keys
1117   * @deprecated As of 2.0.0 and will be removed in 3.0.0
1118   */
1119  @Deprecated
1120  public static boolean overlappingKeys(final byte[] start1, final byte[] end1, final byte[] start2,
1121    final byte[] end2) {
1122    return (end2.length == 0 || start1.length == 0 || Bytes.compareTo(start1, end2) < 0)
1123      && (end1.length == 0 || start2.length == 0 || Bytes.compareTo(start2, end1) < 0);
1124  }
1125
1126  /**
1127   * Sets the given seqId to the cell. Marked as audience Private as of 1.2.0. Setting a Cell
1128   * sequenceid is an internal implementation detail not for general public use.
1129   * @throws IOException when the passed cell is not of type {@link ExtendedCell}
1130   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1131   */
1132  @Deprecated
1133  public static void setSequenceId(Cell cell, long seqId) throws IOException {
1134    PrivateCellUtil.setSequenceId(cell, seqId);
1135  }
1136
1137  /**
1138   * Sets the given timestamp to the cell.
1139   * @throws IOException when the passed cell is not of type {@link ExtendedCell}
1140   * @deprecated As of HBase-2.0. Will be a LimitedPrivate API in HBase-3.0.
1141   */
1142  @Deprecated
1143  public static void setTimestamp(Cell cell, long ts) throws IOException {
1144    PrivateCellUtil.setTimestamp(cell, ts);
1145  }
1146
1147  /**
1148   * Sets the given timestamp to the cell.
1149   * @param ts       buffer containing the timestamp value
1150   * @param tsOffset offset to the new timestamp
1151   * @throws IOException when the passed cell is not of type {@link ExtendedCell}
1152   * @deprecated As of HBase-2.0. Will be a LimitedPrivate API in HBase-3.0.
1153   */
1154  @Deprecated
1155  public static void setTimestamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
1156    PrivateCellUtil.setTimestamp(cell, Bytes.toLong(ts, tsOffset));
1157  }
1158
1159  /**
1160   * Sets the given timestamp to the cell iff current timestamp is
1161   * {@link HConstants#LATEST_TIMESTAMP}.
1162   * @return True if cell timestamp is modified.
1163   * @throws IOException when the passed cell is not of type {@link ExtendedCell}
1164   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1165   */
1166  @Deprecated
1167  public static boolean updateLatestStamp(Cell cell, long ts) throws IOException {
1168    return PrivateCellUtil.updateLatestStamp(cell, ts);
1169  }
1170
1171  /**
1172   * Sets the given timestamp to the cell iff current timestamp is
1173   * {@link HConstants#LATEST_TIMESTAMP}.
1174   * @param ts       buffer containing the timestamp value
1175   * @param tsOffset offset to the new timestamp
1176   * @return True if cell timestamp is modified.
1177   * @throws IOException when the passed cell is not of type {@link ExtendedCell}
1178   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1179   */
1180  @Deprecated
1181  public static boolean updateLatestStamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
1182    return PrivateCellUtil.updateLatestStamp(cell, Bytes.toLong(ts, tsOffset));
1183  }
1184
1185  /**
1186   * Writes the Cell's key part as it would have serialized in a KeyValue. The format is &lt;2 bytes
1187   * rk len&gt;&lt;rk&gt;&lt;1 byte cf len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes
1188   * timestamp&gt;&lt;1 byte type&gt;
1189   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1190   */
1191  @Deprecated
1192  public static void writeFlatKey(Cell cell, DataOutputStream out) throws IOException {
1193    short rowLen = cell.getRowLength();
1194    byte fLen = cell.getFamilyLength();
1195    int qLen = cell.getQualifierLength();
1196    // Using just one if/else loop instead of every time checking before writing every
1197    // component of cell
1198    if (cell instanceof ByteBufferExtendedCell) {
1199      out.writeShort(rowLen);
1200      ByteBufferUtils.copyBufferToStream((DataOutput) out,
1201        ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
1202        ((ByteBufferExtendedCell) cell).getRowPosition(), rowLen);
1203      out.writeByte(fLen);
1204      ByteBufferUtils.copyBufferToStream((DataOutput) out,
1205        ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
1206        ((ByteBufferExtendedCell) cell).getFamilyPosition(), fLen);
1207      ByteBufferUtils.copyBufferToStream((DataOutput) out,
1208        ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
1209        ((ByteBufferExtendedCell) cell).getQualifierPosition(), qLen);
1210    } else {
1211      out.writeShort(rowLen);
1212      out.write(cell.getRowArray(), cell.getRowOffset(), rowLen);
1213      out.writeByte(fLen);
1214      out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen);
1215      out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen);
1216    }
1217    out.writeLong(cell.getTimestamp());
1218    out.writeByte(cell.getTypeByte());
1219  }
1220
1221  /**
1222   * Writes the row from the given cell to the output stream excluding the common prefix
1223   * @param out     The dataoutputstream to which the data has to be written
1224   * @param cell    The cell whose contents has to be written
1225   * @param rlength the row length
1226   * @deprecated As of 2.0. Will be removed in hbase-3.0
1227   */
1228  @Deprecated
1229  public static void writeRowSkippingBytes(DataOutputStream out, Cell cell, short rlength,
1230    int commonPrefix) throws IOException {
1231    if (cell instanceof ByteBufferExtendedCell) {
1232      ByteBufferUtils.copyBufferToStream((DataOutput) out,
1233        ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
1234        ((ByteBufferExtendedCell) cell).getRowPosition() + commonPrefix, rlength - commonPrefix);
1235    } else {
1236      out.write(cell.getRowArray(), cell.getRowOffset() + commonPrefix, rlength - commonPrefix);
1237    }
1238  }
1239
1240  /** Returns The Key portion of the passed <code>cell</code> as a String. */
1241  public static String getCellKeyAsString(Cell cell) {
1242    return getCellKeyAsString(cell,
1243      c -> Bytes.toStringBinary(c.getRowArray(), c.getRowOffset(), c.getRowLength()));
1244  }
1245
1246  /**
1247   * @param cell         the cell to convert
1248   * @param rowConverter used to convert the row of the cell to a string
1249   * @return The Key portion of the passed <code>cell</code> as a String.
1250   */
1251  public static String getCellKeyAsString(Cell cell, Function<Cell, String> rowConverter) {
1252    StringBuilder sb = new StringBuilder(rowConverter.apply(cell));
1253    sb.append('/');
1254    sb.append(cell.getFamilyLength() == 0
1255      ? ""
1256      : Bytes.toStringBinary(cell.getFamilyArray(), cell.getFamilyOffset(),
1257        cell.getFamilyLength()));
1258    // KeyValue only added ':' if family is non-null. Do same.
1259    if (cell.getFamilyLength() > 0) sb.append(':');
1260    sb.append(cell.getQualifierLength() == 0
1261      ? ""
1262      : Bytes.toStringBinary(cell.getQualifierArray(), cell.getQualifierOffset(),
1263        cell.getQualifierLength()));
1264    sb.append('/');
1265    sb.append(KeyValue.humanReadableTimestamp(cell.getTimestamp()));
1266    sb.append('/');
1267    sb.append(Type.codeToType(cell.getTypeByte()));
1268    if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
1269      sb.append("/vlen=");
1270      sb.append(cell.getValueLength());
1271    }
1272    sb.append("/seqid=");
1273    sb.append(cell.getSequenceId());
1274    return sb.toString();
1275  }
1276
1277  /**
1278   * This method exists just to encapsulate how we serialize keys. To be replaced by a factory that
1279   * we query to figure what the Cell implementation is and then, what serialization engine to use
1280   * and further, how to serialize the key for inclusion in hfile index. TODO.
1281   * @return The key portion of the Cell serialized in the old-school KeyValue way or null if passed
1282   *         a null <code>cell</code>
1283   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1284   */
1285  @Deprecated
1286  public static byte[] getCellKeySerializedAsKeyValueKey(final Cell cell) {
1287    if (cell == null) return null;
1288    byte[] b = new byte[KeyValueUtil.keyLength(cell)];
1289    KeyValueUtil.appendKeyTo(cell, b, 0);
1290    return b;
1291  }
1292
1293  /**
1294   * Write rowkey excluding the common part.
1295   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1296   */
1297  @Deprecated
1298  public static void writeRowKeyExcludingCommon(Cell cell, short rLen, int commonPrefix,
1299    DataOutputStream out) throws IOException {
1300    if (commonPrefix == 0) {
1301      out.writeShort(rLen);
1302    } else if (commonPrefix == 1) {
1303      out.writeByte((byte) rLen);
1304      commonPrefix--;
1305    } else {
1306      commonPrefix -= KeyValue.ROW_LENGTH_SIZE;
1307    }
1308    if (rLen > commonPrefix) {
1309      PrivateCellUtil.writeRowSkippingBytes(out, cell, rLen, commonPrefix);
1310    }
1311  }
1312
1313  /**
1314   * Find length of common prefix in keys of the cells, considering key as byte[] if serialized in
1315   * {@link KeyValue}. The key format is &lt;2 bytes rk len&gt;&lt;rk&gt;&lt;1 byte cf
1316   * len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes timestamp&gt;&lt;1 byte type&gt;
1317   * @param c1                the cell
1318   * @param c2                the cell
1319   * @param bypassFamilyCheck when true assume the family bytes same in both cells. Pass it as true
1320   *                          when dealing with Cells in same CF so as to avoid some checks
1321   * @param withTsType        when true check timestamp and type bytes also.
1322   * @return length of common prefix
1323   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1324   */
1325  @Deprecated
1326  public static int findCommonPrefixInFlatKey(Cell c1, Cell c2, boolean bypassFamilyCheck,
1327    boolean withTsType) {
1328    // Compare the 2 bytes in RK length part
1329    short rLen1 = c1.getRowLength();
1330    short rLen2 = c2.getRowLength();
1331    int commonPrefix = KeyValue.ROW_LENGTH_SIZE;
1332    if (rLen1 != rLen2) {
1333      // early out when the RK length itself is not matching
1334      return ByteBufferUtils.findCommonPrefix(Bytes.toBytes(rLen1), 0, KeyValue.ROW_LENGTH_SIZE,
1335        Bytes.toBytes(rLen2), 0, KeyValue.ROW_LENGTH_SIZE);
1336    }
1337    // Compare the RKs
1338    int rkCommonPrefix = 0;
1339    if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) {
1340      rkCommonPrefix =
1341        ByteBufferUtils.findCommonPrefix(((ByteBufferExtendedCell) c1).getRowByteBuffer(),
1342          ((ByteBufferExtendedCell) c1).getRowPosition(), rLen1,
1343          ((ByteBufferExtendedCell) c2).getRowByteBuffer(),
1344          ((ByteBufferExtendedCell) c2).getRowPosition(), rLen2);
1345    } else {
1346      // There cannot be a case where one cell is BBCell and other is KeyValue. This flow comes
1347      // either
1348      // in flush or compactions. In flushes both cells are KV and in case of compaction it will be
1349      // either
1350      // KV or BBCell
1351      rkCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getRowArray(), c1.getRowOffset(), rLen1,
1352        c2.getRowArray(), c2.getRowOffset(), rLen2);
1353    }
1354    commonPrefix += rkCommonPrefix;
1355    if (rkCommonPrefix != rLen1) {
1356      // Early out when RK is not fully matching.
1357      return commonPrefix;
1358    }
1359    // Compare 1 byte CF length part
1360    byte fLen1 = c1.getFamilyLength();
1361    if (bypassFamilyCheck) {
1362      // This flag will be true when caller is sure that the family will be same for both the cells
1363      // Just make commonPrefix to increment by the family part
1364      commonPrefix += KeyValue.FAMILY_LENGTH_SIZE + fLen1;
1365    } else {
1366      byte fLen2 = c2.getFamilyLength();
1367      if (fLen1 != fLen2) {
1368        // early out when the CF length itself is not matching
1369        return commonPrefix;
1370      }
1371      // CF lengths are same so there is one more byte common in key part
1372      commonPrefix += KeyValue.FAMILY_LENGTH_SIZE;
1373      // Compare the CF names
1374      int fCommonPrefix;
1375      if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) {
1376        fCommonPrefix =
1377          ByteBufferUtils.findCommonPrefix(((ByteBufferExtendedCell) c1).getFamilyByteBuffer(),
1378            ((ByteBufferExtendedCell) c1).getFamilyPosition(), fLen1,
1379            ((ByteBufferExtendedCell) c2).getFamilyByteBuffer(),
1380            ((ByteBufferExtendedCell) c2).getFamilyPosition(), fLen2);
1381      } else {
1382        fCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getFamilyArray(), c1.getFamilyOffset(),
1383          fLen1, c2.getFamilyArray(), c2.getFamilyOffset(), fLen2);
1384      }
1385      commonPrefix += fCommonPrefix;
1386      if (fCommonPrefix != fLen1) {
1387        return commonPrefix;
1388      }
1389    }
1390    // Compare the Qualifiers
1391    int qLen1 = c1.getQualifierLength();
1392    int qLen2 = c2.getQualifierLength();
1393    int qCommon;
1394    if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) {
1395      qCommon =
1396        ByteBufferUtils.findCommonPrefix(((ByteBufferExtendedCell) c1).getQualifierByteBuffer(),
1397          ((ByteBufferExtendedCell) c1).getQualifierPosition(), qLen1,
1398          ((ByteBufferExtendedCell) c2).getQualifierByteBuffer(),
1399          ((ByteBufferExtendedCell) c2).getQualifierPosition(), qLen2);
1400    } else {
1401      qCommon = ByteBufferUtils.findCommonPrefix(c1.getQualifierArray(), c1.getQualifierOffset(),
1402        qLen1, c2.getQualifierArray(), c2.getQualifierOffset(), qLen2);
1403    }
1404    commonPrefix += qCommon;
1405    if (!withTsType || Math.max(qLen1, qLen2) != qCommon) {
1406      return commonPrefix;
1407    }
1408    // Compare the timestamp parts
1409    int tsCommonPrefix = ByteBufferUtils.findCommonPrefix(Bytes.toBytes(c1.getTimestamp()), 0,
1410      KeyValue.TIMESTAMP_SIZE, Bytes.toBytes(c2.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE);
1411    commonPrefix += tsCommonPrefix;
1412    if (tsCommonPrefix != KeyValue.TIMESTAMP_SIZE) {
1413      return commonPrefix;
1414    }
1415    // Compare the type
1416    if (c1.getTypeByte() == c2.getTypeByte()) {
1417      commonPrefix += KeyValue.TYPE_SIZE;
1418    }
1419    return commonPrefix;
1420  }
1421
1422  /** Returns a string representation of the cell */
1423  public static String toString(Cell cell, boolean verbose) {
1424    if (cell == null) {
1425      return "";
1426    }
1427    StringBuilder builder = new StringBuilder();
1428    String keyStr = getCellKeyAsString(cell);
1429
1430    String tag = null;
1431    String value = null;
1432    if (verbose) {
1433      // TODO: pretty print tags as well
1434      if (cell.getTagsLength() > 0) {
1435        tag = Bytes.toStringBinary(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
1436      }
1437      if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
1438        value =
1439          Bytes.toStringBinary(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
1440      }
1441    }
1442
1443    builder.append(keyStr);
1444    if (tag != null && !tag.isEmpty()) {
1445      builder.append("/").append(tag);
1446    }
1447    if (value != null) {
1448      builder.append("/").append(value);
1449    }
1450
1451    return builder.toString();
1452  }
1453
1454  /***************** special cases ****************************/
1455
1456  /**
1457   * special case for Cell.equals
1458   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1459   */
1460  @Deprecated
1461  public static boolean equalsIgnoreMvccVersion(Cell a, Cell b) {
1462    // row
1463    boolean res = matchingRows(a, b);
1464    if (!res) return res;
1465
1466    // family
1467    res = matchingColumn(a, b);
1468    if (!res) return res;
1469
1470    // timestamp: later sorts first
1471    if (!matchingTimestamp(a, b)) return false;
1472
1473    // type
1474    int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
1475    if (c != 0) return false;
1476    else return true;
1477  }
1478
1479  /**************** equals ****************************/
1480
1481  public static boolean equals(Cell a, Cell b) {
1482    return matchingRows(a, b) && matchingFamily(a, b) && matchingQualifier(a, b)
1483      && matchingTimestamp(a, b) && PrivateCellUtil.matchingType(a, b);
1484  }
1485
1486  public static boolean matchingTimestamp(Cell a, Cell b) {
1487    return CellComparator.getInstance().compareTimestamps(a.getTimestamp(), b.getTimestamp()) == 0;
1488  }
1489
1490  /**
1491   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1492   */
1493  @Deprecated
1494  public static boolean matchingType(Cell a, Cell b) {
1495    return a.getTypeByte() == b.getTypeByte();
1496  }
1497
1498  /**
1499   * Compares the row of two keyvalues for equality
1500   * @return True if rows match.
1501   */
1502  public static boolean matchingRows(final Cell left, final Cell right) {
1503    short lrowlength = left.getRowLength();
1504    short rrowlength = right.getRowLength();
1505    return matchingRows(left, lrowlength, right, rrowlength);
1506  }
1507
1508  public static boolean matchingRows(final Cell left, final short lrowlength, final Cell right,
1509    final short rrowlength) {
1510    if (lrowlength != rrowlength) return false;
1511    if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
1512      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(),
1513        ((ByteBufferExtendedCell) left).getRowPosition(), lrowlength,
1514        ((ByteBufferExtendedCell) right).getRowByteBuffer(),
1515        ((ByteBufferExtendedCell) right).getRowPosition(), rrowlength);
1516    }
1517    if (left instanceof ByteBufferExtendedCell) {
1518      return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(),
1519        ((ByteBufferExtendedCell) left).getRowPosition(), lrowlength, right.getRowArray(),
1520        right.getRowOffset(), rrowlength);
1521    }
1522    if (right instanceof ByteBufferExtendedCell) {
1523      return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getRowByteBuffer(),
1524        ((ByteBufferExtendedCell) right).getRowPosition(), rrowlength, left.getRowArray(),
1525        left.getRowOffset(), lrowlength);
1526    }
1527    return Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(),
1528      right.getRowOffset(), rrowlength);
1529  }
1530
1531  /**
1532   * Compares the row and column of two keyvalues for equality
1533   * @return True if same row and column.
1534   */
1535  public static boolean matchingRowColumn(final Cell left, final Cell right) {
1536    short lrowlength = left.getRowLength();
1537    short rrowlength = right.getRowLength();
1538    // match length
1539    if (lrowlength != rrowlength) {
1540      return false;
1541    }
1542
1543    byte lfamlength = left.getFamilyLength();
1544    byte rfamlength = right.getFamilyLength();
1545    if (lfamlength != rfamlength) {
1546      return false;
1547    }
1548
1549    int lqlength = left.getQualifierLength();
1550    int rqlength = right.getQualifierLength();
1551    if (lqlength != rqlength) {
1552      return false;
1553    }
1554
1555    if (!matchingRows(left, lrowlength, right, rrowlength)) {
1556      return false;
1557    }
1558    return matchingColumn(left, lfamlength, lqlength, right, rfamlength, rqlength);
1559  }
1560
1561  public static boolean matchingRowColumnBytes(final Cell left, final Cell right) {
1562    int lrowlength = left.getRowLength();
1563    int rrowlength = right.getRowLength();
1564    int lfamlength = left.getFamilyLength();
1565    int rfamlength = right.getFamilyLength();
1566    int lqlength = left.getQualifierLength();
1567    int rqlength = right.getQualifierLength();
1568
1569    // match length
1570    if ((lrowlength != rrowlength) || (lfamlength != rfamlength) || (lqlength != rqlength)) {
1571      return false;
1572    }
1573
1574    // match row
1575    if (
1576      !Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(),
1577        right.getRowOffset(), rrowlength)
1578    ) {
1579      return false;
1580    }
1581    // match family
1582    if (
1583      !Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength,
1584        right.getFamilyArray(), right.getFamilyOffset(), rfamlength)
1585    ) {
1586      return false;
1587    }
1588    // match qualifier
1589    return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), lqlength,
1590      right.getQualifierArray(), right.getQualifierOffset(), rqlength);
1591  }
1592
1593  /**
1594   * Compares the cell's qualifier with the given byte[]
1595   * @param left    the cell for which the qualifier has to be compared
1596   * @param right   the byte[] having the qualifier
1597   * @param rOffset the offset of the qualifier
1598   * @param rLength the length of the qualifier
1599   * @return greater than 0 if left cell's qualifier is bigger than byte[], lesser than 0 if left
1600   *         cell's qualifier is lesser than byte[] and 0 otherwise
1601   */
1602  public final static int compareQualifiers(Cell left, byte[] right, int rOffset, int rLength) {
1603    if (left instanceof ByteBufferExtendedCell) {
1604      return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
1605        ((ByteBufferExtendedCell) left).getQualifierPosition(), left.getQualifierLength(), right,
1606        rOffset, rLength);
1607    }
1608    return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset(),
1609      left.getQualifierLength(), right, rOffset, rLength);
1610  }
1611
1612  /**
1613   * Used when a cell needs to be compared with a key byte[] such as cases of finding the index from
1614   * the index block, bloom keys from the bloom blocks This byte[] is expected to be serialized in
1615   * the KeyValue serialization format If the KeyValue (Cell's) serialization format changes this
1616   * method cannot be used.
1617   * @param comparator the cell comparator
1618   * @param left       the cell to be compared
1619   * @param key        the serialized key part of a KeyValue
1620   * @param offset     the offset in the key byte[]
1621   * @param length     the length of the key byte[]
1622   * @return an int greater than 0 if left is greater than right lesser than 0 if left is lesser
1623   *         than right equal to 0 if left is equal to right
1624   * @deprecated As of HBase-2.0. Will be removed in HBase-3.0
1625   */
1626  @InterfaceAudience.Private
1627  @Deprecated
1628  public static final int compare(CellComparator comparator, Cell left, byte[] key, int offset,
1629    int length) {
1630    // row
1631    short rrowlength = Bytes.toShort(key, offset);
1632    int c = comparator.compareRows(left, key, offset + Bytes.SIZEOF_SHORT, rrowlength);
1633    if (c != 0) return c;
1634
1635    // Compare the rest of the two KVs without making any assumptions about
1636    // the common prefix. This function will not compare rows anyway, so we
1637    // don't need to tell it that the common prefix includes the row.
1638    return PrivateCellUtil.compareWithoutRow(comparator, left, key, offset, length, rrowlength);
1639  }
1640
1641  /**
1642   * Compares the cell's family with the given byte[]
1643   * @param left    the cell for which the family has to be compared
1644   * @param right   the byte[] having the family
1645   * @param roffset the offset of the family
1646   * @param rlength the length of the family
1647   * @return greater than 0 if left cell's family is bigger than byte[], lesser than 0 if left
1648   *         cell's family is lesser than byte[] and 0 otherwise
1649   */
1650  public final static int compareFamilies(Cell left, byte[] right, int roffset, int rlength) {
1651    if (left instanceof ByteBufferExtendedCell) {
1652      return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
1653        ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(), right, roffset,
1654        rlength);
1655    }
1656    return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
1657      right, roffset, rlength);
1658  }
1659
1660  /**
1661   * Compares the cell's column (family and qualifier) with the given byte[]
1662   * @param left     the cell for which the column has to be compared
1663   * @param right    the byte[] having the column
1664   * @param rfoffset the offset of the family
1665   * @param rflength the length of the family
1666   * @param rqoffset the offset of the qualifier
1667   * @param rqlength the length of the qualifier
1668   * @return greater than 0 if left cell's column is bigger than byte[], lesser than 0 if left
1669   *         cell's column is lesser than byte[] and 0 otherwise
1670   */
1671  public final static int compareColumns(Cell left, byte[] right, int rfoffset, int rflength,
1672    int rqoffset, int rqlength) {
1673    int diff = compareFamilies(left, right, rfoffset, rflength);
1674    if (diff != 0) return diff;
1675    return compareQualifiers(left, right, rqoffset, rqlength);
1676  }
1677
1678  public static void cloneIfNecessary(ArrayList<Cell> cells) {
1679    if (cells == null || cells.isEmpty()) {
1680      return;
1681    }
1682    for (int i = 0; i < cells.size(); i++) {
1683      Cell cell = cells.get(i);
1684      cells.set(i, cloneIfNecessary(cell));
1685    }
1686  }
1687
1688  public static Cell cloneIfNecessary(Cell cell) {
1689    return (cell instanceof ByteBufferExtendedCell ? KeyValueUtil.copyToNewKeyValue(cell) : cell);
1690  }
1691}