Skip to content

Commit 805c346

Browse files
authored
HBASE-26811 Secondary replica may be disabled for read forever (#4182)
1 parent 2711142 commit 805c346

File tree

4 files changed

+139
-6
lines changed

4 files changed

+139
-6
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,11 +1335,7 @@ public boolean hasRegionMemStoreReplication() {
13351335
* @return the modifyable TD
13361336
*/
13371337
public ModifyableTableDescriptor setRegionMemStoreReplication(boolean memstoreReplication) {
1338-
setValue(REGION_MEMSTORE_REPLICATION_KEY, Boolean.toString(memstoreReplication));
1339-
// If the memstore replication is setup, we do not have to wait for observing a flush event
1340-
// from primary before starting to serve reads, because gaps from replication is not applicable
1341-
return setValue(REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY,
1342-
Boolean.toString(memstoreReplication));
1338+
return setValue(REGION_MEMSTORE_REPLICATION_KEY, Boolean.toString(memstoreReplication));
13431339
}
13441340

13451341
public ModifyableTableDescriptor setPriority(int priority) {

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.ROW_LOCK_READ_LOCK_KEY;
2424
import static org.apache.hadoop.hbase.util.ConcurrentMapUtils.computeIfAbsent;
2525

26+
import com.google.errorprone.annotations.RestrictedApi;
2627
import edu.umd.cs.findbugs.annotations.Nullable;
2728
import io.opentelemetry.api.trace.Span;
2829
import java.io.EOFException;
@@ -8750,4 +8751,10 @@ public void addReadRequestsCount(long readRequestsCount) {
87508751
public void addWriteRequestsCount(long writeRequestsCount) {
87518752
this.writeRequestsCount.add(writeRequestsCount);
87528753
}
8754+
8755+
@RestrictedApi(explanation = "Should only be called in tests", link = "",
8756+
allowedOnPath = ".*/src/test/.*")
8757+
boolean isReadsEnabled() {
8758+
return this.writestate.readsEnabled;
8759+
}
87538760
}

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2240,7 +2240,13 @@ private void triggerFlushInPrimaryRegion(final HRegion region) {
22402240
}
22412241
TableName tn = region.getTableDescriptor().getTableName();
22422242
if (!ServerRegionReplicaUtil.isRegionReplicaReplicationEnabled(region.conf, tn) ||
2243-
!ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(region.conf)) {
2243+
!ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(region.conf) ||
2244+
// If the memstore replication not setup, we do not have to wait for observing a flush event
2245+
// from primary before starting to serve reads, because gaps from replication is not
2246+
// applicable,this logic is from
2247+
// TableDescriptorBuilder.ModifyableTableDescriptor.setRegionMemStoreReplication by
2248+
// HBASE-13063
2249+
!region.getTableDescriptor().hasRegionMemStoreReplication()) {
22442250
region.setReadsEnabled(true);
22452251
return;
22462252
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.regionserver;
19+
20+
import static org.junit.Assert.assertFalse;
21+
import static org.junit.Assert.assertNotNull;
22+
import static org.junit.Assert.assertNull;
23+
import static org.junit.Assert.assertTrue;
24+
import static org.junit.Assert.fail;
25+
26+
import java.util.ArrayList;
27+
import java.util.Arrays;
28+
import java.util.List;
29+
import org.apache.hadoop.conf.Configuration;
30+
import org.apache.hadoop.hbase.HBaseClassTestRule;
31+
import org.apache.hadoop.hbase.HBaseTestingUtil;
32+
import org.apache.hadoop.hbase.StartTestingClusterOption;
33+
import org.apache.hadoop.hbase.TableName;
34+
import org.apache.hadoop.hbase.TableNameTestRule;
35+
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
36+
import org.apache.hadoop.hbase.client.TableDescriptor;
37+
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
38+
import org.apache.hadoop.hbase.executor.ExecutorType;
39+
import org.apache.hadoop.hbase.testclassification.MediumTests;
40+
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
41+
import org.apache.hadoop.hbase.util.Bytes;
42+
import org.apache.hadoop.hbase.util.Pair;
43+
import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
44+
import org.junit.AfterClass;
45+
import org.junit.BeforeClass;
46+
import org.junit.ClassRule;
47+
import org.junit.Rule;
48+
import org.junit.Test;
49+
import org.junit.experimental.categories.Category;
50+
51+
@Category({ RegionServerTests.class, MediumTests.class })
52+
public class TestRegionReplicaWaitForPrimaryFlushConf {
53+
@ClassRule
54+
public static final HBaseClassTestRule CLASS_RULE =
55+
HBaseClassTestRule.forClass(TestRegionReplicaWaitForPrimaryFlushConf.class);
56+
57+
private static final byte[] FAMILY = Bytes.toBytes("family_test");
58+
59+
private TableName tableName;
60+
61+
@Rule
62+
public final TableNameTestRule name = new TableNameTestRule();
63+
private static final HBaseTestingUtil HTU = new HBaseTestingUtil();
64+
65+
@BeforeClass
66+
public static void setUpBeforeClass() throws Exception {
67+
Configuration conf = HTU.getConfiguration();
68+
conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_REPLICATION_CONF_KEY, true);
69+
conf.setBoolean(ServerRegionReplicaUtil.REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY, false);
70+
HTU.startMiniCluster(StartTestingClusterOption.builder().numRegionServers(2).build());
71+
72+
}
73+
74+
@AfterClass
75+
public static void tearDownAfterClass() throws Exception {
76+
HTU.shutdownMiniCluster();
77+
}
78+
79+
/**
80+
* This test is for HBASE-26811,when
81+
* {@link ServerRegionReplicaUtil#REGION_REPLICA_WAIT_FOR_PRIMARY_FLUSH_CONF_KEY} is false and set
82+
* {@link TableDescriptorBuilder#setRegionMemStoreReplication} to true explicitly,the secondary
83+
* replica would be disabled for read after open.
84+
*/
85+
@Test
86+
public void testSecondaryReplicaReadEnabled() throws Exception {
87+
tableName = name.getTableName();
88+
TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
89+
.setRegionReplication(2).setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAMILY))
90+
.setRegionMemStoreReplication(true).build();
91+
HTU.getAdmin().createTable(tableDescriptor);
92+
93+
final ArrayList<Pair<HRegion, HRegionServer>> regionAndRegionServers =
94+
new ArrayList<Pair<HRegion, HRegionServer>>(Arrays.asList(null, null));
95+
96+
for (int i = 0; i < 2; i++) {
97+
HRegionServer rs = HTU.getMiniHBaseCluster().getRegionServer(i);
98+
List<HRegion> onlineRegions = rs.getRegions(tableName);
99+
for (HRegion region : onlineRegions) {
100+
int replicaId = region.getRegionInfo().getReplicaId();
101+
assertNull(regionAndRegionServers.get(replicaId));
102+
regionAndRegionServers.set(replicaId, new Pair<HRegion, HRegionServer>(region, rs));
103+
}
104+
}
105+
for (Pair<HRegion, HRegionServer> pair : regionAndRegionServers) {
106+
assertNotNull(pair);
107+
}
108+
109+
HRegionServer secondaryRs = regionAndRegionServers.get(1).getSecond();
110+
111+
try {
112+
secondaryRs.getExecutorService()
113+
.getExecutorThreadPool(ExecutorType.RS_REGION_REPLICA_FLUSH_OPS);
114+
fail();
115+
} catch (NullPointerException e) {
116+
assertTrue(e != null);
117+
}
118+
HRegion secondaryRegion = regionAndRegionServers.get(1).getFirst();
119+
assertFalse(
120+
ServerRegionReplicaUtil.isRegionReplicaWaitForPrimaryFlushEnabled(secondaryRegion.conf));
121+
assertTrue(secondaryRegion.isReadsEnabled());
122+
}
123+
124+
}

0 commit comments

Comments
 (0)