HBASE-26811 Secondary replica may be disabled for read forever (#4182)
This commit is contained in:
parent
27111421d9
commit
805c346e54
|
@ -1335,11 +1335,7 @@ public class TableDescriptorBuilder {
|
||||||
* @return the modifyable TD
|
* @return the modifyable TD
|
||||||
*/
|
*/
|
||||||
public ModifyableTableDescriptor setRegionMemStoreReplication(boolean memstoreReplication) {
|
public ModifyableTableDescriptor setRegionMemStoreReplication(boolean memstoreReplication) {
|
||||||
setValue(REGION_MEMSTORE_REPLICATION_KEY, Boolean.toString(memstoreReplication));
|
return setValue(REGION_MEMSTORE_REPLICATION_KEY, Boolean.toString(memstoreReplication));
|
||||||
// If the memstore replication is setup, we do not have to wait for observing a flush event
|
|
||||||
// from primary before starting to serve reads, because gaps from replication is not applicable
|
|
||||||
return setValue(REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY,
|
|
||||||
Boolean.toString(memstoreReplication));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModifyableTableDescriptor setPriority(int priority) {
|
public ModifyableTableDescriptor setPriority(int priority) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.REGION_NAMES
|
||||||
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.ROW_LOCK_READ_LOCK_KEY;
|
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.ROW_LOCK_READ_LOCK_KEY;
|
||||||
import static org.apache.hadoop.hbase.util.ConcurrentMapUtils.computeIfAbsent;
|
import static org.apache.hadoop.hbase.util.ConcurrentMapUtils.computeIfAbsent;
|
||||||
|
|
||||||
|
import com.google.errorprone.annotations.RestrictedApi;
|
||||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||||
import io.opentelemetry.api.trace.Span;
|
import io.opentelemetry.api.trace.Span;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
|
@ -8750,4 +8751,10 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
public void addWriteRequestsCount(long writeRequestsCount) {
|
public void addWriteRequestsCount(long writeRequestsCount) {
|
||||||
this.writeRequestsCount.add(writeRequestsCount);
|
this.writeRequestsCount.add(writeRequestsCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RestrictedApi(explanation = "Should only be called in tests", link = "",
|
||||||
|
allowedOnPath = ".*/src/test/.*")
|
||||||
|
boolean isReadsEnabled() {
|
||||||
|
return this.writestate.readsEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2240,7 +2240,13 @@ public class HRegionServer extends HBaseServerBase<RSRpcServices>
|
||||||
}
|
}
|
||||||
TableName tn = region.getTableDescriptor().getTableName();
|
TableName tn = region.getTableDescriptor().getTableName();
|
||||||
if (!ServerRegionReplicaUtil.isRegionReplicaReplicationEnabled(region.conf, tn) ||
|
if (!ServerRegionReplicaUtil.isRegionReplicaReplicationEnabled(region.conf, tn) ||
|
||||||
!ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(region.conf)) {
|
!ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(region.conf) ||
|
||||||
|
// If the memstore replication not setup, we do not have to wait for observing a flush event
|
||||||
|
// from primary before starting to serve reads, because gaps from replication is not
|
||||||
|
// applicable,this logic is from
|
||||||
|
// TableDescriptorBuilder.ModifyableTableDescriptor.setRegionMemStoreReplication by
|
||||||
|
// HBASE-13063
|
||||||
|
!region.getTableDescriptor().hasRegionMemStoreReplication()) {
|
||||||
region.setReadsEnabled(true);
|
region.setReadsEnabled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.regionserver;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtil;
|
||||||
|
import org.apache.hadoop.hbase.StartTestingClusterOption;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.TableNameTestRule;
|
||||||
|
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
|
||||||
|
import org.apache.hadoop.hbase.client.TableDescriptor;
|
||||||
|
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
|
||||||
|
import org.apache.hadoop.hbase.executor.ExecutorType;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.MediumTests;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.apache.hadoop.hbase.util.Pair;
|
||||||
|
import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
|
||||||
|
@Category({ RegionServerTests.class, MediumTests.class })
|
||||||
|
public class TestRegionReplicaWaitForPrimaryFlushConf {
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestRegionReplicaWaitForPrimaryFlushConf.class);
|
||||||
|
|
||||||
|
private static final byte[] FAMILY = Bytes.toBytes("family_test");
|
||||||
|
|
||||||
|
private TableName tableName;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final TableNameTestRule name = new TableNameTestRule();
|
||||||
|
private static final HBaseTestingUtil HTU = new HBaseTestingUtil();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpBeforeClass() throws Exception {
|
||||||
|
Configuration conf = HTU.getConfiguration();
|
||||||
|
conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_REPLICATION_CONF_KEY, true);
|
||||||
|
conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY, false);
|
||||||
|
HTU.startMiniCluster(StartTestingClusterOption.builder().numRegionServers(2).build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownAfterClass() throws Exception {
|
||||||
|
HTU.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test is for HBASE-26811,when
|
||||||
|
* {@link ServerRegionReplicaUtil#REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY} is false and set
|
||||||
|
* {@link TableDescriptorBuilder#setRegionMemStoreReplication} to true explicitly,the secondary
|
||||||
|
* replica would be disabled for read after open.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSecondaryReplicaReadEnabled() throws Exception {
|
||||||
|
tableName = name.getTableName();
|
||||||
|
TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
|
||||||
|
.setRegionReplication(2).setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY))
|
||||||
|
.setRegionMemStoreReplication(true).build();
|
||||||
|
HTU.getAdmin().createTable(tableDescriptor);
|
||||||
|
|
||||||
|
final ArrayList<Pair<HRegion, HRegionServer>> regionAndRegionServers =
|
||||||
|
new ArrayList<Pair<HRegion, HRegionServer>>(Arrays.asList(null, null));
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i);
|
||||||
|
List<HRegion> onlineRegions = rs.getRegions(tableName);
|
||||||
|
for (HRegion region : onlineRegions) {
|
||||||
|
int replicaId = region.getRegionInfo().getReplicaId();
|
||||||
|
assertNull(regionAndRegionServers.get(replicaId));
|
||||||
|
regionAndRegionServers.set(replicaId, new Pair<HRegion, HRegionServer>(region, rs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Pair<HRegion, HRegionServer> pair : regionAndRegionServers) {
|
||||||
|
assertNotNull(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRegionServer secondaryRs = regionAndRegionServers.get(1).getSecond();
|
||||||
|
|
||||||
|
try {
|
||||||
|
secondaryRs.getExecutorService()
|
||||||
|
.getExecutorThreadPool(ExecutorType.RS_REGION_REPLICA_FLUSH_OPS);
|
||||||
|
fail();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertTrue(e != null);
|
||||||
|
}
|
||||||
|
HRegion secondaryRegion = regionAndRegionServers.get(1).getFirst();
|
||||||
|
assertFalse(
|
||||||
|
ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(secondaryRegion.conf));
|
||||||
|
assertTrue(secondaryRegion.isReadsEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue