@@ -399,6 +399,9 @@ public void setRestoredRegion(boolean restoredRegion) {
399399 private final int miniBatchSize ;
400400
401401 final ConcurrentHashMap <RegionScanner , Long > scannerReadPoints ;
402+ // Lock to manage concurrency between RegionScanner and getSmallestReadPoint
403+ final ReentrantReadWriteLock scannerReadPointsLock = new ReentrantReadWriteLock ();
404+ final boolean useReadWriteLockForReadPoints ;
402405
403406 /**
404407 * The sequence ID that was enLongAddered when this region was opened.
@@ -446,18 +449,26 @@ public long getSmallestReadPoint() {
446449 long minimumReadPoint ;
447450 // We need to ensure that while we are calculating the smallestReadPoint
448451 // no new RegionScanners can grab a readPoint that we are unaware of.
449- // We achieve this by synchronizing on the scannerReadPoints object.
450- synchronized (scannerReadPoints ) {
451- minimumReadPoint = mvcc .getReadPoint ();
452- for (Long readPoint : this .scannerReadPoints .values ()) {
453- if (readPoint < minimumReadPoint ) {
454- minimumReadPoint = readPoint ;
455- }
452+ if (useReadWriteLockForReadPoints ) {
453+ scannerReadPointsLock .writeLock ().lock ();
454+ try {
455+ minimumReadPoint = calculateSmallestReadPoint ();
456+ } finally {
457+ scannerReadPointsLock .writeLock ().unlock ();
458+ }
459+ } else {
460+ // We achieve this by synchronizing on the scannerReadPoints object.
461+ synchronized (scannerReadPoints ) {
462+ minimumReadPoint = calculateSmallestReadPoint ();
456463 }
457464 }
458465 return minimumReadPoint ;
459466 }
460467
468+ private long calculateSmallestReadPoint () {
469+ return scannerReadPoints .values ().stream ().mapToLong (Long ::longValue ).min ().orElse (0L );
470+ }
471+
461472 /*
462473 * Data structure of write state flags used coordinating flushes, compactions and closes.
463474 */
@@ -798,6 +809,13 @@ public HRegion(final HRegionFileSystem fs, final WAL wal, final Configuration co
798809 }
799810 this .rowLockWaitDuration = tmpRowLockDuration ;
800811
812+ this .useReadWriteLockForReadPoints =
813+ conf .getBoolean ("hbase.readpoints.read.write.lock.enable" , false );
814+ if (LOG .isDebugEnabled ()) {
815+ LOG .debug ("region = {}, useReadWriteLockForReadPoints = {}" , getRegionInfo (),
816+ useReadWriteLockForReadPoints );
817+ }
818+
801819 this .isLoadingCfsOnDemandDefault = conf .getBoolean (LOAD_CFS_ON_DEMAND_CONFIG_KEY , true );
802820 this .htableDescriptor = htd ;
803821 Set <byte []> families = this .htableDescriptor .getColumnFamilyNames ();
@@ -8145,7 +8163,7 @@ private void doAttachReplicateRegionReplicaAction(WALKeyImpl walKey, WALEdit wal
81458163 (3 * ClassSize .CONCURRENT_HASHMAP ) + // lockedRows, scannerReadPoints, regionLockHolders
81468164 WriteState .HEAP_SIZE + // writestate
81478165 ClassSize .CONCURRENT_SKIPLISTMAP + ClassSize .CONCURRENT_SKIPLISTMAP_ENTRY + // stores
8148- (2 * ClassSize .REENTRANT_LOCK ) + // lock, updatesLock
8166+ (3 * ClassSize .REENTRANT_LOCK ) + // lock, updatesLock, scannerReadPointsLock
81498167 MultiVersionConcurrencyControl .FIXED_SIZE // mvcc
81508168 + 2 * ClassSize .TREEMAP // maxSeqIdInStores, replicationScopes
81518169 + 2 * ClassSize .ATOMIC_INTEGER // majorInProgress, minorInProgress
0 commit comments