-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-30341: Fix FSHLog WAL lockup on uncaught exception in publishSyncOnRingBuffer #8611
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
base: branch-2
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -794,8 +794,11 @@ private SyncFuture publishSyncOnRingBuffer(boolean forceSync) { | |
|
|
||
| protected SyncFuture publishSyncOnRingBuffer(long sequence, boolean forceSync) { | ||
| // here we use ring buffer sequence as transaction id | ||
| SyncFuture syncFuture = getSyncFuture(sequence, forceSync); | ||
| // getSyncFuture must stay inside the try: the sequence is already claimed, so we must publish | ||
| // it even if this throws, else the consumer wedges. | ||
| SyncFuture syncFuture = null; | ||
| try { | ||
| syncFuture = getSyncFuture(sequence, forceSync); | ||
| RingBufferTruck truck = this.disruptor.getRingBuffer().get(sequence); | ||
| truck.load(syncFuture); | ||
| } finally { | ||
|
|
@@ -1079,11 +1082,13 @@ public void onEvent(final RingBufferTruck truck, final long sequence, boolean en | |
| } finally { | ||
| entry.release(); | ||
| } | ||
| } else if (truck.type() == RingBufferTruck.Type.EMPTY) { | ||
| // publishSyncOnRingBuffer claimed the sequence but threw before loading the truck. | ||
| LOG.warn("Empty RingBufferTruck at sequence {}", sequence); | ||
| return; | ||
| } else { | ||
| // What is this if not an append or sync. Fail all up to this!!! | ||
| cleanupOutstandingSyncsOnException(sequence, | ||
| new IllegalStateException("Neither append nor sync")); | ||
| // Return to keep processing. | ||
| new IllegalStateException("Unexpected truck type: " + truck.type())); | ||
| return; | ||
|
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. Should we keep the
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. Agreed, it should be the same but more readable if we return |
||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,8 @@ | |
| import org.apache.hadoop.conf.Configuration; | ||
| import org.apache.hadoop.hbase.HConstants; | ||
| import org.apache.yetus.audience.InterfaceAudience; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import org.apache.hbase.thirdparty.com.google.common.cache.Cache; | ||
| import org.apache.hbase.thirdparty.com.google.common.cache.CacheBuilder; | ||
|
|
@@ -45,6 +47,8 @@ | |
| @InterfaceAudience.Private | ||
| public final class SyncFutureCache { | ||
|
|
||
| private static final Logger LOG = LoggerFactory.getLogger(SyncFutureCache.class); | ||
|
|
||
| private static final long SYNC_FUTURE_INVALIDATION_TIMEOUT_MINS = 2; | ||
|
|
||
| private final Cache<Thread, SyncFuture> syncFutureCache; | ||
|
|
@@ -57,9 +61,15 @@ public SyncFutureCache(final Configuration conf) { | |
| } | ||
|
|
||
| public SyncFuture getIfPresentOrNew() { | ||
| // Invalidate the entry if a mapping exists. We do not want it to be reused at the same time. | ||
| SyncFuture future = syncFutureCache.asMap().remove(Thread.currentThread()); | ||
| return (future == null) ? new SyncFuture() : future; | ||
| // The cache is only an allocation optimisation; never let it fail a write. | ||
| try { | ||
| // Invalidate the entry if a mapping exists. We do not want it to be reused at the same time. | ||
| SyncFuture future = syncFutureCache.asMap().remove(Thread.currentThread()); | ||
| return (future == null) ? new SyncFuture() : future; | ||
| } catch (RuntimeException e) { | ||
|
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. Where does the RuntimeException come from?
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. There can be the same NPE from Guava's java.lang.NullPointerException: Cannot invoke "...ReferenceEntry.setNextInWriteQueue(...)" because "previous" is null
at org.apache.hbase.thirdparty.com.google.common.cache.LocalCache.connectWriteOrder(LocalCache.java:1818)
at org.apache.hbase.thirdparty.com.google.common.cache.LocalCache$WriteQueue.remove(LocalCache.java:3725)
at org.apache.hbase.thirdparty.com.google.common.cache.LocalCache.remove(LocalCache.java:4273)
at org.apache.hadoop.hbase.regionserver.wal.SyncFutureCache.getIfPresentOrNew(SyncFutureCache.java:61)I'm happy to reduce this to just a NPE catch if you'd like. I kept it broad so any exception falls back to a new SyncFuture() |
||
| LOG.warn("SyncFutureCache lookup failed; falling back to a new SyncFuture", e); | ||
| return new SyncFuture(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
||
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.
What exception will getSyncFuture throw? Seems the method only has memory operations...
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.
It's all in-memory, but the memory it mutates is Guava's
LocalCache, and its write-order queue (present becauseSyncFutureCacheusesexpireAfterWrite) can NPE under a race. We hit it in production on branch-2.6 (hbase.wal.provider=filesystem):