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