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