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