2121import java .util .List ;
2222import java .util .Optional ;
2323import org .apache .hadoop .conf .Configuration ;
24+ import org .apache .hadoop .fs .FileSystem ;
25+ import org .apache .hadoop .fs .Path ;
2426import org .apache .hadoop .hbase .CompareOperator ;
2527import org .apache .hadoop .hbase .CoprocessorEnvironment ;
2628import org .apache .hadoop .hbase .HBaseInterfaceAudience ;
5153import org .apache .hadoop .hbase .coprocessor .RegionServerObserver ;
5254import org .apache .hadoop .hbase .filter .ByteArrayComparable ;
5355import org .apache .hadoop .hbase .filter .Filter ;
56+ import org .apache .hadoop .hbase .master .MasterFileSystem ;
57+ import org .apache .hadoop .hbase .master .MasterServices ;
5458import org .apache .hadoop .hbase .regionserver .FlushLifeCycleTracker ;
5559import org .apache .hadoop .hbase .regionserver .MiniBatchOperationInProgress ;
5660import org .apache .hadoop .hbase .regionserver .Store ;
5761import org .apache .hadoop .hbase .regionserver .StoreFile ;
5862import org .apache .hadoop .hbase .regionserver .compactions .CompactionLifeCycleTracker ;
63+ import org .apache .hadoop .hbase .util .FSUtils ;
5964import org .apache .hadoop .hbase .util .Pair ;
6065import org .apache .hadoop .hbase .wal .WALEdit ;
6166import org .apache .yetus .audience .InterfaceAudience ;
@@ -74,6 +79,8 @@ public class ReadOnlyController implements MasterCoprocessor, RegionCoprocessor,
7479 ConfigurationObserver {
7580
7681 private static final Logger LOG = LoggerFactory .getLogger (ReadOnlyController .class );
82+ private MasterServices masterServices ;
83+
7784 private volatile boolean globalReadOnlyEnabled ;
7885
7986 private void internalReadOnlyGuard () throws IOException {
@@ -84,7 +91,13 @@ private void internalReadOnlyGuard() throws IOException {
8491
8592 @ Override
8693 public void start (CoprocessorEnvironment env ) throws IOException {
87-
94+ if (env instanceof MasterCoprocessorEnvironment ) {
95+ this .masterServices = ((MasterCoprocessorEnvironment ) env ).getMasterServices ();
96+ LOG .info ("ReadOnlyController obtained MasterServices reference from start()." );
97+ } else {
98+ LOG .debug ("ReadOnlyController loaded in a non-Master environment. "
99+ + "File system operations for read-only state will not work." );
100+ }
88101 this .globalReadOnlyEnabled =
89102 env .getConfiguration ().getBoolean (HConstants .HBASE_GLOBAL_READONLY_ENABLED_KEY ,
90103 HConstants .HBASE_GLOBAL_READONLY_ENABLED_DEFAULT );
@@ -411,14 +424,50 @@ public void preCleanupBulkLoad(ObserverContext<RegionCoprocessorEnvironment> ctx
411424 BulkLoadObserver .super .preCleanupBulkLoad (ctx );
412425 }
413426
427+ private void manageActiveClusterIdFile (boolean newValue ) {
428+ MasterFileSystem mfs = this .masterServices .getMasterFileSystem ();
429+ FileSystem fs = mfs .getFileSystem ();
430+ Path rootDir = mfs .getRootDir ();
431+ Path activeClusterFile = new Path (rootDir , HConstants .ACTIVE_CLUSTER_SUFFIX_FILE_NAME );
432+
433+ try {
434+ if (newValue ) {
435+ // ENABLING READ-ONLY (false -> true), delete the active cluster file.
436+ LOG .debug ("Global read-only mode is being ENABLED. Deleting active cluster file: {}" ,
437+ activeClusterFile );
438+ try {
439+ fs .delete (activeClusterFile , false );
440+ LOG .info ("Successfully deleted active cluster file: {}" , activeClusterFile );
441+ } catch (IOException e ) {
442+ LOG .error (
443+ "Failed to delete active cluster file: {}. "
444+ + "Read-only flag will be updated, but file system state is inconsistent." ,
445+ activeClusterFile );
446+ }
447+ } else {
448+ // DISABLING READ-ONLY (true -> false), create the active cluster file id file
449+ int wait = mfs .getConfiguration ().getInt (HConstants .THREAD_WAKE_FREQUENCY , 10 * 1000 );
450+ FSUtils .setActiveClusterSuffix (fs , rootDir , mfs .getSuffixFileDataToWrite (), wait );
451+ }
452+ } catch (IOException e ) {
453+ // We still update the flag, but log that the operation failed.
454+ LOG .error ("Failed to perform file operation for read-only switch. "
455+ + "Flag will be updated, but file system state may be inconsistent." , e );
456+ }
457+ }
458+
414459 /* ---- ConfigurationObserver Overrides ---- */
415- @ Override
416460 public void onConfigurationChange (Configuration conf ) {
417461 boolean maybeUpdatedConfValue = conf .getBoolean (HConstants .HBASE_GLOBAL_READONLY_ENABLED_KEY ,
418462 HConstants .HBASE_GLOBAL_READONLY_ENABLED_DEFAULT );
419463 if (this .globalReadOnlyEnabled != maybeUpdatedConfValue ) {
464+ if (this .masterServices != null ) {
465+ manageActiveClusterIdFile (maybeUpdatedConfValue );
466+ } else {
467+ LOG .debug ("Global R/O flag changed, but not running on master" );
468+ }
420469 this .globalReadOnlyEnabled = maybeUpdatedConfValue ;
421- LOG .info ("Config {} has been dynamically changed to {}" ,
470+ LOG .info ("Config {} has been dynamically changed to {}. " ,
422471 HConstants .HBASE_GLOBAL_READONLY_ENABLED_KEY , this .globalReadOnlyEnabled );
423472 }
424473 }
0 commit comments