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.util; 019 020import static org.apache.hadoop.hbase.regionserver.HStoreFile.BULKLOAD_TIME_KEY; 021import static org.junit.Assert.assertArrayEquals; 022import static org.junit.Assert.fail; 023 024import java.io.IOException; 025import java.util.Locale; 026import java.util.Optional; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.fs.FileSystem; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.hbase.ArrayBackedTag; 031import org.apache.hadoop.hbase.Cell; 032import org.apache.hadoop.hbase.ExtendedCell; 033import org.apache.hadoop.hbase.KeyValue; 034import org.apache.hadoop.hbase.PrivateCellUtil; 035import org.apache.hadoop.hbase.Tag; 036import org.apache.hadoop.hbase.TagType; 037import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 038import org.apache.hadoop.hbase.client.Result; 039import org.apache.hadoop.hbase.client.ResultScanner; 040import org.apache.hadoop.hbase.client.Scan; 041import org.apache.hadoop.hbase.client.Table; 042import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; 043import org.apache.hadoop.hbase.io.hfile.CacheConfig; 044import org.apache.hadoop.hbase.io.hfile.HFile; 045import org.apache.hadoop.hbase.io.hfile.HFileContext; 046import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder; 047import org.apache.hadoop.hbase.mob.MobUtils; 048 049/** 050 * Utility class for HFile-related testing. 051 */ 052public class HFileTestUtil { 053 public static final String OPT_DATA_BLOCK_ENCODING = 054 ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING.toLowerCase(Locale.ROOT); 055 /** Column family used by the test */ 056 public static byte[] DEFAULT_COLUMN_FAMILY = Bytes.toBytes("test_cf"); 057 /** Column families used by the test */ 058 public static final byte[][] DEFAULT_COLUMN_FAMILIES = { DEFAULT_COLUMN_FAMILY }; 059 060 /** 061 * Create an HFile with the given number of rows between a given start key and end key @ 062 * family:qualifier. The value will be the key value. This file will not have tags. 063 */ 064 public static void createHFile(Configuration configuration, FileSystem fs, Path path, 065 byte[] family, byte[] qualifier, byte[] startKey, byte[] endKey, int numRows) 066 throws IOException { 067 createHFile(configuration, fs, path, DataBlockEncoding.NONE, family, qualifier, startKey, 068 endKey, numRows, false); 069 } 070 071 /** 072 * Create an HFile with the given number of rows between a given start key and end key @ 073 * family:qualifier. The value will be the key value. This file will use certain data block 074 * encoding algorithm. 075 */ 076 public static void createHFileWithDataBlockEncoding(Configuration configuration, FileSystem fs, 077 Path path, DataBlockEncoding encoding, byte[] family, byte[] qualifier, byte[] startKey, 078 byte[] endKey, int numRows) throws IOException { 079 createHFile(configuration, fs, path, encoding, family, qualifier, startKey, endKey, numRows, 080 false); 081 } 082 083 /** 084 * Create an HFile with the given number of rows between a given start key and end key @ 085 * family:qualifier. The value will be the key value. This cells will also have a tag whose value 086 * is the key. 087 */ 088 public static void createHFileWithTags(Configuration configuration, FileSystem fs, Path path, 089 byte[] family, byte[] qualifier, byte[] startKey, byte[] endKey, int numRows) 090 throws IOException { 091 createHFile(configuration, fs, path, DataBlockEncoding.NONE, family, qualifier, startKey, 092 endKey, numRows, true); 093 } 094 095 /** 096 * Create an HFile with the given number of rows between a given start key and end key @ 097 * family:qualifier. If withTag is true, we add the rowKey as the tag value for tagtype 098 * MOB_TABLE_NAME_TAG_TYPE 099 */ 100 public static void createHFile(Configuration configuration, FileSystem fs, Path path, 101 DataBlockEncoding encoding, byte[] family, byte[] qualifier, byte[] startKey, byte[] endKey, 102 int numRows, boolean withTag) throws IOException { 103 HFileContext meta = new HFileContextBuilder().withIncludesTags(withTag) 104 .withDataBlockEncoding(encoding).withColumnFamily(family).build(); 105 HFile.Writer writer = HFile.getWriterFactory(configuration, new CacheConfig(configuration)) 106 .withPath(fs, path).withFileContext(meta).create(); 107 long now = EnvironmentEdgeManager.currentTime(); 108 try { 109 // subtract 2 since iterateOnSplits doesn't include boundary keys 110 for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, numRows - 2)) { 111 ExtendedCell kv = new KeyValue(key, family, qualifier, now, key); 112 if (withTag) { 113 // add a tag. Arbitrarily chose mob tag since we have a helper already. 114 Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, key); 115 kv = MobUtils.createMobRefCell(kv, key, tableNameTag); 116 117 // verify that the kv has the tag. 118 Optional<Tag> tag = PrivateCellUtil.getTag(kv, TagType.MOB_TABLE_NAME_TAG_TYPE); 119 if (!tag.isPresent()) { 120 throw new IllegalStateException("Tag didn't stick to KV " + kv.toString()); 121 } 122 } 123 writer.append(kv); 124 } 125 } finally { 126 writer.appendFileInfo(BULKLOAD_TIME_KEY, Bytes.toBytes(EnvironmentEdgeManager.currentTime())); 127 writer.close(); 128 } 129 } 130 131 /** 132 * This verifies that each cell has a tag that is equal to its rowkey name. For this to work the 133 * hbase instance must have HConstants.RPC_CODEC_CONF_KEY set to 134 * KeyValueCodecWithTags.class.getCanonicalName()); 135 * @param table table containing tagged cells 136 * @throws IOException if problems reading table 137 */ 138 public static void verifyTags(Table table) throws IOException { 139 ResultScanner s = table.getScanner(new Scan()); 140 for (Result r : s) { 141 for (Cell c : r.listCells()) { 142 Optional<Tag> tag = 143 PrivateCellUtil.getTag((ExtendedCell) c, TagType.MOB_TABLE_NAME_TAG_TYPE); 144 if (!tag.isPresent()) { 145 fail(c.toString() + " has null tag"); 146 continue; 147 } 148 Tag t = tag.get(); 149 byte[] tval = Tag.cloneValue(t); 150 assertArrayEquals(c.toString() + " has tag" + Bytes.toString(tval), r.getRow(), tval); 151 } 152 } 153 } 154}