Skip to content

Commit 0ae42dd

Browse files
authored
HBASE-27230 RegionServer should be aborted when WAL.sync throws Timeo… (#4641)
Signed-off-by: Duo Zhang <[email protected]>
1 parent 31fc97e commit 0ae42dd

File tree

10 files changed

+307
-18
lines changed

10 files changed

+307
-18
lines changed

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@
153153
import org.apache.hadoop.hbase.regionserver.throttle.NoLimitThroughputController;
154154
import org.apache.hadoop.hbase.regionserver.throttle.StoreHotnessProtector;
155155
import org.apache.hadoop.hbase.regionserver.throttle.ThroughputController;
156+
import org.apache.hadoop.hbase.regionserver.wal.WALSyncTimeoutIOException;
156157
import org.apache.hadoop.hbase.regionserver.wal.WALUtil;
157158
import org.apache.hadoop.hbase.replication.ReplicationUtils;
158159
import org.apache.hadoop.hbase.replication.regionserver.ReplicationObserver;
@@ -1367,7 +1368,9 @@ public RegionInfo getRegionInfo() {
13671368
return this.fs.getRegionInfo();
13681369
}
13691370

1370-
/** Returns Instance of {@link RegionServerServices} used by this HRegion. Can be null. */
1371+
/**
1372+
* Returns Instance of {@link RegionServerServices} used by this HRegion. Can be null.
1373+
*/
13711374
RegionServerServices getRegionServerServices() {
13721375
return this.rsServices;
13731376
}
@@ -2863,7 +2866,7 @@ private boolean writeCanNotFlushMarkerToWAL(WriteEntry flushOpSeqIdMVCCEntry, WA
28632866
if (sink != null && !writeFlushWalMarker) {
28642867
/**
28652868
* Here for replication to secondary region replica could use {@link FlushAction#CANNOT_FLUSH}
2866-
* to recover writeFlushWalMarker is false, we create {@link WALEdit} for
2869+
* to recover when writeFlushWalMarker is false, we create {@link WALEdit} for
28672870
* {@link FlushDescriptor} and attach the {@link RegionReplicationSink#add} to the
28682871
* flushOpSeqIdMVCCEntry,see HBASE-26960 for more details.
28692872
*/
@@ -3694,7 +3697,7 @@ public void doPostOpCleanupForMiniBatch(
36943697
* @param familyMap Map of Cells by family
36953698
*/
36963699
protected void applyFamilyMapToMemStore(Map<byte[], List<Cell>> familyMap,
3697-
MemStoreSizing memstoreAccounting) throws IOException {
3700+
MemStoreSizing memstoreAccounting) {
36983701
for (Map.Entry<byte[], List<Cell>> e : familyMap.entrySet()) {
36993702
byte[] family = e.getKey();
37003703
List<Cell> cells = e.getValue();
@@ -5231,7 +5234,7 @@ public void setReadsEnabled(boolean readsEnabled) {
52315234
* scenario but that do not make sense otherwise.
52325235
*/
52335236
private void applyToMemStore(HStore store, List<Cell> cells, boolean delta,
5234-
MemStoreSizing memstoreAccounting) throws IOException {
5237+
MemStoreSizing memstoreAccounting) {
52355238
// Any change in how we update Store/MemStore needs to also be done in other applyToMemStore!!!!
52365239
boolean upsert = delta && store.getColumnFamilyDescriptor().getMaxVersions() == 1;
52375240
if (upsert) {
@@ -8047,6 +8050,19 @@ private WriteEntry doWALAppend(WALEdit walEdit, BatchOperation<?> batchOp,
80478050
if (walKey.getWriteEntry() != null) {
80488051
mvcc.complete(walKey.getWriteEntry());
80498052
}
8053+
8054+
/**
8055+
* If {@link WAL#sync} get a timeout exception, the only correct way is to abort the region
8056+
* server, as the design of {@link WAL#sync}, is to succeed or die, there is no 'failure'. It
8057+
* is usually not a big deal is because we set a very large default value(5 minutes) for
8058+
* {@link AbstractFSWAL#WAL_SYNC_TIMEOUT_MS}, usually the WAL system will abort the region
8059+
* server if it can not finish the sync within 5 minutes.
8060+
*/
8061+
if (ioe instanceof WALSyncTimeoutIOException) {
8062+
if (rsServices != null) {
8063+
rsServices.abort("WAL sync timeout,forcing server shutdown", ioe);
8064+
}
8065+
}
80508066
throw ioe;
80518067
}
80528068
}
@@ -8057,7 +8073,7 @@ private WriteEntry doWALAppend(WALEdit walEdit, BatchOperation<?> batchOp,
80578073
*/
80588074
private void attachRegionReplicationInWALAppend(BatchOperation<?> batchOp,
80598075
MiniBatchOperationInProgress<Mutation> miniBatchOp, WALKeyImpl walKey, WALEdit walEdit,
8060-
WriteEntry writeEntry) throws IOException {
8076+
WriteEntry writeEntry) {
80618077
if (!regionReplicationSink.isPresent()) {
80628078
return;
80638079
}
@@ -8086,7 +8102,7 @@ private void attachRegionReplicationInWALAppend(BatchOperation<?> batchOp,
80868102
* replica.
80878103
*/
80888104
private void doAttachReplicateRegionReplicaAction(WALKeyImpl walKey, WALEdit walEdit,
8089-
WriteEntry writeEntry) throws IOException {
8105+
WriteEntry writeEntry) {
80908106
if (walEdit == null || walEdit.isEmpty()) {
80918107
return;
80928108
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,8 +1880,7 @@ public long getSmallestReadPoint() {
18801880
* across all of them.
18811881
* @param readpoint readpoint below which we can safely remove duplicate KVs
18821882
*/
1883-
public void upsert(Iterable<Cell> cells, long readpoint, MemStoreSizing memstoreSizing)
1884-
throws IOException {
1883+
public void upsert(Iterable<Cell> cells, long readpoint, MemStoreSizing memstoreSizing) {
18851884
this.storeEngine.readLock();
18861885
try {
18871886
this.memstore.upsert(cells, readpoint, memstoreSizing);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public abstract class AbstractFSWAL<W extends WriterBase> implements WAL {
142142
"hbase.regionserver.wal.slowsync.roll.interval.ms";
143143
protected static final int DEFAULT_SLOW_SYNC_ROLL_INTERVAL_MS = 60 * 1000; // in ms, 1 minute
144144

145-
protected static final String WAL_SYNC_TIMEOUT_MS = "hbase.regionserver.wal.sync.timeout";
145+
public static final String WAL_SYNC_TIMEOUT_MS = "hbase.regionserver.wal.sync.timeout";
146146
protected static final int DEFAULT_WAL_SYNC_TIMEOUT_MS = 5 * 60 * 1000; // in ms, 5min
147147

148148
public static final String WAL_ROLL_MULTIPLIER = "hbase.regionserver.logroll.multiplier";
@@ -881,7 +881,7 @@ protected final void blockOnSync(SyncFuture syncFuture) throws IOException {
881881
}
882882
}
883883
} catch (TimeoutIOException tioe) {
884-
throw tioe;
884+
throw new WALSyncTimeoutIOException(tioe);
885885
} catch (InterruptedException ie) {
886886
LOG.warn("Interrupted", ie);
887887
throw convertInterruptedExceptionToIOException(ie);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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.wal;
19+
20+
import org.apache.hadoop.hbase.HBaseIOException;
21+
import org.apache.hadoop.hbase.wal.WAL;
22+
import org.apache.yetus.audience.InterfaceAudience;
23+
24+
/**
25+
* Thrown when {@link WAL#sync} timeout.
26+
*/
27+
@InterfaceAudience.Private
28+
public class WALSyncTimeoutIOException extends HBaseIOException {
29+
30+
private static final long serialVersionUID = 5067699288291906985L;
31+
32+
public WALSyncTimeoutIOException() {
33+
super();
34+
}
35+
36+
public WALSyncTimeoutIOException(String message, Throwable cause) {
37+
super(message, cause);
38+
}
39+
40+
public WALSyncTimeoutIOException(String message) {
41+
super(message);
42+
}
43+
44+
public WALSyncTimeoutIOException(Throwable cause) {
45+
super(cause);
46+
}
47+
48+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ private static WALKeyImpl doFullMarkerAppendTransaction(final WAL wal,
176176
if (walKey.getWriteEntry() != null) {
177177
mvcc.complete(walKey.getWriteEntry());
178178
}
179+
/**
180+
* Here we do not abort the RegionServer for {@link WALSyncTimeoutIOException} as
181+
* {@link HRegion#doWALAppend} does,because WAL Marker just records the internal state and
182+
* seems it is no need to always abort the RegionServer when {@link WAL#sync} timeout,it is
183+
* the internal state transition that determines whether RegionServer is aborted or not.
184+
*/
179185
throw ioe;
180186
}
181187
return walKey;

hbase-server/src/main/java/org/apache/hadoop/hbase/wal/AsyncFSWALProvider.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,15 @@ void init(FileSystem fs, Path path, Configuration c, boolean overwritable, long
6262
StreamSlowMonitor monitor) throws IOException, CommonFSUtils.StreamLacksCapabilityException;
6363
}
6464

65-
private EventLoopGroup eventLoopGroup;
65+
/**
66+
* Protected visibility for used in tests.
67+
*/
68+
protected EventLoopGroup eventLoopGroup;
6669

67-
private Class<? extends Channel> channelClass;
70+
/**
71+
* Protected visibility for used in tests.
72+
*/
73+
protected Class<? extends Channel> channelClass;
6874

6975
@Override
7076
protected AsyncFSWAL createWAL() throws IOException {

hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WAL.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException;
2828
import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener;
2929
import org.apache.hadoop.hbase.regionserver.wal.WALCoprocessorHost;
30+
import org.apache.hadoop.hbase.regionserver.wal.WALSyncTimeoutIOException;
3031
import org.apache.hadoop.hbase.replication.regionserver.WALFileLengthProvider;
3132
import org.apache.yetus.audience.InterfaceAudience;
3233
import org.apache.yetus.audience.InterfaceStability;
@@ -133,18 +134,21 @@ void updateStore(byte[] encodedRegionName, byte[] familyName, Long sequenceid,
133134

134135
/**
135136
* Sync what we have in the WAL.
137+
* @throws when timeout, it would throw {@link WALSyncTimeoutIOException}.
136138
*/
137139
void sync() throws IOException;
138140

139141
/**
140142
* Sync the WAL if the txId was not already sync'd.
141143
* @param txid Transaction id to sync to.
144+
* @throws when timeout, it would throw {@link WALSyncTimeoutIOException}.
142145
*/
143146
void sync(long txid) throws IOException;
144147

145148
/**
146149
* @param forceSync Flag to force sync rather than flushing to the buffer. Example - Hadoop hflush
147150
* vs hsync.
151+
* @throws when timeout, it would throw {@link WALSyncTimeoutIOException}.
148152
*/
149153
default void sync(boolean forceSync) throws IOException {
150154
sync();
@@ -154,6 +158,7 @@ default void sync(boolean forceSync) throws IOException {
154158
* @param txid Transaction id to sync to.
155159
* @param forceSync Flag to force sync rather than flushing to the buffer. Example - Hadoop hflush
156160
* vs hsync.
161+
* @throws when timeout, it would throw {@link WALSyncTimeoutIOException}.
157162
*/
158163
default void sync(long txid, boolean forceSync) throws IOException {
159164
sync(txid);

hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALFactory.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.hadoop.hbase.wal;
1919

20+
import com.google.errorprone.annotations.RestrictedApi;
2021
import java.io.IOException;
2122
import java.io.InterruptedIOException;
2223
import java.util.List;
@@ -505,4 +506,10 @@ public final WALProvider getMetaWALProvider() {
505506
public ExcludeDatanodeManager getExcludeDatanodeManager() {
506507
return excludeDatanodeManager;
507508
}
509+
510+
@RestrictedApi(explanation = "Should only be called in tests", link = "",
511+
allowedOnPath = ".*/src/test/.*")
512+
public String getFactoryId() {
513+
return this.factoryId;
514+
}
508515
}

hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestWarmupRegion.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@
2121
import static org.junit.Assert.assertTrue;
2222

2323
import java.io.IOException;
24-
import org.apache.hadoop.conf.Configuration;
2524
import org.apache.hadoop.hbase.HBaseClassTestRule;
2625
import org.apache.hadoop.hbase.HBaseTestingUtil;
27-
import org.apache.hadoop.hbase.SingleProcessHBaseCluster;
2826
import org.apache.hadoop.hbase.TableName;
2927
import org.apache.hadoop.hbase.Waiter;
3028
import org.apache.hadoop.hbase.client.CompactionState;
@@ -54,7 +52,6 @@
5452
* named for the method and does its stuff against that.
5553
*/
5654
@Category({ MasterTests.class, LargeTests.class })
57-
@SuppressWarnings("deprecation")
5855
public class TestWarmupRegion {
5956

6057
@ClassRule
@@ -66,20 +63,17 @@ public class TestWarmupRegion {
6663
protected final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
6764
private static byte[] ROW = Bytes.toBytes("testRow");
6865
private static byte[] FAMILY = Bytes.toBytes("testFamily");
69-
private static byte[] QUALIFIER = Bytes.toBytes("testQualifier");
7066
private static byte[] VALUE = Bytes.toBytes("testValue");
7167
private static byte[] COLUMN = Bytes.toBytes("column");
7268
private static int numRows = 10000;
7369
protected static int SLAVES = 3;
74-
private static SingleProcessHBaseCluster myCluster;
7570
private static Table table;
7671

7772
/**
7873
* @throws java.lang.Exception
7974
*/
8075
@BeforeClass
8176
public static void setUpBeforeClass() throws Exception {
82-
Configuration conf = TEST_UTIL.getConfiguration();
8377
TEST_UTIL.startMiniCluster(SLAVES);
8478
}
8579

0 commit comments

Comments
 (0)