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.regionserver; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertNotNull; 022import static org.junit.Assert.assertTrue; 023import static org.mockito.Mockito.mock; 024 025import java.io.File; 026import java.io.FileOutputStream; 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.List; 031import java.util.Random; 032 033import org.apache.hadoop.conf.Configuration; 034import org.apache.hadoop.fs.FSDataOutputStream; 035import org.apache.hadoop.fs.Path; 036import org.apache.hadoop.hbase.CellBuilderType; 037import org.apache.hadoop.hbase.CellUtil; 038import org.apache.hadoop.hbase.ExtendedCellBuilderFactory; 039import org.apache.hadoop.hbase.HBaseConfiguration; 040import org.apache.hadoop.hbase.HBaseTestingUtility; 041import org.apache.hadoop.hbase.KeyValue; 042import org.apache.hadoop.hbase.TableName; 043import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 044import org.apache.hadoop.hbase.client.RegionInfo; 045import org.apache.hadoop.hbase.client.RegionInfoBuilder; 046import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 047import org.apache.hadoop.hbase.io.hfile.HFile; 048import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder; 049import org.apache.hadoop.hbase.util.Bytes; 050import org.apache.hadoop.hbase.util.Pair; 051import org.apache.hadoop.hbase.wal.WAL; 052import org.apache.hadoop.hbase.wal.WALEdit; 053import org.hamcrest.Description; 054import org.hamcrest.Matcher; 055import org.hamcrest.TypeSafeMatcher; 056 057import org.junit.Before; 058import org.junit.ClassRule; 059import org.junit.Rule; 060import org.junit.rules.TemporaryFolder; 061import org.junit.rules.TestName; 062 063import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 064import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos; 065 066public class TestBulkloadBase { 067 @ClassRule 068 public static TemporaryFolder testFolder = new TemporaryFolder(); 069 private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 070 protected final WAL log = mock(WAL.class); 071 protected final Configuration conf = HBaseConfiguration.create(); 072 private final Random random = new Random(); 073 private final byte[] randomBytes = new byte[100]; 074 protected final byte[] family1 = Bytes.toBytes("family1"); 075 protected final byte[] family2 = Bytes.toBytes("family2"); 076 protected final byte[] family3 = Bytes.toBytes("family3"); 077 078 @Rule 079 public TestName name = new TestName(); 080 081 @Before 082 public void before() throws IOException { 083 random.nextBytes(randomBytes); 084 } 085 086 protected Pair<byte[], String> withMissingHFileForFamily(byte[] family) { 087 return new Pair<>(family, getNotExistFilePath()); 088 } 089 090 private String getNotExistFilePath() { 091 Path path = new Path(TEST_UTIL.getDataTestDir(), "does_not_exist"); 092 return path.toUri().getPath(); 093 } 094 095 protected Pair<byte[], String> withInvalidColumnFamilyButProperHFileLocation(byte[] family) 096 throws IOException { 097 createHFileForFamilies(family); 098 return new Pair<>(new byte[] { 0x00, 0x01, 0x02 }, getNotExistFilePath()); 099 } 100 101 protected HRegion testRegionWithFamiliesAndSpecifiedTableName(TableName tableName, 102 byte[]... families) throws IOException { 103 RegionInfo hRegionInfo = RegionInfoBuilder.newBuilder(tableName).build(); 104 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName); 105 106 for (byte[] family : families) { 107 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)); 108 } 109 ChunkCreator.initialize(MemStoreLAB.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null, 110 MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_DEFAULT); 111 // TODO We need a way to do this without creating files 112 return HRegion.createHRegion(hRegionInfo, new Path(testFolder.newFolder().toURI()), conf, 113 builder.build(), log); 114 115 } 116 117 protected HRegion testRegionWithFamilies(byte[]... families) throws IOException { 118 TableName tableName = TableName.valueOf(name.getMethodName()); 119 return testRegionWithFamiliesAndSpecifiedTableName(tableName, families); 120 } 121 122 private List<Pair<byte[], String>> getBlankFamilyPaths() { 123 return new ArrayList<>(); 124 } 125 126 protected List<Pair<byte[], String>> withFamilyPathsFor(byte[]... families) throws IOException { 127 List<Pair<byte[], String>> familyPaths = getBlankFamilyPaths(); 128 for (byte[] family : families) { 129 familyPaths.add(new Pair<>(family, createHFileForFamilies(family))); 130 } 131 return familyPaths; 132 } 133 134 private String createHFileForFamilies(byte[] family) throws IOException { 135 HFile.WriterFactory hFileFactory = HFile.getWriterFactoryNoCache(conf); 136 // TODO We need a way to do this without creating files 137 File hFileLocation = testFolder.newFile(); 138 FSDataOutputStream out = new FSDataOutputStream(new FileOutputStream(hFileLocation), null); 139 try { 140 hFileFactory.withOutputStream(out); 141 hFileFactory.withFileContext(new HFileContextBuilder().build()); 142 HFile.Writer writer = hFileFactory.create(); 143 try { 144 writer.append(new KeyValue(ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY) 145 .setRow(randomBytes).setFamily(family).setQualifier(randomBytes).setTimestamp(0L) 146 .setType(KeyValue.Type.Put.getCode()).setValue(randomBytes).build())); 147 } finally { 148 writer.close(); 149 } 150 } finally { 151 out.close(); 152 } 153 return hFileLocation.getAbsoluteFile().getAbsolutePath(); 154 } 155 156 protected static Matcher<WALEdit> bulkLogWalEditType(byte[] typeBytes) { 157 return new WalMatcher(typeBytes); 158 } 159 160 protected static Matcher<WALEdit> bulkLogWalEdit(byte[] typeBytes, byte[] tableName, 161 byte[] familyName, List<String> storeFileNames) { 162 return new WalMatcher(typeBytes, tableName, familyName, storeFileNames); 163 } 164 165 private static class WalMatcher extends TypeSafeMatcher<WALEdit> { 166 private final byte[] typeBytes; 167 private final byte[] tableName; 168 private final byte[] familyName; 169 private final List<String> storeFileNames; 170 171 public WalMatcher(byte[] typeBytes) { 172 this(typeBytes, null, null, null); 173 } 174 175 public WalMatcher(byte[] typeBytes, byte[] tableName, byte[] familyName, 176 List<String> storeFileNames) { 177 this.typeBytes = typeBytes; 178 this.tableName = tableName; 179 this.familyName = familyName; 180 this.storeFileNames = storeFileNames; 181 } 182 183 @Override 184 protected boolean matchesSafely(WALEdit item) { 185 assertTrue(Arrays.equals(CellUtil.cloneQualifier(item.getCells().get(0)), typeBytes)); 186 WALProtos.BulkLoadDescriptor desc; 187 try { 188 desc = WALEdit.getBulkLoadDescriptor(item.getCells().get(0)); 189 } catch (IOException e) { 190 return false; 191 } 192 assertNotNull(desc); 193 194 if (tableName != null) { 195 assertTrue( 196 Bytes.equals(ProtobufUtil.toTableName(desc.getTableName()).getName(), tableName)); 197 } 198 199 if (storeFileNames != null) { 200 int index = 0; 201 WALProtos.StoreDescriptor store = desc.getStores(0); 202 assertTrue(Bytes.equals(store.getFamilyName().toByteArray(), familyName)); 203 assertTrue(Bytes.equals(Bytes.toBytes(store.getStoreHomeDir()), familyName)); 204 assertEquals(storeFileNames.size(), store.getStoreFileCount()); 205 } 206 207 return true; 208 } 209 210 @Override 211 public void describeTo(Description description) { 212 213 } 214 } 215}