-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-24877 Add option to avoid aborting RS process upon uncaught exc… #2255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
5a0adaf
3fb4dce
8af3041
84994f9
e716047
2fcf714
16db51e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ | |
| import java.util.concurrent.PriorityBlockingQueue; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.concurrent.TimeoutException; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import java.util.concurrent.atomic.AtomicLong; | ||
| import java.util.function.Predicate; | ||
| import org.apache.commons.lang3.StringUtils; | ||
|
|
@@ -119,6 +120,14 @@ public class ReplicationSource implements ReplicationSourceInterface { | |
| private int logQueueWarnThreshold; | ||
| // ReplicationEndpoint which will handle the actual replication | ||
| private volatile ReplicationEndpoint replicationEndpoint; | ||
| //This is needed for the startup loop to identify when there's already | ||
| // an initialization happening (but not finished yet), | ||
| // so that it doesn't try submit another initialize thread. | ||
| // NOTE: this should only be set to false at the end of initialize method, prior to return. | ||
| // private final AtomicBoolean startupOngoing = new AtomicBoolean(false); | ||
|
|
||
| private boolean abortOnError; | ||
|
|
||
|
|
||
| /** | ||
| * A filter (or a chain of filters) for WAL entries; filters out edits. | ||
|
|
@@ -217,6 +226,10 @@ public void init(Configuration conf, FileSystem fs, ReplicationSourceManager man | |
| this.throttler = new ReplicationThrottler((double) currentBandwidth / 10.0); | ||
| this.totalBufferUsed = manager.getTotalBufferUsed(); | ||
| this.walFileLengthProvider = walFileLengthProvider; | ||
|
|
||
| this.abortOnError = this.conf.getBoolean("replication.source.regionserver.abort", | ||
| true); | ||
|
|
||
| LOG.info("queueId={}, ReplicationSource: {}, currentBandwidth={}", queueId, | ||
| replicationPeer.getId(), this.currentBandwidth); | ||
| } | ||
|
|
@@ -373,9 +386,9 @@ private void tryStartNewShipper(String walGroupId, PriorityBlockingQueue<Path> q | |
| Threads.setDaemonThreadRunning( | ||
| walReader, Thread.currentThread().getName() | ||
| + ".replicationSource.wal-reader." + walGroupId + "," + queueId, | ||
| this::uncaughtException); | ||
| (t,e) -> this.uncaughtException(t, e, this.manager, this.getPeerId())); | ||
| worker.setWALReader(walReader); | ||
| worker.startup(this::uncaughtException); | ||
| worker.startup((t,e) -> this.uncaughtException(t, e, this.manager, this.getPeerId())); | ||
| return worker; | ||
| } | ||
| }); | ||
|
|
@@ -450,11 +463,28 @@ WALEntryFilter getWalEntryFilter() { | |
| return walEntryFilter; | ||
| } | ||
|
|
||
| protected final void uncaughtException(Thread t, Throwable e) { | ||
| protected final void uncaughtException(Thread t, Throwable e, | ||
| ReplicationSourceManager manager, String peerId) { | ||
| RSRpcServices.exitIfOOME(e); | ||
| LOG.error("Unexpected exception in {} currentPath={}", | ||
| t.getName(), getCurrentPath(), e); | ||
| server.abort("Unexpected exception in " + t.getName(), e); | ||
| if(abortOnError){ | ||
| server.abort("Unexpected exception in " + t.getName(), e); | ||
| } | ||
| if(manager!=null){ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to update the formatter config? Usually it should be 'if (manager != null) {'. |
||
| while (true) { | ||
| try { | ||
| LOG.info("Refreshing replication sources now due to previous error on thread: {}", | ||
| t.getName()); | ||
| manager.refreshSources(peerId); | ||
| break; | ||
| } catch (IOException e1) { | ||
| LOG.error("Replication sources refresh failed.", e1); | ||
| sleepForRetries("Sleeping before try refreshing sources again", | ||
| maxRetriesMultiplier); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -587,12 +617,25 @@ private void initialize() { | |
|
|
||
| @Override | ||
| public void startup() { | ||
| // mark we are running now | ||
| this.sourceRunning = true; | ||
| initThread = new Thread(this::initialize); | ||
| Threads.setDaemonThreadRunning(initThread, | ||
| Thread.currentThread().getName() + ".replicationSource," + this.queueId, | ||
| this::uncaughtException); | ||
| //Flag that signalizes uncaught error happening while starting up the source | ||
| // and a retry should be attempted | ||
| AtomicBoolean retryStartup = new AtomicBoolean(false); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we need a AtomicBoolean here? It is only used locally, so a simple boolean is enough?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's been modified by the lambda expression on line #635, since lambdas expressions require variables to be final, I can't use a simple, local primitive boolean or wrapper.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then use MutableBoolean? We do not need to use atomic here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, thanks for suggesting MutableBoolean, am not too familiar with apache commons lib. |
||
| retryStartup.set(true); | ||
| do { | ||
| if(retryStartup.get()) { | ||
| retryStartup.set(false); | ||
| // mark we are running now | ||
| this.sourceRunning = true; | ||
| initThread = new Thread(this::initialize); | ||
| Threads.setDaemonThreadRunning(initThread, | ||
| Thread.currentThread().getName() + ".replicationSource," + this.queueId, | ||
| (t,e) -> { | ||
| sourceRunning = false; | ||
| uncaughtException(t, e, null, null); | ||
| retryStartup.set(true); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hope if we encounter uncaughtException here, we want to retry the loop again.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, we want to keep trying until we succeed.
The only cases
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah right, it is not set to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed the nits and added some comments to the two flags. |
||
| }); | ||
| } | ||
| } while (!this.sourceRunning); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a second thought on this here, we can't simply re-use this boolean, because in case of failure, we risk reach this point before the exception handler has updated it to false. I'm bringing back the original startupOngoing in the next commit, |
||
| } | ||
|
|
||
| @Override | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: indent?