Skip to content

Commit

Permalink
HBASE-23055 Alter hbase:meta
Browse files Browse the repository at this point in the history
    Make it so hbase:meta can be altered. TableState for hbase:meta
    was hardcoded ENABLED. Make it dynamic. State is now kept in
    current active Master. It is transient so falls back to default
    if Master crashes. Add to registry a getMetaTableState
    which reads mirrored state from zookeeper (NOT from Master and
    defaults ENABLED if no implementation or error fetching state).
    hbase:meta schema will be bootstrapped from the filesystem.
    Changes to filesystem schema are atomic so we should be ok if
    Master fails mid-edit (TBD). Undoes a bunch of guards that
    prevented our being able to edit hbase:meta.

    TODO: Tests, more clarity around hbase:meta table state, and undoing
    references to hard-coded hbase:meta regioninfo.

    M hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java
     Throw illegal access exception if you try to use MetaTableAccessor
     getting state of the hbase:meta table.

    M hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java
     Add fetching of hbase:meta table state from registry. Adds cache of
     tablestates w/ a ttl of 1 second (adjustable).

    M hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
    M hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java
      Add querying registry for hbase:meta table state.

    M hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZKAsyncRegistry.java
      Add querying of mirrored table state for hbase:meta table.

    M hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZNodePaths.java
     Shutdown access.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/TableDescriptors.java
     Just cleanup.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java
     Add state holder for hbase:meta. Removed unused methods.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStateStore.java
     Shut down access.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DisableTableProcedure.java
     Allow hbase:meta to be disabled.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/EnableTableProcedure.java
     Allow hbase:meta to be enabled.

Signed-off-by: Bharath Vissapragada <[email protected]>
  • Loading branch information
saintstack committed Jan 10, 2020
1 parent f3bdb02 commit 9abdb7b
Show file tree
Hide file tree
Showing 34 changed files with 533 additions and 419 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.apache.hadoop.hbase;


import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -80,6 +81,7 @@
import org.slf4j.LoggerFactory;

import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
import org.apache.hbase.thirdparty.com.google.common.base.Throwables;

/**
Expand Down Expand Up @@ -304,11 +306,18 @@ public static HRegionLocation getRegionLocation(Connection connection, byte[] re
*/
public static HRegionLocation getRegionLocation(Connection connection, RegionInfo regionInfo)
throws IOException {
byte[] row = getMetaKeyForRegion(regionInfo);
Get get = new Get(row);
return getRegionLocation(getCatalogFamilyRow(connection, regionInfo),
regionInfo, regionInfo.getReplicaId());
}

/**
* @return Return the {@link HConstants#CATALOG_FAMILY} row from hbase:meta.
*/
public static Result getCatalogFamilyRow(Connection connection, RegionInfo ri)
throws IOException {
Get get = new Get(getMetaKeyForRegion(ri));
get.addFamily(HConstants.CATALOG_FAMILY);
Result r = get(getMetaHTable(connection), get);
return getRegionLocation(r, regionInfo, regionInfo.getReplicaId());
return get(getMetaHTable(connection), get);
}

/** Returns the row key to use for this regionInfo */
Expand Down Expand Up @@ -940,7 +949,8 @@ static int parseReplicaIdFromServerColumn(byte[] serverColumn) {
* @return A ServerName instance or null if necessary fields not found or empty.
*/
@Nullable
@InterfaceAudience.Private // for use by HMaster#getTableRegionRow which is used for testing only
// for use by HMaster#getTableRegionRow which is used for testing only
@InterfaceAudience.Private
public static ServerName getServerName(final Result r, final int replicaId) {
byte[] serverColumn = getServerColumn(replicaId);
Cell cell = r.getColumnLatestCell(getCatalogFamily(), serverColumn);
Expand Down Expand Up @@ -1079,9 +1089,8 @@ public static RegionInfo getRegionInfo(final Result r, byte [] qualifier) {
@Nullable
public static TableState getTableState(Connection conn, TableName tableName)
throws IOException {
if (tableName.equals(TableName.META_TABLE_NAME)) {
return new TableState(tableName, TableState.State.ENABLED);
}
Preconditions.checkArgument(!tableName.equals(TableName.META_TABLE_NAME),
"Not for hbase:meta state");
Table metaHTable = getMetaHTable(conn);
Get get = new Get(tableName.getName()).addColumn(getTableFamily(), getTableStateColumn());
Result result = metaHTable.get(get);
Expand All @@ -1108,7 +1117,8 @@ public static Map<TableName, TableState> getTableStates(Connection conn)
}

/**
* Updates state in META
* Updates state in META.
* Do not use. For internal use only.
* @param conn connection to use
* @param tableName table to look for
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.concurrent.CompletableFuture;
import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.yetus.audience.InterfaceAudience;

/**
Expand All @@ -29,12 +30,26 @@
*/
@InterfaceAudience.Private
interface AsyncRegistry extends Closeable {
/**
* A completed CompletableFuture to host default hbase:meta table state (ENABLED).
*/
TableState ENABLED_META_TABLE_STATE =
new TableState(TableName.META_TABLE_NAME, TableState.State.ENABLED);
CompletableFuture<TableState> COMPLETED_GET_META_TABLE_STATE =
CompletableFuture.completedFuture(ENABLED_META_TABLE_STATE);

/**
* Get the location of meta region.
*/
CompletableFuture<RegionLocations> getMetaRegionLocation();

/**
* The hbase:meta table state.
*/
default CompletableFuture<TableState> getMetaTableState() {
return COMPLETED_GET_META_TABLE_STATE;
}

/**
* Should only be called once.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil;
import org.apache.hadoop.hbase.security.access.UserPermission;

import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
import org.apache.hadoop.hbase.snapshot.SnapshotCreationException;
Expand Down Expand Up @@ -666,42 +667,55 @@ public CompletableFuture<Void> disableTable(TableName tableName) {
new DisableTableProcedureBiConsumer(tableName));
}

/**
* Utility for completing passed TableState {@link CompletableFuture} <code>future</code>
* using passed parameters.
*/
private static CompletableFuture<Boolean> completeCheckTableState(
CompletableFuture<Boolean> future, TableState tableState, Throwable error,
TableState.State targetState, TableName tableName) {
if (error != null) {
future.completeExceptionally(error);
} else {
if (tableState != null) {
future.complete(tableState.inStates(targetState));
} else {
future.completeExceptionally(new TableNotFoundException(tableName));
}
}
return future;
}

@Override
public CompletableFuture<Boolean> isTableEnabled(TableName tableName) {
if (TableName.isMetaTableName(tableName)) {
return CompletableFuture.completedFuture(true);
CompletableFuture<Boolean> future = new CompletableFuture<>();
addListener(this.connection.registry.getMetaTableState(), (tableState, error) -> {
completeCheckTableState(future, tableState, error, TableState.State.ENABLED, tableName);
});
return future;
}
CompletableFuture<Boolean> future = new CompletableFuture<>();
addListener(AsyncMetaTableAccessor.getTableState(metaTable, tableName), (state, error) -> {
if (error != null) {
future.completeExceptionally(error);
return;
}
if (state.isPresent()) {
future.complete(state.get().inStates(TableState.State.ENABLED));
} else {
future.completeExceptionally(new TableNotFoundException(tableName));
}
addListener(AsyncMetaTableAccessor.getTableState(metaTable, tableName), (tableState, error) -> {
completeCheckTableState(future, tableState.isPresent()? tableState.get(): null, error,
TableState.State.ENABLED, tableName);
});
return future;
}

@Override
public CompletableFuture<Boolean> isTableDisabled(TableName tableName) {
if (TableName.isMetaTableName(tableName)) {
return CompletableFuture.completedFuture(false);
CompletableFuture<Boolean> future = new CompletableFuture<>();
addListener(this.connection.registry.getMetaTableState(), (tableState, error) -> {
completeCheckTableState(future, tableState, error, TableState.State.DISABLED, tableName);
});
return future;
}
CompletableFuture<Boolean> future = new CompletableFuture<>();
addListener(AsyncMetaTableAccessor.getTableState(metaTable, tableName), (state, error) -> {
if (error != null) {
future.completeExceptionally(error);
return;
}
if (state.isPresent()) {
future.complete(state.get().inStates(TableState.State.DISABLED));
} else {
future.completeExceptionally(new TableNotFoundException(tableName));
}
addListener(AsyncMetaTableAccessor.getTableState(metaTable, tableName), (tableState, error) -> {
completeCheckTableState(future, tableState.isPresent()? tableState.get(): null, error,
TableState.State.DISABLED, tableName);
});
return future;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,26 @@
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.stream.Collectors;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterId;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.zookeeper.ReadOnlyZKClient;
import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos;

Expand All @@ -58,8 +62,19 @@ class ZKAsyncRegistry implements AsyncRegistry {

private final ZNodePaths znodePaths;

/**
* A znode maintained by MirroringTableStateManager.
* MirroringTableStateManager is deprecated to be removed in hbase3. It can also be disabled.
* Make sure it is enabled if you want to alter hbase:meta table in hbase2. In hbase3,
* TBD how metatable state will be hosted; likely on active hbase master.
*/
private final String znodeMirroredMetaTableState;


ZKAsyncRegistry(Configuration conf) {
this.znodePaths = new ZNodePaths(conf);
this.znodeMirroredMetaTableState =
ZNodePaths.joinZNode(this.znodePaths.tableZNode, TableName.META_TABLE_NAME.getNameAsString());
this.zk = new ReadOnlyZKClient(conf);
}

Expand Down Expand Up @@ -155,7 +170,8 @@ private void getMetaRegionLocation(CompletableFuture<RegionLocations> future,
}
Pair<RegionState.State, ServerName> stateAndServerName = getStateAndServerName(proto);
if (stateAndServerName.getFirst() != RegionState.State.OPEN) {
LOG.warn("Meta region is in state " + stateAndServerName.getFirst());
LOG.warn("hbase:meta region (replicaId={}) is in state {}", replicaId,
stateAndServerName.getFirst());
}
locs[DEFAULT_REPLICA_ID] = new HRegionLocation(
getRegionInfoForDefaultReplica(FIRST_META_REGIONINFO), stateAndServerName.getSecond());
Expand All @@ -170,7 +186,7 @@ private void getMetaRegionLocation(CompletableFuture<RegionLocations> future,
LOG.warn("Failed to fetch " + path, error);
locs[replicaId] = null;
} else if (proto == null) {
LOG.warn("Meta znode for replica " + replicaId + " is null");
LOG.warn("hbase:meta znode for replica " + replicaId + " is null");
locs[replicaId] = null;
} else {
Pair<RegionState.State, ServerName> stateAndServerName = getStateAndServerName(proto);
Expand All @@ -194,9 +210,8 @@ private void getMetaRegionLocation(CompletableFuture<RegionLocations> future,
public CompletableFuture<RegionLocations> getMetaRegionLocation() {
CompletableFuture<RegionLocations> future = new CompletableFuture<>();
addListener(
zk.list(znodePaths.baseZNode)
.thenApply(children -> children.stream()
.filter(c -> c.startsWith(znodePaths.metaZNodePrefix)).collect(Collectors.toList())),
zk.list(znodePaths.baseZNode).thenApply(children -> children.stream().
filter(c -> znodePaths.isMetaZNodePrefix(c)).collect(Collectors.toList())),
(metaReplicaZNodes, error) -> {
if (error != null) {
future.completeExceptionally(error);
Expand Down Expand Up @@ -229,6 +244,43 @@ public CompletableFuture<ServerName> getMasterAddress() {
});
}

@Override
public CompletableFuture<TableState> getMetaTableState() {
return getAndConvert(this.znodeMirroredMetaTableState, ZKAsyncRegistry::getTableState).
thenApply(state -> {
return state == null || state.equals(ENABLED_META_TABLE_STATE.getState())?
ENABLED_META_TABLE_STATE: new TableState(TableName.META_TABLE_NAME, state);
}).exceptionally(e -> {
// Handle this case where no znode... Return default ENABLED in this case:
// Caused by: java.io.IOException: java.util.concurrent.ExecutionException:
// java.util.concurrent.ExecutionException:
// org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for
// /hbase/table/hbase:meta
// If not case of above, then rethrow but may need to wrap. See
// https://stackoverflow.com/questions/55453961/
// completablefutureexceptionally-rethrow-checked-exception
if (e.getCause() instanceof KeeperException.NoNodeException) {
return ENABLED_META_TABLE_STATE;
}
throw e instanceof CompletionException? (CompletionException)e:
new CompletionException(e);
});
}

/**
* Get tablestate from data byte array found in the mirroring znode of table state.
*/
private static TableState.State getTableState(byte[] data) throws DeserializationException {
if (data == null || data.length == 0) {
return null;
}
try {
return ProtobufUtil.toTableState(ProtobufUtil.toTableState(removeMetaData(data)));
} catch (IOException ioe) {
throw new DeserializationException(ioe);
}
}

@Override
public void close() {
zk.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import org.apache.hadoop.hbase.client.SnapshotType;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.client.TableState;
import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
import org.apache.hadoop.hbase.client.security.SecurityCapability;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
Expand Down Expand Up @@ -3368,4 +3369,46 @@ public static RegionStatesCount toTableRegionStatesCount(
.build();
}


/**
* Parses pb TableState from <code>data</code>
*/
public static ZooKeeperProtos.DeprecatedTableState.State toTableState(byte [] data)
throws DeserializationException, IOException {
if (data == null || data.length <= 0) {
return null;
}
ProtobufUtil.expectPBMagicPrefix(data);
ZooKeeperProtos.DeprecatedTableState.Builder builder =
ZooKeeperProtos.DeprecatedTableState.newBuilder();
int magicLen = ProtobufUtil.lengthOfPBMagic();
ProtobufUtil.mergeFrom(builder, data, magicLen, data.length - magicLen);
return builder.getState();
}


/**
* @return Convert from pb TableState to pojo TableState.
*/
public static TableState.State toTableState(ZooKeeperProtos.DeprecatedTableState.State state) {
TableState.State newState = TableState.State.ENABLED;
if (state != null) {
switch (state) {
case ENABLED:
newState = TableState.State.ENABLED;
break;
case DISABLED:
newState = TableState.State.DISABLED;
break;
case DISABLING:
newState = TableState.State.DISABLING;
break;
case ENABLING:
newState = TableState.State.ENABLING;
break;
default:
}
}
return newState;
}
}
Loading

0 comments on commit 9abdb7b

Please sign in to comment.