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.regionreplication;
019
020import static org.junit.Assert.assertNotNull;
021import static org.junit.Assert.assertTrue;
022
023import java.io.IOException;
024import java.util.Arrays;
025import java.util.List;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.HBaseTestingUtil;
029import org.apache.hadoop.hbase.StartTestingClusterOption;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
032import org.apache.hadoop.hbase.client.Consistency;
033import org.apache.hadoop.hbase.client.Durability;
034import org.apache.hadoop.hbase.client.Get;
035import org.apache.hadoop.hbase.client.Mutation;
036import org.apache.hadoop.hbase.client.Put;
037import org.apache.hadoop.hbase.client.RegionReplicaUtil;
038import org.apache.hadoop.hbase.client.Result;
039import org.apache.hadoop.hbase.client.Table;
040import org.apache.hadoop.hbase.client.TableDescriptor;
041import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
042import org.apache.hadoop.hbase.regionserver.HRegion;
043import org.apache.hadoop.hbase.regionserver.HRegionServer;
044import org.apache.hadoop.hbase.regionserver.Region;
045import org.apache.hadoop.hbase.testclassification.LargeTests;
046import org.apache.hadoop.hbase.testclassification.RegionServerTests;
047import org.apache.hadoop.hbase.util.Bytes;
048import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
049import org.junit.AfterClass;
050import org.junit.BeforeClass;
051import org.junit.ClassRule;
052import org.junit.Test;
053import org.junit.experimental.categories.Category;
054
055@Category({ RegionServerTests.class, LargeTests.class })
056public class TestRegionReplicationForSkipWAL {
057
058  @ClassRule
059  public static final HBaseClassTestRule CLASS_RULE =
060    HBaseClassTestRule.forClass(TestRegionReplicationForSkipWAL.class);
061
062  private static final byte[] FAM1 = Bytes.toBytes("family_test1");
063
064  private static final byte[] QUAL1 = Bytes.toBytes("qualifier_test1");
065
066  private static final byte[] FAM2 = Bytes.toBytes("family_test2");
067
068  private static final byte[] QUAL2 = Bytes.toBytes("qualifier_test2");
069
070  private static final byte[] FAM3 = Bytes.toBytes("family_test3");
071
072  private static final byte[] QUAL3 = Bytes.toBytes("qualifier_test3");
073
074  private static final byte[] FAM4 = Bytes.toBytes("family_test4");
075
076  private static final byte[] QUAL4 = Bytes.toBytes("qualifier_test4");
077
078  private static final byte[] FAM5 = Bytes.toBytes("family_test5");
079
080  private static final byte[] QUAL5 = Bytes.toBytes("qualifier_test5");
081
082  private static final byte[] FAM6 = Bytes.toBytes("family_test6");
083
084  private static final byte[] QUAL6 = Bytes.toBytes("qualifier_test6");
085
086  private static final HBaseTestingUtil HTU = new HBaseTestingUtil();
087  private static final int NB_SERVERS = 2;
088
089  private static final String strTableName = "TestRegionReplicationForSkipWAL";
090
091  @BeforeClass
092  public static void setUp() throws Exception {
093    Configuration conf = HTU.getConfiguration();
094    conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_REPLICATION_CONF_KEY, true);
095    conf.setBoolean(RegionReplicaUtil.REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY, false);
096    HTU.startMiniCluster(StartTestingClusterOption.builder().numRegionServers(NB_SERVERS).build());
097  }
098
099  @AfterClass
100  public static void tearDown() throws Exception {
101    HTU.shutdownMiniCluster();
102  }
103
104  /**
105   * This test is for HBASE-26933,make the new region replication framework introduced by
106   * HBASE-26233 work for table which DURABILITY is Durability.SKIP_WAL.
107   */
108  @Test
109  public void testReplicateToReplicaWhenSkipWAL() throws Exception {
110    final HRegion[] skipWALRegions = this.createTable(true);
111    byte[] rowKey1 = Bytes.toBytes(1);
112    byte[] value1 = Bytes.toBytes(2);
113
114    byte[] rowKey2 = Bytes.toBytes(2);
115    byte[] value2 = Bytes.toBytes(4);
116
117    // Test the table is skipWAL
118    skipWALRegions[0].batchMutate(new Mutation[] { new Put(rowKey1).addColumn(FAM1, QUAL1, value1),
119      new Put(rowKey2).addColumn(FAM2, QUAL2, value2) });
120
121    try (Table skipWALTable = HTU.getConnection().getTable(getTableName(true))) {
122      HTU.waitFor(30000, () -> checkReplica(skipWALTable, FAM1, QUAL1, rowKey1, value1)
123        && checkReplica(skipWALTable, FAM2, QUAL2, rowKey2, value2));
124    }
125
126    byte[] rowKey3 = Bytes.toBytes(3);
127    byte[] value3 = Bytes.toBytes(6);
128    byte[] rowKey4 = Bytes.toBytes(4);
129    byte[] value4 = Bytes.toBytes(8);
130    byte[] rowKey5 = Bytes.toBytes(5);
131    byte[] value5 = Bytes.toBytes(10);
132    byte[] rowKey6 = Bytes.toBytes(6);
133    byte[] value6 = Bytes.toBytes(12);
134
135    // Test the table is normal,but the Put is skipWAL
136    final HRegion[] normalRegions = this.createTable(false);
137    normalRegions[0].batchMutate(new Mutation[] { new Put(rowKey3).addColumn(FAM3, QUAL3, value3),
138      new Put(rowKey4).addColumn(FAM4, QUAL4, value4).setDurability(Durability.SKIP_WAL),
139      new Put(rowKey5).addColumn(FAM5, QUAL5, value5).setDurability(Durability.SKIP_WAL),
140      new Put(rowKey6).addColumn(FAM6, QUAL6, value6) });
141
142    try (Table normalTable = HTU.getConnection().getTable(getTableName(false))) {
143      HTU.waitFor(30000,
144        () -> checkReplica(normalTable, FAM3, QUAL3, rowKey3, value3)
145          && checkReplica(normalTable, FAM4, QUAL4, rowKey4, value4)
146          && checkReplica(normalTable, FAM5, QUAL5, rowKey5, value5)
147          && checkReplica(normalTable, FAM6, QUAL6, rowKey6, value6));
148    }
149  }
150
151  private static boolean checkReplica(Table table, byte[] fam, byte[] qual, byte[] rowKey,
152    byte[] expectValue) throws IOException {
153    Get get = new Get(rowKey).setConsistency(Consistency.TIMELINE).setReplicaId(1);
154    Result result = table.get(get);
155    byte[] value = result.getValue(fam, qual);
156    return value != null && value.length > 0 && Arrays.equals(expectValue, value);
157  }
158
159  private TableName getTableName(boolean skipWAL) {
160    return TableName.valueOf(strTableName + (skipWAL ? "_skipWAL" : ""));
161  }
162
163  private HRegion[] createTable(boolean skipWAL) throws Exception {
164    TableName tableName = getTableName(skipWAL);
165    TableDescriptorBuilder builder =
166      TableDescriptorBuilder.newBuilder(tableName).setRegionReplication(NB_SERVERS)
167        .setColumnFamilies(Arrays.asList(ColumnFamilyDescriptorBuilder.of(FAM1),
168          ColumnFamilyDescriptorBuilder.of(FAM2), ColumnFamilyDescriptorBuilder.of(FAM3),
169          ColumnFamilyDescriptorBuilder.of(FAM4), ColumnFamilyDescriptorBuilder.of(FAM5),
170          ColumnFamilyDescriptorBuilder.of(FAM6)));
171    if (skipWAL) {
172      builder.setDurability(Durability.SKIP_WAL);
173
174    }
175    TableDescriptor tableDescriptor = builder.build();
176
177    HTU.getAdmin().createTable(tableDescriptor);
178    final HRegion[] regions = new HRegion[NB_SERVERS];
179    for (int i = 0; i < NB_SERVERS; i++) {
180      HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i);
181      List<HRegion> onlineRegions = rs.getRegions(tableName);
182      for (HRegion region : onlineRegions) {
183        int replicaId = region.getRegionInfo().getReplicaId();
184        assertTrue(regions[replicaId] == null);
185        regions[region.getRegionInfo().getReplicaId()] = region;
186      }
187    }
188    for (Region region : regions) {
189      assertNotNull(region);
190    }
191    return regions;
192  }
193}