Skip to content

Commit f45bb13

Browse files
authored
HBASE-29642 Active cluster file is not being updated after promoting … (#7437)
* HBASE-29642 Active cluster file is not being updated after promoting a new active cluster * HBASE-29642 Active cluster file is not being updated after promoting a new active cluster * HBASE-29642 Active cluster file is not being updated after promoting a new active cluster
1 parent 459db1d commit f45bb13

File tree

4 files changed

+87
-3
lines changed

4 files changed

+87
-3
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterCoprocessorEnvironment.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
2424
import org.apache.hadoop.hbase.ServerName;
2525
import org.apache.hadoop.hbase.client.Connection;
26+
import org.apache.hadoop.hbase.master.MasterServices;
2627
import org.apache.hadoop.hbase.metrics.MetricRegistry;
2728
import org.apache.yetus.audience.InterfaceAudience;
2829
import org.apache.yetus.audience.InterfaceStability;
@@ -88,4 +89,6 @@ public interface MasterCoprocessorEnvironment extends CoprocessorEnvironment<Mas
8889
* @return A MetricRegistry for the coprocessor class to track and export metrics.
8990
*/
9091
MetricRegistry getMetricRegistryForMaster();
92+
93+
MasterServices getMasterServices();
9194
}

hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ public MetricRegistry getMetricRegistryForMaster() {
111111
return metricRegistry;
112112
}
113113

114+
@Override
115+
public MasterServices getMasterServices() {
116+
return services;
117+
}
118+
114119
@Override
115120
public void shutdown() {
116121
super.shutdown();

hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ReadOnlyController.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.List;
2222
import java.util.Optional;
2323
import org.apache.hadoop.conf.Configuration;
24+
import org.apache.hadoop.fs.FileSystem;
25+
import org.apache.hadoop.fs.Path;
2426
import org.apache.hadoop.hbase.CompareOperator;
2527
import org.apache.hadoop.hbase.CoprocessorEnvironment;
2628
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
@@ -51,11 +53,14 @@
5153
import org.apache.hadoop.hbase.coprocessor.RegionServerObserver;
5254
import org.apache.hadoop.hbase.filter.ByteArrayComparable;
5355
import org.apache.hadoop.hbase.filter.Filter;
56+
import org.apache.hadoop.hbase.master.MasterFileSystem;
57+
import org.apache.hadoop.hbase.master.MasterServices;
5458
import org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker;
5559
import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
5660
import org.apache.hadoop.hbase.regionserver.Store;
5761
import org.apache.hadoop.hbase.regionserver.StoreFile;
5862
import org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTracker;
63+
import org.apache.hadoop.hbase.util.FSUtils;
5964
import org.apache.hadoop.hbase.util.Pair;
6065
import org.apache.hadoop.hbase.wal.WALEdit;
6166
import 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
}

hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestReadOnlyController.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
package org.apache.hadoop.hbase.security.access;
1919

2020
import static org.apache.hadoop.hbase.HConstants.HBASE_CLIENT_RETRIES_NUMBER;
21+
import static org.junit.Assert.assertFalse;
22+
import static org.junit.Assert.assertTrue;
2123

2224
import java.io.IOException;
2325
import java.util.ArrayList;
2426
import java.util.List;
2527
import org.apache.hadoop.conf.Configuration;
28+
import org.apache.hadoop.fs.FileSystem;
29+
import org.apache.hadoop.fs.Path;
2630
import org.apache.hadoop.hbase.HBaseClassTestRule;
2731
import org.apache.hadoop.hbase.HBaseTestingUtil;
2832
import org.apache.hadoop.hbase.HConstants;
@@ -36,6 +40,7 @@
3640
import org.apache.hadoop.hbase.client.Table;
3741
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
3842
import org.apache.hadoop.hbase.master.HMaster;
43+
import org.apache.hadoop.hbase.master.MasterFileSystem;
3944
import org.apache.hadoop.hbase.regionserver.HRegionServer;
4045
import org.apache.hadoop.hbase.testclassification.LargeTests;
4146
import org.apache.hadoop.hbase.testclassification.SecurityTests;
@@ -154,6 +159,14 @@ private static void notifyObservers() {
154159
hRegionServer.getConfigurationManager().notifyAllObservers(conf);
155160
}
156161

162+
private static boolean isActiveClusterIdFileExists() throws IOException {
163+
MasterFileSystem mfs = hMaster.getMasterFileSystem();
164+
Path rootDir = mfs.getRootDir();
165+
FileSystem fs = mfs.getFileSystem();
166+
Path activeClusterFile = new Path(rootDir, HConstants.ACTIVE_CLUSTER_SUFFIX_FILE_NAME);
167+
return fs.exists(activeClusterFile);
168+
}
169+
157170
// The test case for successfully creating a table with Read-Only mode disabled happens when
158171
// setting up the test class, so we only need a test function for a failed table creation.
159172
@Test
@@ -221,4 +234,18 @@ public void testCannotBatchPutWithReadOnlyEnabled() throws IOException, Interrup
221234
// This should throw the IOException
222235
testTable.batch(actions, null);
223236
}
237+
238+
@Test
239+
public void testActiveClusterIdFileCreationWhenReadOnlyDisabled()
240+
throws IOException, InterruptedException {
241+
disableReadOnlyMode();
242+
assertTrue(isActiveClusterIdFileExists());
243+
}
244+
245+
@Test
246+
public void testActiveClusterIdFileDeletionWhenReadOnlyEnabled()
247+
throws IOException, InterruptedException {
248+
enableReadOnlyMode();
249+
assertFalse(isActiveClusterIdFileExists());
250+
}
224251
}

0 commit comments

Comments
 (0)