17
17
*/
18
18
package org .apache .hadoop .hbase .master .procedure ;
19
19
20
+ import com .google .errorprone .annotations .RestrictedApi ;
20
21
import java .io .IOException ;
21
22
import java .util .Arrays ;
22
23
import java .util .HashMap ;
23
24
import java .util .List ;
24
25
import java .util .Map ;
25
26
import java .util .Optional ;
27
+ import java .util .function .Consumer ;
26
28
import java .util .function .Function ;
27
29
import java .util .function .Supplier ;
28
30
import org .apache .commons .lang3 .builder .ToStringBuilder ;
@@ -418,7 +420,9 @@ private static <T extends Comparable<T>> void removeFromRunQueue(FairQueue<T> fa
418
420
// ============================================================================
419
421
private TableQueue getTableQueue (TableName tableName ) {
420
422
TableQueue node = AvlTree .get (tableMap , tableName , TABLE_QUEUE_KEY_COMPARATOR );
421
- if (node != null ) return node ;
423
+ if (node != null ) {
424
+ return node ;
425
+ }
422
426
423
427
node = new TableQueue (tableName , MasterProcedureUtil .getTablePriority (tableName ),
424
428
locking .getTableLock (tableName ), locking .getNamespaceLock (tableName .getNamespaceAsString ()));
@@ -431,6 +435,21 @@ private void removeTableQueue(TableName tableName) {
431
435
locking .removeTableLock (tableName );
432
436
}
433
437
438
+ /**
439
+ * Tries to remove the queue and the table-lock of the specified table. If there are new
440
+ * operations pending (e.g. a new create), the remove will not be performed.
441
+ * @param table the name of the table that should be marked as deleted
442
+ * @param procedure the procedure that is removing the table
443
+ * @return true if deletion succeeded, false otherwise meaning that there are other new operations
444
+ * pending for that table (e.g. a new create).
445
+ */
446
+ @ RestrictedApi (explanation = "Should only be called in tests" , link = "" ,
447
+ allowedOnPath = ".*/(MasterProcedureScheduler.java|src/test/.*)" )
448
+ boolean markTableAsDeleted (final TableName table , final Procedure <?> procedure ) {
449
+ return tryCleanupQueue (table , procedure , () -> tableMap , TABLE_QUEUE_KEY_COMPARATOR ,
450
+ locking ::getTableLock , tableRunQueue , this ::removeTableQueue );
451
+ }
452
+
434
453
private static boolean isTableProcedure (Procedure <?> proc ) {
435
454
return proc instanceof TableProcedureInterface ;
436
455
}
@@ -467,23 +486,10 @@ private void removeServerQueue(ServerName serverName) {
467
486
}
468
487
469
488
private void tryCleanupServerQueue (ServerName serverName , Procedure <?> proc ) {
470
- schedLock ();
471
- try {
472
- int index = getBucketIndex (serverBuckets , serverName .hashCode ());
473
- ServerQueue node = AvlTree .get (serverBuckets [index ], serverName , SERVER_QUEUE_KEY_COMPARATOR );
474
- if (node == null ) {
475
- return ;
476
- }
477
-
478
- LockAndQueue lock = locking .getServerLock (serverName );
479
- if (node .isEmpty () && lock .tryExclusiveLock (proc )) {
480
- removeFromRunQueue (serverRunQueue , node ,
481
- () -> "clean up server queue after " + proc + " completed" );
482
- removeServerQueue (serverName );
483
- }
484
- } finally {
485
- schedUnlock ();
486
- }
489
+ // serverBuckets
490
+ tryCleanupQueue (serverName , proc ,
491
+ () -> serverBuckets [getBucketIndex (serverBuckets , serverName .hashCode ())],
492
+ SERVER_QUEUE_KEY_COMPARATOR , locking ::getServerLock , serverRunQueue , this ::removeServerQueue );
487
493
}
488
494
489
495
private static int getBucketIndex (Object [] buckets , int hashCode ) {
@@ -516,23 +522,9 @@ private void removePeerQueue(String peerId) {
516
522
locking .removePeerLock (peerId );
517
523
}
518
524
519
- private void tryCleanupPeerQueue (String peerId , Procedure procedure ) {
520
- schedLock ();
521
- try {
522
- PeerQueue queue = AvlTree .get (peerMap , peerId , PEER_QUEUE_KEY_COMPARATOR );
523
- if (queue == null ) {
524
- return ;
525
- }
526
-
527
- final LockAndQueue lock = locking .getPeerLock (peerId );
528
- if (queue .isEmpty () && lock .tryExclusiveLock (procedure )) {
529
- removeFromRunQueue (peerRunQueue , queue ,
530
- () -> "clean up peer queue after " + procedure + " completed" );
531
- removePeerQueue (peerId );
532
- }
533
- } finally {
534
- schedUnlock ();
535
- }
525
+ private void tryCleanupPeerQueue (String peerId , Procedure <?> procedure ) {
526
+ tryCleanupQueue (peerId , procedure , () -> peerMap , PEER_QUEUE_KEY_COMPARATOR ,
527
+ locking ::getPeerLock , peerRunQueue , this ::removePeerQueue );
536
528
}
537
529
538
530
private static boolean isPeerProcedure (Procedure <?> proc ) {
@@ -560,6 +552,35 @@ private static boolean isMetaProcedure(Procedure<?> proc) {
560
552
return proc instanceof MetaProcedureInterface ;
561
553
}
562
554
555
+ private <T extends Comparable <T >, TNode extends Queue <T >> boolean tryCleanupQueue (T id ,
556
+ Procedure <?> proc , Supplier <TNode > getMap , AvlKeyComparator <TNode > comparator ,
557
+ Function <T , LockAndQueue > getLock , FairQueue <T > runQueue , Consumer <T > removeQueue ) {
558
+ schedLock ();
559
+ try {
560
+ Queue <T > queue = AvlTree .get (getMap .get (), id , comparator );
561
+ if (queue == null ) {
562
+ return true ;
563
+ }
564
+
565
+ LockAndQueue lock = getLock .apply (id );
566
+ if (queue .isEmpty () && lock .isWaitingQueueEmpty () && !lock .isLocked ()) {
567
+ // 1. the queue is empty
568
+ // 2. no procedure is in the lock's waiting queue
569
+ // 3. no other one holds the lock. It is possible that someone else holds the lock, usually
570
+ // our parent procedures
571
+ // If we can meet all the above conditions, it is safe for us to remove the queue
572
+ removeFromRunQueue (runQueue , queue , () -> "clean up queue after " + proc + " completed" );
573
+ removeQueue .accept (id );
574
+ return true ;
575
+ } else {
576
+ return false ;
577
+ }
578
+
579
+ } finally {
580
+ schedUnlock ();
581
+ }
582
+ }
583
+
563
584
// ============================================================================
564
585
// Table Locking Helpers
565
586
// ============================================================================
@@ -699,39 +720,6 @@ public void wakeTableSharedLock(final Procedure<?> procedure, final TableName ta
699
720
}
700
721
}
701
722
702
- /**
703
- * Tries to remove the queue and the table-lock of the specified table. If there are new
704
- * operations pending (e.g. a new create), the remove will not be performed.
705
- * @param table the name of the table that should be marked as deleted
706
- * @param procedure the procedure that is removing the table
707
- * @return true if deletion succeeded, false otherwise meaning that there are other new operations
708
- * pending for that table (e.g. a new create).
709
- */
710
- boolean markTableAsDeleted (final TableName table , final Procedure <?> procedure ) {
711
- schedLock ();
712
- try {
713
- final TableQueue queue = getTableQueue (table );
714
- final LockAndQueue tableLock = locking .getTableLock (table );
715
- if (queue == null ) {
716
- return true ;
717
- }
718
-
719
- if (queue .isEmpty () && tableLock .tryExclusiveLock (procedure )) {
720
- // remove the table from the run-queue and the map
721
- if (AvlIterableList .isLinked (queue )) {
722
- tableRunQueue .remove (queue );
723
- }
724
- removeTableQueue (table );
725
- } else {
726
- // TODO: If there are no create, we can drop all the other ops
727
- return false ;
728
- }
729
- } finally {
730
- schedUnlock ();
731
- }
732
- return true ;
733
- }
734
-
735
723
// ============================================================================
736
724
// Region Locking Helpers
737
725
// ============================================================================
0 commit comments