-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-30220: A replica cluster can have read-only mode disabled even when another active cluster already exists #8377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.hadoop.hbase; | ||
|
|
||
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| /** | ||
| * Thrown when a replica cluster attempts to disable read-only mode while another active cluster | ||
| * already exists on the same storage location. | ||
| */ | ||
| @InterfaceAudience.Public | ||
| public class ReadOnlyTransitionException extends DoNotRetryIOException { | ||
|
|
||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| public ReadOnlyTransitionException() { | ||
| super(); | ||
| } | ||
|
|
||
| /** | ||
| * @param message the message for this exception | ||
| */ | ||
| public ReadOnlyTransitionException(String message) { | ||
| super(message); | ||
| } | ||
|
|
||
| /** | ||
| * @param message the message for this exception | ||
| * @param throwable the {@link Throwable} to use for this exception | ||
| */ | ||
| public ReadOnlyTransitionException(String message, Throwable throwable) { | ||
| super(message, throwable); | ||
| } | ||
|
|
||
| /** | ||
| * @param throwable the {@link Throwable} to use for this exception | ||
| */ | ||
| public ReadOnlyTransitionException(Throwable throwable) { | ||
| super(throwable); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,6 +73,7 @@ | |
| import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent; | ||
| import org.apache.hadoop.hbase.util.Addressing; | ||
| import org.apache.hadoop.hbase.util.CommonFSUtils; | ||
| import org.apache.hadoop.hbase.util.ConfigurationUtil; | ||
| import org.apache.hadoop.hbase.util.DNS; | ||
| import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; | ||
| import org.apache.hadoop.hbase.util.FSTableDescriptors; | ||
|
|
@@ -102,15 +103,19 @@ public abstract class HBaseServerBase<R extends HBaseRpcServicesBase<?>> extends | |
| protected final AtomicBoolean abortRequested = new AtomicBoolean(false); | ||
|
|
||
| // Set when a report to the master comes back with a message asking us to | ||
| // shutdown. Also set by call to stop when debugging or running unit tests | ||
| // shut down. Also set by call to stop when debugging or running unit tests | ||
| // of HRegionServer in isolation. | ||
| protected volatile boolean stopped = false; | ||
|
|
||
| // Flag set when a read-only to read-write transition is blocked because another active cluster | ||
| // exists | ||
| protected volatile boolean readOnlyTransitionBlocked = false; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not strictly necessary here, but I prefer to use |
||
|
|
||
| // Only for testing | ||
| private boolean isShutdownHookInstalled = false; | ||
|
|
||
| /** | ||
| * This servers startcode. | ||
| * This server's startcode. | ||
| */ | ||
| protected final long startcode; | ||
|
|
||
|
|
@@ -639,11 +644,30 @@ public void updateConfiguration() throws IOException { | |
| LOG.info("Reloading the configuration from disk."); | ||
| // Reload the configuration from disk. | ||
| preUpdateConfiguration(); | ||
| this.readOnlyTransitionBlocked = false; | ||
| conf.reloadConfiguration(); | ||
| configurationManager.notifyAllObservers(conf); | ||
| this.checkForBlockedReadOnlyTransition(); | ||
| postUpdateConfiguration(); | ||
| } | ||
|
|
||
| protected Configuration blockReadOnlyTransition(Configuration updatedConf) { | ||
| LOG.error( | ||
| "Cannot disable read-only mode. The {} file contains a different cluster ID, which means " | ||
| + "that cluster is already the active cluster. Reverting {} to true", | ||
| HConstants.ACTIVE_CLUSTER_SUFFIX_FILE_NAME, HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY); | ||
| this.readOnlyTransitionBlocked = true; | ||
| return ConfigurationUtil.getReadOnlyEnabledConfigurationCopy(updatedConf); | ||
| } | ||
|
|
||
| protected void checkForBlockedReadOnlyTransition() throws ReadOnlyTransitionException { | ||
| if (this.readOnlyTransitionBlocked) { | ||
| throw new ReadOnlyTransitionException( | ||
| "Cannot disable read-only mode because another active cluster already exists on this " | ||
| + "storage location. The read-only coprocessors have not been removed."); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public KeyManagementService getKeyManagementService() { | ||
| return this; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -116,8 +116,22 @@ public static List<Map.Entry<String, String>> getKeyValues(Configuration conf, S | |
| return rtn; | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the provided Configuration object has | ||
| * {@link HConstants#HBASE_GLOBAL_READONLY_ENABLED_KEY} set to true; false otherwise. | ||
| */ | ||
| public static boolean isReadOnlyModeEnabledInConf(Configuration conf) { | ||
| return conf.getBoolean(HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY, | ||
| HConstants.HBASE_GLOBAL_READONLY_ENABLED_DEFAULT); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a copied version of the provided Configuration object that has | ||
| * {@link HConstants#HBASE_GLOBAL_READONLY_ENABLED_KEY} set to true. | ||
| */ | ||
| public static Configuration getReadOnlyEnabledConfigurationCopy(Configuration conf) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think setReadOnlyEnabledConfigurationCopy would be a better name for this method. |
||
| Configuration readOnlyConf = new Configuration(conf); | ||
| readOnlyConf.setBoolean(HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY, true); | ||
| return readOnlyConf; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Could encapsulate a String field identifying the current active cluster's ID and emitted to log when the exception is converted to string.