HBASE-16304 HRegion#RegionScannerImpl#handleFileNotFoundException may lead to deadlock when trying to obtain write lock on updatesLock
This commit is contained in:
parent
dda8f67b2c
commit
bf7015d320
|
@ -239,6 +239,9 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
protected volatile long lastReplayedOpenRegionSeqId = -1L;
|
protected volatile long lastReplayedOpenRegionSeqId = -1L;
|
||||||
protected volatile long lastReplayedCompactionSeqId = -1L;
|
protected volatile long lastReplayedCompactionSeqId = -1L;
|
||||||
|
|
||||||
|
// collects Map(s) of Store to sequence Id when handleFileNotFound() is involved
|
||||||
|
protected List<Map> storeSeqIds = new ArrayList<>();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Members
|
// Members
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -4970,6 +4973,7 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
|
|
||||||
startRegionOperation(); // obtain region close lock
|
startRegionOperation(); // obtain region close lock
|
||||||
try {
|
try {
|
||||||
|
Map<Store, Long> map = new HashMap<Store, Long>();
|
||||||
synchronized (writestate) {
|
synchronized (writestate) {
|
||||||
for (Store store : getStores()) {
|
for (Store store : getStores()) {
|
||||||
// TODO: some stores might see new data from flush, while others do not which
|
// TODO: some stores might see new data from flush, while others do not which
|
||||||
|
@ -5002,8 +5006,7 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop the memstore contents if they are now smaller than the latest seen flushed file
|
map.put(store, storeSeqId);
|
||||||
totalFreedSize += dropMemstoreContentsForSeqId(storeSeqId, store);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5026,6 +5029,19 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;
|
this.lastReplayedOpenRegionSeqId = smallestSeqIdInStores;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!map.isEmpty()) {
|
||||||
|
if (!force) {
|
||||||
|
for (Map.Entry<Store, Long> entry : map.entrySet()) {
|
||||||
|
// Drop the memstore contents if they are now smaller than the latest seen flushed file
|
||||||
|
totalFreedSize += dropMemstoreContentsForSeqId(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronized (storeSeqIds) {
|
||||||
|
// don't try to acquire write lock of updatesLock now
|
||||||
|
storeSeqIds.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// C. Finally notify anyone waiting on memstore to clear:
|
// C. Finally notify anyone waiting on memstore to clear:
|
||||||
// e.g. checkResources().
|
// e.g. checkResources().
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
@ -7141,6 +7157,28 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);
|
return increment(increment, HConstants.NO_NONCE, HConstants.NO_NONCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dropMemstoreContentsForSeqId() would acquire write lock of updatesLock
|
||||||
|
// We perform this operation outside of the read lock of updatesLock to avoid dead lock
|
||||||
|
// See HBASE-16304
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void dropMemstoreContents() throws IOException {
|
||||||
|
long totalFreedSize = 0;
|
||||||
|
while (!storeSeqIds.isEmpty()) {
|
||||||
|
Map<Store, Long> map = null;
|
||||||
|
synchronized (storeSeqIds) {
|
||||||
|
if (storeSeqIds.isEmpty()) break;
|
||||||
|
map = storeSeqIds.remove(storeSeqIds.size()-1);
|
||||||
|
}
|
||||||
|
for (Map.Entry<Store, Long> entry : map.entrySet()) {
|
||||||
|
// Drop the memstore contents if they are now smaller than the latest seen flushed file
|
||||||
|
totalFreedSize += dropMemstoreContentsForSeqId(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (totalFreedSize > 0) {
|
||||||
|
LOG.debug("Freed " + totalFreedSize + " bytes from memstore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result increment(Increment mutation, long nonceGroup, long nonce)
|
public Result increment(Increment mutation, long nonceGroup, long nonce)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -7206,6 +7244,10 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
writeEntry = null;
|
writeEntry = null;
|
||||||
} finally {
|
} finally {
|
||||||
this.updatesLock.readLock().unlock();
|
this.updatesLock.readLock().unlock();
|
||||||
|
// For increment/append, a region scanner for doing a get operation could throw
|
||||||
|
// FileNotFoundException. So we call dropMemstoreContents() in finally block
|
||||||
|
// after releasing read lock
|
||||||
|
dropMemstoreContents();
|
||||||
}
|
}
|
||||||
// If results is null, then client asked that we not return the calculated results.
|
// If results is null, then client asked that we not return the calculated results.
|
||||||
return results != null && returnResults? Result.create(results): null;
|
return results != null && returnResults? Result.create(results): null;
|
||||||
|
@ -7546,7 +7588,7 @@ public class HRegion implements HeapSize, PropagatingConfigurationObserver, Regi
|
||||||
public static final long FIXED_OVERHEAD = ClassSize.align(
|
public static final long FIXED_OVERHEAD = ClassSize.align(
|
||||||
ClassSize.OBJECT +
|
ClassSize.OBJECT +
|
||||||
ClassSize.ARRAY +
|
ClassSize.ARRAY +
|
||||||
48 * ClassSize.REFERENCE + 2 * Bytes.SIZEOF_INT +
|
49 * ClassSize.REFERENCE + 2 * Bytes.SIZEOF_INT +
|
||||||
(14 * Bytes.SIZEOF_LONG) +
|
(14 * Bytes.SIZEOF_LONG) +
|
||||||
5 * Bytes.SIZEOF_BOOLEAN);
|
5 * Bytes.SIZEOF_BOOLEAN);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue