Skip to content

Commit 54b49a0

Browse files
ramkrish86Jenkins
authored andcommitted
HBASE-22072 High read/write intensive regions may cause long crash (apache#214)
* HBASE-22072 High read/write intensive regions may cause long crash recovery * Make the 'closing' variable as volatile and move the test case to standlone class (cherry picked from commit 8d56693) Change-Id: I3bd6e4f030458516aebe3c7adb96712cbef16b20
1 parent 614572a commit 54b49a0

File tree

3 files changed

+319
-26
lines changed

3 files changed

+319
-26
lines changed

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

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ public class StoreScanner extends NonReversedNonLazyKeyValueScanner
7979
private int storeOffset = 0;
8080

8181
// Used to indicate that the scanner has closed (see HBASE-1107)
82-
// Do not need to be volatile because it's always accessed via synchronized methods
83-
private boolean closing = false;
82+
private volatile boolean closing = false;
8483
private final boolean get;
8584
private final boolean explicitColumnQuery;
8685
private final boolean useRowColBloom;
@@ -157,6 +156,8 @@ public class StoreScanner extends NonReversedNonLazyKeyValueScanner
157156
final List<KeyValueScanner> currentScanners = new ArrayList<>();
158157
// flush update lock
159158
private final ReentrantLock flushLock = new ReentrantLock();
159+
// lock for closing.
160+
private final ReentrantLock closeLock = new ReentrantLock();
160161

161162
protected final long readPt;
162163
private boolean topChanged = false;
@@ -473,31 +474,38 @@ public void close() {
473474
}
474475

475476
private void close(boolean withDelayedScannersClose) {
476-
if (this.closing) {
477-
return;
478-
}
479-
if (withDelayedScannersClose) {
480-
this.closing = true;
481-
}
482-
// For mob compaction, we do not have a store.
483-
if (this.store != null) {
484-
this.store.deleteChangedReaderObserver(this);
485-
}
486-
if (withDelayedScannersClose) {
487-
clearAndClose(scannersForDelayedClose);
488-
clearAndClose(memStoreScannersAfterFlush);
489-
clearAndClose(flushedstoreFileScanners);
490-
if (this.heap != null) {
491-
this.heap.close();
492-
this.currentScanners.clear();
493-
this.heap = null; // CLOSED!
477+
closeLock.lock();
478+
// If the closeLock is acquired then any subsequent updateReaders()
479+
// call is ignored.
480+
try {
481+
if (this.closing) {
482+
return;
494483
}
495-
} else {
496-
if (this.heap != null) {
497-
this.scannersForDelayedClose.add(this.heap);
498-
this.currentScanners.clear();
499-
this.heap = null;
484+
if (withDelayedScannersClose) {
485+
this.closing = true;
486+
}
487+
// For mob compaction, we do not have a store.
488+
if (this.store != null) {
489+
this.store.deleteChangedReaderObserver(this);
500490
}
491+
if (withDelayedScannersClose) {
492+
clearAndClose(scannersForDelayedClose);
493+
clearAndClose(memStoreScannersAfterFlush);
494+
clearAndClose(flushedstoreFileScanners);
495+
if (this.heap != null) {
496+
this.heap.close();
497+
this.currentScanners.clear();
498+
this.heap = null; // CLOSED!
499+
}
500+
} else {
501+
if (this.heap != null) {
502+
this.scannersForDelayedClose.add(this.heap);
503+
this.currentScanners.clear();
504+
this.heap = null;
505+
}
506+
}
507+
} finally {
508+
closeLock.unlock();
501509
}
502510
}
503511

@@ -876,8 +884,25 @@ public void updateReaders(List<HStoreFile> sfs, List<KeyValueScanner> memStoreSc
876884
if (CollectionUtils.isEmpty(sfs) && CollectionUtils.isEmpty(memStoreScanners)) {
877885
return;
878886
}
887+
boolean updateReaders = false;
879888
flushLock.lock();
880889
try {
890+
if (!closeLock.tryLock()) {
891+
// The reason for doing this is that when the current store scanner does not retrieve
892+
// any new cells, then the scanner is considered to be done. The heap of this scanner
893+
// is not closed till the shipped() call is completed. Hence in that case if at all
894+
// the partial close (close (false)) has been called before updateReaders(), there is no
895+
// need for the updateReaders() to happen.
896+
LOG.debug("StoreScanner already has the close lock. There is no need to updateReaders");
897+
// no lock acquired.
898+
return;
899+
}
900+
// lock acquired
901+
updateReaders = true;
902+
if (this.closing) {
903+
LOG.debug("StoreScanner already closing. There is no need to updateReaders");
904+
return;
905+
}
881906
flushed = true;
882907
final boolean isCompaction = false;
883908
boolean usePread = get || scanUsePread;
@@ -896,6 +921,9 @@ public void updateReaders(List<HStoreFile> sfs, List<KeyValueScanner> memStoreSc
896921
}
897922
} finally {
898923
flushLock.unlock();
924+
if (updateReaders) {
925+
closeLock.unlock();
926+
}
899927
}
900928
// Let the next() call handle re-creating and seeking
901929
}

hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestStoreScanner.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434
import java.util.OptionalInt;
3535
import java.util.TreeSet;
3636
import java.util.concurrent.atomic.AtomicInteger;
37+
3738
import org.apache.hadoop.conf.Configuration;
3839
import org.apache.hadoop.hbase.Cell;
3940
import org.apache.hadoop.hbase.CellComparator;
4041
import org.apache.hadoop.hbase.CellUtil;
4142
import org.apache.hadoop.hbase.HBaseClassTestRule;
4243
import org.apache.hadoop.hbase.HBaseConfiguration;
44+
import org.apache.hadoop.hbase.HBaseTestingUtility;
4345
import org.apache.hadoop.hbase.HConstants;
4446
import org.apache.hadoop.hbase.KeepDeletedCells;
4547
import org.apache.hadoop.hbase.KeyValue;
@@ -74,6 +76,7 @@ public class TestStoreScanner {
7476
private static final String CF_STR = "cf";
7577
private static final byte[] CF = Bytes.toBytes(CF_STR);
7678
static Configuration CONF = HBaseConfiguration.create();
79+
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
7780
private ScanInfo scanInfo = new ScanInfo(CONF, CF, 0, Integer.MAX_VALUE, Long.MAX_VALUE,
7881
KeepDeletedCells.FALSE, HConstants.DEFAULT_BLOCKSIZE, 0, CellComparator.getInstance(), false);
7982

@@ -847,7 +850,6 @@ public void testScannerReseekDoesntNPE() throws Exception {
847850
}
848851
}
849852

850-
851853
@Test @Ignore("this fails, since we don't handle deletions, etc, in peek")
852854
public void testPeek() throws Exception {
853855
KeyValue[] kvs = new KeyValue [] {

0 commit comments

Comments
 (0)