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}