Skip to content
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

HBASE-28120 Switch that allows avoiding reopening all regions when altering table #5482

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1535,7 +1535,16 @@ default void modifyTable(TableName tableName, TableDescriptor td) throws IOExcep
throw new IllegalArgumentException("the specified table name '" + tableName
+ "' doesn't match with the HTD one: " + td.getTableName());
}
modifyTable(td);
modifyTable(td, true);
}

/**
* Modify an existing table, more IRB friendly version.
* @param td modified description of the table
* @throws IOException if a remote or network exception occurs
*/
default void modifyTable(TableDescriptor td, boolean reopenRegions) throws IOException {
get(modifyTableAsync(td, reopenRegions), getSyncWaitTimeout(), TimeUnit.MILLISECONDS);
}

/**
Expand All @@ -1544,7 +1553,7 @@ default void modifyTable(TableName tableName, TableDescriptor td) throws IOExcep
* @throws IOException if a remote or network exception occurs
*/
default void modifyTable(TableDescriptor td) throws IOException {
get(modifyTableAsync(td), getSyncWaitTimeout(), TimeUnit.MILLISECONDS);
get(modifyTableAsync(td, true), getSyncWaitTimeout(), TimeUnit.MILLISECONDS);
}

/**
Expand All @@ -1559,7 +1568,7 @@ default void modifyTable(TableDescriptor td) throws IOException {
* @return the result of the async modify. You can use Future.get(long, TimeUnit) to wait on the
* operation to complete
* @deprecated since 2.0 version and will be removed in 3.0 version. use
* {@link #modifyTableAsync(TableDescriptor)}
* {@link #modifyTableAsync(TableDescriptor, boolean)}
*/
@Deprecated
default Future<Void> modifyTableAsync(TableName tableName, TableDescriptor td)
Expand All @@ -1568,7 +1577,7 @@ default Future<Void> modifyTableAsync(TableName tableName, TableDescriptor td)
throw new IllegalArgumentException("the specified table name '" + tableName
+ "' doesn't match with the HTD one: " + td.getTableName());
}
return modifyTableAsync(td);
return modifyTableAsync(td, true);
}

/**
Expand All @@ -1582,7 +1591,7 @@ default Future<Void> modifyTableAsync(TableName tableName, TableDescriptor td)
* @return the result of the async modify. You can use Future.get(long, TimeUnit) to wait on the
* operation to complete
*/
Future<Void> modifyTableAsync(TableDescriptor td) throws IOException;
Future<Void> modifyTableAsync(TableDescriptor td, boolean reopenRegions) throws IOException;

/**
* Change the store file tracker of the given table.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,20 @@ CompletableFuture<Void> createTable(TableDescriptor desc, byte[] startKey, byte[
* Modify an existing table, more IRB friendly version.
* @param desc modified description of the table
*/
CompletableFuture<Void> modifyTable(TableDescriptor desc);
default CompletableFuture<Void> modifyTable(TableDescriptor desc) {
return modifyTable(desc, true);
}

/**
* Modify an existing table, more IRB friendly version.
* @param desc description of the table
* @param reopenRegions By default, 'modifyTable' reopens all regions, potentially causing a RIT
* (Region In Transition) storm in large tables. If set to 'false', regions
* will remain unaware of the modification until they are individually
* reopened. Please note that this may temporarily result in configuration
* inconsistencies among regions.
*/
CompletableFuture<Void> modifyTable(TableDescriptor desc, boolean reopenRegions);

/**
* Change the store file tracker of the given table.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,12 @@ public CompletableFuture<Void> createTable(TableDescriptor desc, byte[][] splitK

@Override
public CompletableFuture<Void> modifyTable(TableDescriptor desc) {
return wrap(rawAdmin.modifyTable(desc));
return modifyTable(desc, true);
}

@Override
public CompletableFuture<Void> modifyTable(TableDescriptor desc, boolean reopenRegions) {
return wrap(rawAdmin.modifyTable(desc, reopenRegions));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,8 @@ public TableDescriptor getDescriptor(TableName tableName)
}

@Override
public Future<Void> modifyTableAsync(TableDescriptor td) throws IOException {
public Future<Void> modifyTableAsync(TableDescriptor td, boolean reopenRegions)
throws IOException {
ModifyTableResponse response = executeCallable(
new MasterCallable<ModifyTableResponse>(getConnection(), getRpcControllerFactory()) {
long nonceGroup = ng.getNonceGroup();
Expand All @@ -401,8 +402,8 @@ public Future<Void> modifyTableAsync(TableDescriptor td) throws IOException {
@Override
protected ModifyTableResponse rpcCall() throws Exception {
setPriority(td.getTableName());
ModifyTableRequest request =
RequestConverter.buildModifyTableRequest(td.getTableName(), td, nonceGroup, nonce);
ModifyTableRequest request = RequestConverter.buildModifyTableRequest(td.getTableName(),
td, nonceGroup, nonce, reopenRegions);
return master.modifyTable(getRpcController(), request);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,9 +659,14 @@ private CompletableFuture<Void> createTable(TableName tableName, CreateTableRequ

@Override
public CompletableFuture<Void> modifyTable(TableDescriptor desc) {
return modifyTable(desc, true);
}

public CompletableFuture<Void> modifyTable(TableDescriptor desc, boolean reopenRegions) {
// TODO fill the request with reopenRegions
return this.<ModifyTableRequest, ModifyTableResponse> procedureCall(desc.getTableName(),
RequestConverter.buildModifyTableRequest(desc.getTableName(), desc, ng.getNonceGroup(),
ng.newNonce()),
ng.newNonce(), reopenRegions),
(s, c, req, done) -> s.modifyTable(c, req, done), (resp) -> resp.getProcId(),
new ModifyTableProcedureBiConsumer(this, desc.getTableName()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1295,12 +1295,14 @@ public static CreateTableRequest buildCreateTableRequest(final TableDescriptor t
* @return a ModifyTableRequest
*/
public static ModifyTableRequest buildModifyTableRequest(final TableName tableName,
final TableDescriptor tableDesc, final long nonceGroup, final long nonce) {
final TableDescriptor tableDesc, final long nonceGroup, final long nonce,
boolean reopenRegions) {
ModifyTableRequest.Builder builder = ModifyTableRequest.newBuilder();
builder.setTableName(ProtobufUtil.toProtoTableName(tableName));
builder.setTableSchema(ProtobufUtil.toTableSchema(tableDesc));
builder.setNonceGroup(nonceGroup);
builder.setNonce(nonce);
builder.setReopenRegions(reopenRegions);
return builder.build();
}

Expand Down
1 change: 1 addition & 0 deletions hbase-protocol-shaded/src/main/protobuf/Master.proto
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ message ModifyTableRequest {
required TableSchema table_schema = 2;
optional uint64 nonce_group = 3 [default = 0];
optional uint64 nonce = 4 [default = 0];
optional bool reopen_regions = 5 [default = true];
}

message ModifyTableResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ message ModifyTableStateData {
required TableSchema modified_table_schema = 3;
required bool delete_column_family_in_modify = 4;
optional bool should_check_descriptor = 5;
optional bool reopen_regions = 6;
}

enum TruncateTableState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2689,6 +2689,13 @@ protected String getDescription() {
private long modifyTable(final TableName tableName,
final TableDescriptorGetter newDescriptorGetter, final long nonceGroup, final long nonce,
final boolean shouldCheckDescriptor) throws IOException {
return modifyTable(tableName, newDescriptorGetter, nonceGroup, nonce, shouldCheckDescriptor,
true);
}

private long modifyTable(final TableName tableName,
final TableDescriptorGetter newDescriptorGetter, final long nonceGroup, final long nonce,
final boolean shouldCheckDescriptor, final boolean reopenRegions) throws IOException {
return MasterProcedureUtil
.submitProcedure(new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
@Override
Expand All @@ -2707,7 +2714,7 @@ protected void run() throws IOException {
// checks. This will block only the beginning of the procedure. See HBASE-19953.
ProcedurePrepareLatch latch = ProcedurePrepareLatch.createBlockingLatch();
submitProcedure(new ModifyTableProcedure(procedureExecutor.getEnvironment(),
newDescriptor, latch, oldDescriptor, shouldCheckDescriptor));
newDescriptor, latch, oldDescriptor, shouldCheckDescriptor, reopenRegions));
latch.await();

getMaster().getMasterCoprocessorHost().postModifyTable(tableName, oldDescriptor,
Expand All @@ -2724,14 +2731,14 @@ protected String getDescription() {

@Override
public long modifyTable(final TableName tableName, final TableDescriptor newDescriptor,
final long nonceGroup, final long nonce) throws IOException {
final long nonceGroup, final long nonce, final boolean reopenRegions) throws IOException {
checkInitialized();
return modifyTable(tableName, new TableDescriptorGetter() {
@Override
public TableDescriptor get() throws IOException {
return newDescriptor;
}
}, nonceGroup, nonce, false);
}, nonceGroup, nonce, false, reopenRegions);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,8 @@ public ModifyTableResponse modifyTable(RpcController controller, ModifyTableRequ
throws ServiceException {
try {
long procId = master.modifyTable(ProtobufUtil.toTableName(req.getTableName()),
ProtobufUtil.toTableDescriptor(req.getTableSchema()), req.getNonceGroup(), req.getNonce());
ProtobufUtil.toTableDescriptor(req.getTableSchema()), req.getNonceGroup(), req.getNonce(),
req.getReopenRegions());
return ModifyTableResponse.newBuilder().setProcId(procId).build();
} catch (IOException ioe) {
throw new ServiceException(ioe);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,19 @@ public long truncateTable(final TableName tableName, final boolean preserveSplit
* @param tableName The table name
* @param descriptor The updated table descriptor
*/
default long modifyTable(final TableName tableName, final TableDescriptor descriptor,
final long nonceGroup, final long nonce) throws IOException {
return modifyTable(tableName, descriptor, nonceGroup, nonce, true);
}

/**
* Modify the descriptor of an existing table
* @param tableName The table name
* @param descriptor The updated table descriptor
* @param reopenRegions Whether to reopen regions after modifying the table descriptor
*/
long modifyTable(final TableName tableName, final TableDescriptor descriptor,
final long nonceGroup, final long nonce) throws IOException;
final long nonceGroup, final long nonce, final boolean reopenRegions) throws IOException;

/**
* Modify the store file tracker of an existing table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
Expand All @@ -33,11 +34,13 @@
import org.apache.hadoop.hbase.client.RegionInfo;
import org.apache.hadoop.hbase.client.RegionReplicaUtil;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
import org.apache.hadoop.hbase.master.zksyncer.MetaLocationSyncer;
import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerValidationUtils;
import org.apache.hadoop.hbase.replication.ReplicationException;
import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
import org.apache.yetus.audience.InterfaceAudience;
Expand All @@ -56,6 +59,7 @@ public class ModifyTableProcedure extends AbstractStateMachineTableProcedure<Mod
private TableDescriptor modifiedTableDescriptor;
private boolean deleteColumnFamilyInModify;
private boolean shouldCheckDescriptor;
private boolean reopenRegions;
/**
* List of column families that cannot be deleted from the hbase:meta table. They are critical to
* cluster operation. This is a bit of an odd place to keep this list but then this is the tooling
Expand Down Expand Up @@ -84,7 +88,15 @@ public ModifyTableProcedure(final MasterProcedureEnv env,
final TableDescriptor newTableDescriptor, final ProcedurePrepareLatch latch,
final TableDescriptor oldTableDescriptor, final boolean shouldCheckDescriptor)
throws HBaseIOException {
this(env, newTableDescriptor, latch, oldTableDescriptor, shouldCheckDescriptor, true);
}

public ModifyTableProcedure(final MasterProcedureEnv env,
final TableDescriptor newTableDescriptor, final ProcedurePrepareLatch latch,
final TableDescriptor oldTableDescriptor, final boolean shouldCheckDescriptor,
final boolean reopenRegions) throws HBaseIOException {
super(env, latch);
this.reopenRegions = reopenRegions;
initialize(oldTableDescriptor, shouldCheckDescriptor);
this.modifiedTableDescriptor = newTableDescriptor;
preflightChecks(env, null/* No table checks; if changing peers, table can be online */);
Expand All @@ -104,6 +116,55 @@ protected void preflightChecks(MasterProcedureEnv env, Boolean enabled) throws H
}
}
}
if (!reopenRegions) {
if (this.unmodifiedTableDescriptor == null) {
throw new HBaseIOException(
"unmodifiedTableDescriptor cannot be null when this table modification won't reopen regions");
}
if (
0 != this.unmodifiedTableDescriptor.getTableName()
.compareTo(this.modifiedTableDescriptor.getTableName())
) {
throw new HBaseIOException(
"Cannot change the table name when this modification won't " + "reopen regions.");
}
if (
this.unmodifiedTableDescriptor.getColumnFamilyCount()
!= this.modifiedTableDescriptor.getColumnFamilyCount()
) {
throw new HBaseIOException(
"Cannot add or remove column families when this modification " + "won't reopen regions.");
}
if (
this.unmodifiedTableDescriptor.getCoprocessorDescriptors().hashCode()
!= this.modifiedTableDescriptor.getCoprocessorDescriptors().hashCode()
) {
throw new HBaseIOException(
"Can not modify Coprocessor when table modification won't reopen regions");
}
final Set<String> s = new HashSet<>(Arrays.asList(TableDescriptorBuilder.REGION_REPLICATION,
TableDescriptorBuilder.REGION_MEMSTORE_REPLICATION, RSGroupInfo.TABLE_DESC_PROP_GROUP));
for (String k : s) {
if (
isTablePropertyModified(this.unmodifiedTableDescriptor, this.modifiedTableDescriptor, k)
) {
throw new HBaseIOException(
"Can not modify " + k + " of a table when modification won't reopen regions");
}
}
}
}

private boolean isTablePropertyModified(TableDescriptor oldDescriptor,
TableDescriptor newDescriptor, String key) {
String oldV = oldDescriptor.getValue(key);
String newV = newDescriptor.getValue(key);
if (oldV == null && newV == null) {
return false;
} else if (oldV != null && newV != null && oldV.equals(newV)) {
return false;
}
return true;
}

private void initialize(final TableDescriptor unmodifiedTableDescriptor,
Expand All @@ -124,8 +185,11 @@ protected Flow executeFromState(final MasterProcedureEnv env, final ModifyTableS
setNextState(ModifyTableState.MODIFY_TABLE_PRE_OPERATION);
break;
case MODIFY_TABLE_PRE_OPERATION:
preModify(env, state);
setNextState(ModifyTableState.MODIFY_TABLE_CLOSE_EXCESS_REPLICAS);
if (reopenRegions) {
setNextState(ModifyTableState.MODIFY_TABLE_CLOSE_EXCESS_REPLICAS);
} else {
setNextState(ModifyTableState.MODIFY_TABLE_UPDATE_TABLE_DESCRIPTOR);
}
break;
case MODIFY_TABLE_CLOSE_EXCESS_REPLICAS:
if (isTableEnabled(env)) {
Expand All @@ -135,15 +199,23 @@ protected Flow executeFromState(final MasterProcedureEnv env, final ModifyTableS
break;
case MODIFY_TABLE_UPDATE_TABLE_DESCRIPTOR:
updateTableDescriptor(env);
setNextState(ModifyTableState.MODIFY_TABLE_REMOVE_REPLICA_COLUMN);
if (reopenRegions) {
setNextState(ModifyTableState.MODIFY_TABLE_REMOVE_REPLICA_COLUMN);
} else {
setNextState(ModifyTableState.MODIFY_TABLE_POST_OPERATION);
}
break;
case MODIFY_TABLE_REMOVE_REPLICA_COLUMN:
removeReplicaColumnsIfNeeded(env);
setNextState(ModifyTableState.MODIFY_TABLE_POST_OPERATION);
break;
case MODIFY_TABLE_POST_OPERATION:
postModify(env, state);
setNextState(ModifyTableState.MODIFY_TABLE_REOPEN_ALL_REGIONS);
if (reopenRegions) {
setNextState(ModifyTableState.MODIFY_TABLE_REOPEN_ALL_REGIONS);
} else {
return Flow.NO_MORE_STATE;
}
break;
case MODIFY_TABLE_REOPEN_ALL_REGIONS:
if (isTableEnabled(env)) {
Expand Down Expand Up @@ -238,7 +310,7 @@ protected void serializeStateData(ProcedureStateSerializer serializer) throws IO
.setUserInfo(MasterProcedureUtil.toProtoUserInfo(getUser()))
.setModifiedTableSchema(ProtobufUtil.toTableSchema(modifiedTableDescriptor))
.setDeleteColumnFamilyInModify(deleteColumnFamilyInModify)
.setShouldCheckDescriptor(shouldCheckDescriptor);
.setShouldCheckDescriptor(shouldCheckDescriptor).setReopenRegions(reopenRegions);

if (unmodifiedTableDescriptor != null) {
modifyTableMsg
Expand All @@ -260,6 +332,7 @@ protected void deserializeStateData(ProcedureStateSerializer serializer) throws
deleteColumnFamilyInModify = modifyTableMsg.getDeleteColumnFamilyInModify();
shouldCheckDescriptor =
modifyTableMsg.hasShouldCheckDescriptor() ? modifyTableMsg.getShouldCheckDescriptor() : false;
reopenRegions = modifyTableMsg.hasReopenRegions() ? modifyTableMsg.getReopenRegions() : true;

if (modifyTableMsg.hasUnmodifiedTableSchema()) {
unmodifiedTableDescriptor =
Expand Down
Loading