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;
019
020import static org.apache.hadoop.hbase.AcidGuaranteesTestTool.FAMILIES;
021import static org.apache.hadoop.hbase.AcidGuaranteesTestTool.TABLE_NAME;
022
023import java.util.Arrays;
024import java.util.List;
025import java.util.stream.Stream;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
028import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
029import org.apache.hadoop.hbase.regionserver.CompactingMemStore;
030import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;
031import org.apache.hadoop.hbase.regionserver.MemStoreLAB;
032import org.junit.jupiter.api.AfterAll;
033import org.junit.jupiter.api.AfterEach;
034import org.junit.jupiter.api.BeforeAll;
035import org.junit.jupiter.api.BeforeEach;
036import org.junit.jupiter.params.provider.Arguments;
037
038import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
039
040/**
041 * Test case that uses multiple threads to read and write multifamily rows into a table, verifying
042 * that reads never see partially-complete writes. This can run as a junit test, or with a main()
043 * function which runs against a real cluster (eg for testing with failures, region movement, etc)
044 */
045public abstract class AcidGuaranteesTestBase {
046
047  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
048
049  private AcidGuaranteesTestTool tool = new AcidGuaranteesTestTool();
050
051  private MemoryCompactionPolicy policy;
052
053  protected AcidGuaranteesTestBase(MemoryCompactionPolicy policy) {
054    this.policy = policy;
055  }
056
057  public static Stream<Arguments> parameters() {
058    return Arrays.stream(MemoryCompactionPolicy.values()).map(Arguments::of);
059  }
060
061  @BeforeAll
062  public static void setUpBeforeClass() throws Exception {
063    // Set small flush size for minicluster so we exercise reseeking scanners
064    Configuration conf = UTIL.getConfiguration();
065    conf.set(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, String.valueOf(128 * 1024));
066    // prevent aggressive region split
067    conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
068      ConstantSizeRegionSplitPolicy.class.getName());
069    conf.setInt("hfile.format.version", 3); // for mob tests
070    UTIL.startMiniCluster(1);
071  }
072
073  @AfterAll
074  public static void tearDownAfterClass() throws Exception {
075    UTIL.shutdownMiniCluster();
076  }
077
078  @BeforeEach
079  public void setUp() throws Exception {
080    TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TABLE_NAME)
081      .setValue(CompactingMemStore.COMPACTING_MEMSTORE_TYPE_KEY, policy.name());
082    if (policy == MemoryCompactionPolicy.EAGER) {
083      builder.setValue(MemStoreLAB.USEMSLAB_KEY, "false");
084      builder.setValue(CompactingMemStore.IN_MEMORY_FLUSH_THRESHOLD_FACTOR_KEY, "0.9");
085    }
086    Stream.of(FAMILIES).map(ColumnFamilyDescriptorBuilder::of)
087      .forEachOrdered(builder::setColumnFamily);
088    for (int i = 0; i < 10; i++) {
089      // try to delete the table several times
090      if (UTIL.getAdmin().tableExists(TABLE_NAME)) {
091        UTIL.deleteTable(TABLE_NAME);
092        Thread.sleep(1000);
093      } else {
094        break;
095      }
096    }
097    UTIL.getAdmin().createTable(builder.build());
098    tool.setConf(UTIL.getConfiguration());
099  }
100
101  @AfterEach
102  public void tearDown() throws Exception {
103    UTIL.deleteTable(TABLE_NAME);
104  }
105
106  protected final void runTestAtomicity(long millisToRun, int numWriters, int numGetters,
107    int numScanners, int numUniqueRows, boolean useMob) throws Exception {
108    List<String> args = Lists.newArrayList("-millis", String.valueOf(millisToRun), "-numWriters",
109      String.valueOf(numWriters), "-numGetters", String.valueOf(numGetters), "-numScanners",
110      String.valueOf(numScanners), "-numUniqueRows", String.valueOf(numUniqueRows), "-crazyFlush");
111    if (useMob) {
112      args.add("-useMob");
113    }
114    tool.run(args.toArray(new String[0]));
115  }
116
117}