001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.util; 020 021import static org.apache.hadoop.hbase.regionserver.HStoreFile.BULKLOAD_TIME_KEY; 022import static org.junit.Assert.assertArrayEquals; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.util.Arrays; 027import java.util.Locale; 028import java.util.Optional; 029 030import org.apache.hadoop.conf.Configuration; 031import org.apache.hadoop.fs.FileSystem; 032import org.apache.hadoop.fs.Path; 033import org.apache.hadoop.hbase.ArrayBackedTag; 034import org.apache.hadoop.hbase.Cell; 035import org.apache.hadoop.hbase.HColumnDescriptor; 036import org.apache.hadoop.hbase.KeyValue; 037import org.apache.hadoop.hbase.PrivateCellUtil; 038import org.apache.hadoop.hbase.Tag; 039import org.apache.hadoop.hbase.TagType; 040import org.apache.hadoop.hbase.client.Result; 041import org.apache.hadoop.hbase.client.ResultScanner; 042import org.apache.hadoop.hbase.client.Scan; 043import org.apache.hadoop.hbase.client.Table; 044import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; 045import org.apache.hadoop.hbase.io.hfile.CacheConfig; 046import org.apache.hadoop.hbase.io.hfile.HFile; 047import org.apache.hadoop.hbase.io.hfile.HFileContext; 048import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder; 049import org.apache.hadoop.hbase.mob.MobUtils; 050 051/** 052 * Utility class for HFile-related testing. 053 */ 054public class HFileTestUtil { 055 056 public static final String OPT_DATA_BLOCK_ENCODING_USAGE = 057 "Encoding algorithm (e.g. prefix " 058 + "compression) to use for data blocks in the test column family, " 059 + "one of " + Arrays.toString(DataBlockEncoding.values()) + "."; 060 public static final String OPT_DATA_BLOCK_ENCODING = 061 HColumnDescriptor.DATA_BLOCK_ENCODING.toLowerCase(Locale.ROOT); 062 /** Column family used by the test */ 063 public static byte[] DEFAULT_COLUMN_FAMILY = Bytes.toBytes("test_cf"); 064 /** Column families used by the test */ 065 public static final byte[][] DEFAULT_COLUMN_FAMILIES = { DEFAULT_COLUMN_FAMILY }; 066 067 /** 068 * Create an HFile with the given number of rows between a given 069 * start key and end key @ family:qualifier. The value will be the key value. 070 * This file will not have tags. 071 */ 072 public static void createHFile( 073 Configuration configuration, 074 FileSystem fs, Path path, 075 byte[] family, byte[] qualifier, 076 byte[] startKey, byte[] endKey, int numRows) throws IOException { 077 createHFile(configuration, fs, path, DataBlockEncoding.NONE, family, qualifier, 078 startKey, endKey, numRows, false); 079 } 080 081 /** 082 * Create an HFile with the given number of rows between a given 083 * start key and end key @ family:qualifier. The value will be the key value. 084 * This file will use certain data block encoding algorithm. 085 */ 086 public static void createHFileWithDataBlockEncoding( 087 Configuration configuration, 088 FileSystem fs, Path path, DataBlockEncoding encoding, 089 byte[] family, byte[] qualifier, 090 byte[] startKey, byte[] endKey, int numRows) throws IOException { 091 createHFile(configuration, fs, path, encoding, family, qualifier, startKey, endKey, 092 numRows, false); 093 } 094 095 /** 096 * Create an HFile with the given number of rows between a given 097 * start key and end key @ family:qualifier. The value will be the key value. 098 * This cells will also have a tag whose value is the key. 099 */ 100 public static void createHFileWithTags( 101 Configuration configuration, 102 FileSystem fs, Path path, 103 byte[] family, byte[] qualifier, 104 byte[] startKey, byte[] endKey, int numRows) throws IOException { 105 createHFile(configuration, fs, path, DataBlockEncoding.NONE, family, qualifier, 106 startKey, endKey, numRows, true); 107 } 108 109 /** 110 * Create an HFile with the given number of rows between a given 111 * start key and end key @ family:qualifier. 112 * If withTag is true, we add the rowKey as the tag value for 113 * tagtype MOB_TABLE_NAME_TAG_TYPE 114 */ 115 public static void createHFile( 116 Configuration configuration, 117 FileSystem fs, Path path, DataBlockEncoding encoding, 118 byte[] family, byte[] qualifier, 119 byte[] startKey, byte[] endKey, int numRows, boolean withTag) throws IOException { 120 HFileContext meta = new HFileContextBuilder() 121 .withIncludesTags(withTag) 122 .withDataBlockEncoding(encoding) 123 .withColumnFamily(family) 124 .build(); 125 HFile.Writer writer = HFile.getWriterFactory(configuration, new CacheConfig(configuration)) 126 .withPath(fs, path) 127 .withFileContext(meta) 128 .create(); 129 long now = System.currentTimeMillis(); 130 try { 131 // subtract 2 since iterateOnSplits doesn't include boundary keys 132 for (byte[] key : Bytes.iterateOnSplits(startKey, endKey, numRows - 2)) { 133 Cell kv = new KeyValue(key, family, qualifier, now, key); 134 if (withTag) { 135 // add a tag. Arbitrarily chose mob tag since we have a helper already. 136 Tag tableNameTag = new ArrayBackedTag(TagType.MOB_TABLE_NAME_TAG_TYPE, key); 137 kv = MobUtils.createMobRefCell(kv, key, tableNameTag); 138 139 // verify that the kv has the tag. 140 Optional<Tag> tag = PrivateCellUtil.getTag(kv, TagType.MOB_TABLE_NAME_TAG_TYPE); 141 if (!tag.isPresent()) { 142 throw new IllegalStateException("Tag didn't stick to KV " + kv.toString()); 143 } 144 } 145 writer.append(kv); 146 } 147 } finally { 148 writer.appendFileInfo(BULKLOAD_TIME_KEY, Bytes.toBytes(System.currentTimeMillis())); 149 writer.close(); 150 } 151 } 152 153 /** 154 * This verifies that each cell has a tag that is equal to its rowkey name. For this to work 155 * the hbase instance must have HConstants.RPC_CODEC_CONF_KEY set to 156 * KeyValueCodecWithTags.class.getCanonicalName()); 157 * @param table table containing tagged cells 158 * @throws IOException if problems reading table 159 */ 160 public static void verifyTags(Table table) throws IOException { 161 ResultScanner s = table.getScanner(new Scan()); 162 for (Result r : s) { 163 for (Cell c : r.listCells()) { 164 Optional<Tag> tag = PrivateCellUtil.getTag(c, TagType.MOB_TABLE_NAME_TAG_TYPE); 165 if (!tag.isPresent()) { 166 fail(c.toString() + " has null tag"); 167 continue; 168 } 169 Tag t = tag.get(); 170 byte[] tval = Tag.cloneValue(t); 171 assertArrayEquals(c.toString() + " has tag" + Bytes.toString(tval), 172 r.getRow(), tval); 173 } 174 } 175 } 176}