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 java.nio.ByteBuffer;
021import java.util.Collection;
022import java.util.List;
023import org.apache.commons.lang3.StringUtils;
024import org.apache.hadoop.hbase.util.Bytes;
025import org.apache.hadoop.hbase.util.Strings;
026import org.apache.yetus.audience.InterfaceAudience;
027
028import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
029import org.apache.hbase.thirdparty.org.apache.commons.collections4.IterableUtils;
030
031@InterfaceAudience.Private
032public class KeyValueTestUtil {
033
034  public static KeyValue create(String row, String family, String qualifier, long timestamp,
035    String value) {
036    return create(row, family, qualifier, timestamp, KeyValue.Type.Put, value);
037  }
038
039  public static KeyValue create(String row, String family, String qualifier, long timestamp,
040    KeyValue.Type type, String value) {
041    return new KeyValue(Bytes.toBytes(row), Bytes.toBytes(family), Bytes.toBytes(qualifier),
042      timestamp, type, Bytes.toBytes(value));
043  }
044
045  public static ByteBuffer toByteBufferAndRewind(final Iterable<? extends KeyValue> kvs,
046    boolean includeMemstoreTS) {
047    int totalBytes = KeyValueUtil.totalLengthWithMvccVersion(kvs, includeMemstoreTS);
048    ByteBuffer bb = ByteBuffer.allocate(totalBytes);
049    for (KeyValue kv : IterableUtils.emptyIfNull(kvs)) {
050      KeyValueUtil.appendToByteBuffer(bb, kv, includeMemstoreTS);
051    }
052    bb.rewind();
053    return bb;
054  }
055
056  /**
057   * Checks whether KeyValues from kvCollection2 are contained in kvCollection1. The comparison is
058   * made without distinguishing MVCC version of the KeyValues
059   * @return true if KeyValues from kvCollection2 are contained in kvCollection1
060   */
061  public static boolean containsIgnoreMvccVersion(Collection<? extends Cell> kvCollection1,
062    Collection<? extends Cell> kvCollection2) {
063    for (Cell kv1 : kvCollection1) {
064      boolean found = false;
065      for (Cell kv2 : kvCollection2) {
066        if (PrivateCellUtil.equalsIgnoreMvccVersion(kv1, kv2)) found = true;
067      }
068      if (!found) return false;
069    }
070    return true;
071  }
072
073  public static List<KeyValue> rewindThenToList(final ByteBuffer bb,
074    final boolean includesMemstoreTS, final boolean useTags) {
075    bb.rewind();
076    List<KeyValue> kvs = Lists.newArrayList();
077    KeyValue kv = null;
078    while (true) {
079      kv = KeyValueUtil.nextShallowCopy(bb, includesMemstoreTS, useTags);
080      if (kv == null) {
081        break;
082      }
083      kvs.add(kv);
084    }
085    return kvs;
086  }
087
088  /********************* toString ************************************/
089
090  public static String toStringWithPadding(final Collection<? extends KeyValue> kvs,
091    final boolean includeMeta) {
092    int maxRowStringLength = 0;
093    int maxFamilyStringLength = 0;
094    int maxQualifierStringLength = 0;
095    int maxTimestampLength = 0;
096    for (KeyValue kv : kvs) {
097      maxRowStringLength = Math.max(maxRowStringLength, getRowString(kv).length());
098      maxFamilyStringLength = Math.max(maxFamilyStringLength, getFamilyString(kv).length());
099      maxQualifierStringLength =
100        Math.max(maxQualifierStringLength, getQualifierString(kv).length());
101      maxTimestampLength =
102        Math.max(maxTimestampLength, Long.valueOf(kv.getTimestamp()).toString().length());
103    }
104    StringBuilder sb = new StringBuilder();
105    for (KeyValue kv : kvs) {
106      if (sb.length() > 0) {
107        sb.append("\n");
108      }
109      String row = toStringWithPadding(kv, maxRowStringLength, maxFamilyStringLength,
110        maxQualifierStringLength, maxTimestampLength, includeMeta);
111      sb.append(row);
112    }
113    return sb.toString();
114  }
115
116  protected static String toStringWithPadding(final KeyValue kv, final int maxRowLength,
117    int maxFamilyLength, int maxQualifierLength, int maxTimestampLength, boolean includeMeta) {
118    String leadingLengths = "";
119    String familyLength = kv.getFamilyLength() + " ";
120    if (includeMeta) {
121      leadingLengths += Strings.padFront(kv.getKeyLength() + "", '0', 4);
122      leadingLengths += " ";
123      leadingLengths += Strings.padFront(kv.getValueLength() + "", '0', 4);
124      leadingLengths += " ";
125      leadingLengths += Strings.padFront(kv.getRowLength() + "", '0', 2);
126      leadingLengths += " ";
127    }
128    int spacesAfterRow = maxRowLength - getRowString(kv).length() + 2;
129    int spacesAfterFamily = maxFamilyLength - getFamilyString(kv).length() + 2;
130    int spacesAfterQualifier = maxQualifierLength - getQualifierString(kv).length() + 1;
131    int spacesAfterTimestamp =
132      maxTimestampLength - Long.valueOf(kv.getTimestamp()).toString().length() + 1;
133    return leadingLengths + getRowString(kv) + StringUtils.repeat(' ', spacesAfterRow)
134      + familyLength + getFamilyString(kv) + StringUtils.repeat(' ', spacesAfterFamily)
135      + getQualifierString(kv) + StringUtils.repeat(' ', spacesAfterQualifier)
136      + getTimestampString(kv) + StringUtils.repeat(' ', spacesAfterTimestamp) + getTypeString(kv)
137      + " " + getValueString(kv);
138  }
139
140  protected static String getRowString(final KeyValue kv) {
141    return Bytes.toStringBinary(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength());
142  }
143
144  protected static String getFamilyString(final KeyValue kv) {
145    return Bytes.toStringBinary(kv.getFamilyArray(), kv.getFamilyOffset(), kv.getFamilyLength());
146  }
147
148  protected static String getQualifierString(final KeyValue kv) {
149    return Bytes.toStringBinary(kv.getQualifierArray(), kv.getQualifierOffset(),
150      kv.getQualifierLength());
151  }
152
153  protected static String getTimestampString(final KeyValue kv) {
154    return kv.getTimestamp() + "";
155  }
156
157  protected static String getTypeString(final KeyValue kv) {
158    return KeyValue.Type.codeToType(kv.getTypeByte()).toString();
159  }
160
161  protected static String getValueString(final KeyValue kv) {
162    return Bytes.toStringBinary(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength());
163  }
164
165}