HBASE-26286: Add support for specifying store file tracker when restoring or cloning snapshot
Closes #3851 Signed-off-by: Duo Zhang <zhangduo@apache.org> Signed-off-by: Josh Elser <elserj@apache.org>
This commit is contained in:
parent
d00b5faade
commit
771e552cf4
|
@ -69,6 +69,7 @@ import org.apache.hadoop.hbase.util.Pair;
|
|||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
||||
import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableList;
|
||||
import org.apache.yetus.audience.InterfaceStability;
|
||||
|
||||
/**
|
||||
* The administrative API for HBase. Obtain an instance from {@link Connection#getAdmin()} and
|
||||
|
@ -1620,7 +1621,7 @@ public interface Admin extends Abortable, Closeable {
|
|||
* @throws IllegalArgumentException if the restore request is formatted incorrectly
|
||||
*/
|
||||
void restoreSnapshot(String snapshotName, boolean takeFailSafeSnapshot, boolean restoreAcl)
|
||||
throws IOException, RestoreSnapshotException;
|
||||
throws IOException, RestoreSnapshotException;
|
||||
|
||||
/**
|
||||
* Create a new table by cloning the snapshot content.
|
||||
|
@ -1633,7 +1634,25 @@ public interface Admin extends Abortable, Closeable {
|
|||
*/
|
||||
default void cloneSnapshot(String snapshotName, TableName tableName)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
cloneSnapshot(snapshotName, tableName, false);
|
||||
cloneSnapshot(snapshotName, tableName, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new table by cloning the snapshot content.
|
||||
* @param snapshotName name of the snapshot to be cloned
|
||||
* @param tableName name of the table where the snapshot will be restored
|
||||
* @param restoreAcl <code>true</code> to clone acl into newly created table
|
||||
* @param customSFT specify the StoreFileTracker used for the table
|
||||
* @throws IOException if a remote or network exception occurs
|
||||
* @throws TableExistsException if table to be created already exists
|
||||
* @throws RestoreSnapshotException if snapshot failed to be cloned
|
||||
* @throws IllegalArgumentException if the specified table has not a valid name
|
||||
*/
|
||||
default void cloneSnapshot(String snapshotName, TableName tableName, boolean restoreAcl,
|
||||
String customSFT)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
get(cloneSnapshotAsync(snapshotName, tableName, restoreAcl, customSFT), getSyncWaitTimeout(),
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1680,8 +1699,25 @@ public interface Admin extends Abortable, Closeable {
|
|||
* @throws RestoreSnapshotException if snapshot failed to be cloned
|
||||
* @throws IllegalArgumentException if the specified table has not a valid name
|
||||
*/
|
||||
Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName, boolean restoreAcl)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException;
|
||||
default Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
return cloneSnapshotAsync(snapshotName, tableName, restoreAcl, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new table by cloning the snapshot content.
|
||||
* @param snapshotName name of the snapshot to be cloned
|
||||
* @param tableName name of the table where the snapshot will be restored
|
||||
* @param restoreAcl <code>true</code> to clone acl into newly created table
|
||||
* @param customSFT specify the StroreFileTracker used for the table
|
||||
* @throws IOException if a remote or network exception occurs
|
||||
* @throws TableExistsException if table to be created already exists
|
||||
* @throws RestoreSnapshotException if snapshot failed to be cloned
|
||||
* @throws IllegalArgumentException if the specified table has not a valid name
|
||||
*/
|
||||
Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName, boolean restoreAcl,
|
||||
String customSFT) throws IOException, TableExistsException, RestoreSnapshotException;
|
||||
|
||||
/**
|
||||
* Execute a distributed procedure on a cluster.
|
||||
|
|
|
@ -644,14 +644,15 @@ class AdminOverAsyncAdmin implements Admin {
|
|||
|
||||
@Override
|
||||
public void restoreSnapshot(String snapshotName, boolean takeFailSafeSnapshot, boolean restoreAcl)
|
||||
throws IOException, RestoreSnapshotException {
|
||||
throws IOException, RestoreSnapshotException {
|
||||
get(admin.restoreSnapshot(snapshotName, takeFailSafeSnapshot, restoreAcl));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl) throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
return admin.cloneSnapshot(snapshotName, tableName, restoreAcl);
|
||||
boolean restoreAcl, String customSFT)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
return admin.cloneSnapshot(snapshotName, tableName, restoreAcl, customSFT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -895,8 +895,20 @@ public interface AsyncAdmin {
|
|||
* @param tableName name of the table where the snapshot will be restored
|
||||
* @param restoreAcl <code>true</code> to restore acl of snapshot
|
||||
*/
|
||||
default CompletableFuture<Void> cloneSnapshot(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl) {
|
||||
return cloneSnapshot(snapshotName, tableName, restoreAcl, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new table by cloning the snapshot content.
|
||||
* @param snapshotName name of the snapshot to be cloned
|
||||
* @param tableName name of the table where the snapshot will be restored
|
||||
* @param restoreAcl <code>true</code> to restore acl of snapshot
|
||||
* @param customSFT specify the StroreFileTracker used for the table
|
||||
*/
|
||||
CompletableFuture<Void> cloneSnapshot(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl);
|
||||
boolean restoreAcl, String customSFT);
|
||||
|
||||
/**
|
||||
* List completed snapshots.
|
||||
|
|
|
@ -488,14 +488,14 @@ class AsyncHBaseAdmin implements AsyncAdmin {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<Void> restoreSnapshot(String snapshotName, boolean takeFailSafeSnapshot,
|
||||
boolean restoreAcl) {
|
||||
boolean restoreAcl) {
|
||||
return wrap(rawAdmin.restoreSnapshot(snapshotName, takeFailSafeSnapshot, restoreAcl));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> cloneSnapshot(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl) {
|
||||
return wrap(rawAdmin.cloneSnapshot(snapshotName, tableName, restoreAcl));
|
||||
boolean restoreAcl, String customSFT) {
|
||||
return wrap(rawAdmin.cloneSnapshot(snapshotName, tableName, restoreAcl, customSFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -195,6 +195,11 @@ public interface ColumnFamilyDescriptor {
|
|||
* @return A clone value. Null if no mapping for the key
|
||||
*/
|
||||
Bytes getValue(Bytes key);
|
||||
/**
|
||||
* @param key The key.
|
||||
* @return A clone value. Null if no mapping for the key
|
||||
*/
|
||||
String getValue(String key);
|
||||
/**
|
||||
* @param key The key.
|
||||
* @return A clone value. Null if no mapping for the key
|
||||
|
|
|
@ -671,6 +671,12 @@ public class ColumnFamilyDescriptorBuilder {
|
|||
return value == null ? null : value.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
Bytes rval = values.get(new Bytes(Bytes.toBytes(key)));
|
||||
return rval == null ? null : Bytes.toString(rval.get(), rval.getOffset(), rval.getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Bytes, Bytes> getValues() {
|
||||
return Collections.unmodifiableMap(values);
|
||||
|
|
|
@ -1967,7 +1967,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
|
|||
} else if (!exists) {
|
||||
// if table does not exist, then just clone snapshot into new table.
|
||||
completeConditionalOnFuture(future,
|
||||
internalRestoreSnapshot(snapshotName, finalTableName, restoreAcl));
|
||||
internalRestoreSnapshot(snapshotName, finalTableName, restoreAcl, null));
|
||||
} else {
|
||||
addListener(isTableDisabled(finalTableName), (disabled, err4) -> {
|
||||
if (err4 != null) {
|
||||
|
@ -2003,12 +2003,13 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
|
|||
future.completeExceptionally(err);
|
||||
} else {
|
||||
// Step.2 Restore snapshot
|
||||
addListener(internalRestoreSnapshot(snapshotName, tableName, restoreAcl),
|
||||
addListener(internalRestoreSnapshot(snapshotName, tableName, restoreAcl, null),
|
||||
(void2, err2) -> {
|
||||
if (err2 != null) {
|
||||
// Step.3.a Something went wrong during the restore and try to rollback.
|
||||
addListener(
|
||||
internalRestoreSnapshot(failSafeSnapshotSnapshotName, tableName, restoreAcl),
|
||||
internalRestoreSnapshot(failSafeSnapshotSnapshotName, tableName, restoreAcl,
|
||||
null),
|
||||
(void3, err3) -> {
|
||||
if (err3 != null) {
|
||||
future.completeExceptionally(err3);
|
||||
|
@ -2036,7 +2037,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
|
|||
});
|
||||
return future;
|
||||
} else {
|
||||
return internalRestoreSnapshot(snapshotName, tableName, restoreAcl);
|
||||
return internalRestoreSnapshot(snapshotName, tableName, restoreAcl, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2053,7 +2054,7 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<Void> cloneSnapshot(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl) {
|
||||
boolean restoreAcl, String customSFT) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
addListener(tableExists(tableName), (exists, err) -> {
|
||||
if (err != null) {
|
||||
|
@ -2062,14 +2063,14 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
|
|||
future.completeExceptionally(new TableExistsException(tableName));
|
||||
} else {
|
||||
completeConditionalOnFuture(future,
|
||||
internalRestoreSnapshot(snapshotName, tableName, restoreAcl));
|
||||
internalRestoreSnapshot(snapshotName, tableName, restoreAcl, customSFT));
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> internalRestoreSnapshot(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl) {
|
||||
boolean restoreAcl, String customSFT) {
|
||||
SnapshotProtos.SnapshotDescription snapshot = SnapshotProtos.SnapshotDescription.newBuilder()
|
||||
.setName(snapshotName).setTable(tableName.getNameAsString()).build();
|
||||
try {
|
||||
|
@ -2077,10 +2078,15 @@ class RawAsyncHBaseAdmin implements AsyncAdmin {
|
|||
} catch (IllegalArgumentException e) {
|
||||
return failedFuture(e);
|
||||
}
|
||||
RestoreSnapshotRequest.Builder builder =
|
||||
RestoreSnapshotRequest.newBuilder().setSnapshot(snapshot).setNonceGroup(ng.getNonceGroup())
|
||||
.setNonce(ng.newNonce()).setRestoreACL(restoreAcl);
|
||||
if(customSFT != null){
|
||||
builder.setCustomSFT(customSFT);
|
||||
}
|
||||
return waitProcedureResult(this.<Long> newMasterCaller().action((controller, stub) -> this
|
||||
.<RestoreSnapshotRequest, RestoreSnapshotResponse, Long> call(controller, stub,
|
||||
RestoreSnapshotRequest.newBuilder().setSnapshot(snapshot).setNonceGroup(ng.getNonceGroup())
|
||||
.setNonce(ng.newNonce()).setRestoreACL(restoreAcl).build(),
|
||||
builder.build(),
|
||||
(s, c, req, done) -> s.restoreSnapshot(c, req, done), (resp) -> resp.getProcId()))
|
||||
.call());
|
||||
}
|
||||
|
|
|
@ -462,6 +462,7 @@ message RestoreSnapshotRequest {
|
|||
optional uint64 nonce_group = 2 [default = 0];
|
||||
optional uint64 nonce = 3 [default = 0];
|
||||
optional bool restoreACL = 4 [default = false];
|
||||
optional string customSFT = 5;
|
||||
}
|
||||
|
||||
message RestoreSnapshotResponse {
|
||||
|
|
|
@ -208,6 +208,7 @@ message CloneSnapshotStateData {
|
|||
repeated RegionInfo region_info = 4;
|
||||
repeated RestoreParentToChildRegionsPair parent_to_child_regions_pair_list = 5;
|
||||
optional bool restore_acl = 6;
|
||||
optional string customSFT = 7;
|
||||
}
|
||||
|
||||
enum RestoreSnapshotState {
|
||||
|
|
|
@ -2619,8 +2619,8 @@ public class HMaster extends HBaseServerBase<MasterRpcServices> implements Maste
|
|||
|
||||
}
|
||||
|
||||
public long restoreSnapshot(final SnapshotDescription snapshotDesc,
|
||||
final long nonceGroup, final long nonce, final boolean restoreAcl) throws IOException {
|
||||
public long restoreSnapshot(final SnapshotDescription snapshotDesc, final long nonceGroup,
|
||||
final long nonce, final boolean restoreAcl, final String customSFT) throws IOException {
|
||||
checkInitialized();
|
||||
getSnapshotManager().checkSnapshotSupport();
|
||||
|
||||
|
@ -2629,18 +2629,19 @@ public class HMaster extends HBaseServerBase<MasterRpcServices> implements Maste
|
|||
getClusterSchema().getNamespace(dstTable.getNamespaceAsString());
|
||||
|
||||
return MasterProcedureUtil.submitProcedure(
|
||||
new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
|
||||
@Override
|
||||
protected void run() throws IOException {
|
||||
new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
|
||||
@Override
|
||||
protected void run() throws IOException {
|
||||
setProcId(
|
||||
getSnapshotManager().restoreOrCloneSnapshot(snapshotDesc, getNonceKey(), restoreAcl));
|
||||
}
|
||||
getSnapshotManager().restoreOrCloneSnapshot(snapshotDesc, getNonceKey(), restoreAcl,
|
||||
customSFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription() {
|
||||
return "RestoreSnapshotProcedure";
|
||||
}
|
||||
});
|
||||
@Override
|
||||
protected String getDescription() {
|
||||
return "RestoreSnapshotProcedure";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkTableExists(final TableName tableName)
|
||||
|
|
|
@ -1586,7 +1586,7 @@ public class MasterRpcServices extends HBaseRpcServicesBase<HMaster>
|
|||
RestoreSnapshotRequest request) throws ServiceException {
|
||||
try {
|
||||
long procId = server.restoreSnapshot(request.getSnapshot(), request.getNonceGroup(),
|
||||
request.getNonce(), request.getRestoreACL());
|
||||
request.getNonce(), request.getRestoreACL(), request.getCustomSFT());
|
||||
return RestoreSnapshotResponse.newBuilder().setProcId(procId).build();
|
||||
} catch (ForeignException e) {
|
||||
throw new ServiceException(e.getCause());
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.apache.hadoop.fs.FileSystem;
|
|||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.hadoop.hbase.TableExistsException;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
|
||||
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
|
||||
import org.apache.hadoop.hbase.client.RegionInfo;
|
||||
import org.apache.hadoop.hbase.client.TableDescriptor;
|
||||
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
|
||||
|
@ -44,6 +46,8 @@ import org.apache.hadoop.hbase.master.procedure.CreateTableProcedure.CreateHdfsR
|
|||
import org.apache.hadoop.hbase.monitoring.MonitoredTask;
|
||||
import org.apache.hadoop.hbase.monitoring.TaskMonitor;
|
||||
import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
|
||||
import org.apache.hadoop.hbase.procedure2.util.StringUtils;
|
||||
import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
|
||||
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
|
||||
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
|
||||
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper;
|
||||
|
@ -72,6 +76,7 @@ public class CloneSnapshotProcedure
|
|||
private TableDescriptor tableDescriptor;
|
||||
private SnapshotDescription snapshot;
|
||||
private boolean restoreAcl;
|
||||
private String customSFT;
|
||||
private List<RegionInfo> newRegions = null;
|
||||
private Map<String, Pair<String, String> > parentsToChildrenPairMap = new HashMap<>();
|
||||
|
||||
|
@ -95,13 +100,20 @@ public class CloneSnapshotProcedure
|
|||
* @param tableDescriptor the table to operate on
|
||||
* @param snapshot snapshot to clone from
|
||||
*/
|
||||
public CloneSnapshotProcedure(final MasterProcedureEnv env,
|
||||
final TableDescriptor tableDescriptor, final SnapshotDescription snapshot,
|
||||
final boolean restoreAcl) {
|
||||
this(env, tableDescriptor, snapshot, restoreAcl, null);
|
||||
}
|
||||
|
||||
public CloneSnapshotProcedure(final MasterProcedureEnv env,
|
||||
final TableDescriptor tableDescriptor, final SnapshotDescription snapshot,
|
||||
final boolean restoreAcl) {
|
||||
final boolean restoreAcl, final String customSFT) {
|
||||
super(env);
|
||||
this.tableDescriptor = tableDescriptor;
|
||||
this.snapshot = snapshot;
|
||||
this.restoreAcl = restoreAcl;
|
||||
this.customSFT = customSFT;
|
||||
|
||||
getMonitorStatus();
|
||||
}
|
||||
|
@ -139,6 +151,7 @@ public class CloneSnapshotProcedure
|
|||
setNextState(CloneSnapshotState.CLONE_SNAPSHOT_WRITE_FS_LAYOUT);
|
||||
break;
|
||||
case CLONE_SNAPSHOT_WRITE_FS_LAYOUT:
|
||||
updateTableDescriptorWithSFT();
|
||||
newRegions = createFilesystemLayout(env, tableDescriptor, newRegions);
|
||||
env.getMasterServices().getTableDescriptors().update(tableDescriptor, true);
|
||||
setNextState(CloneSnapshotState.CLONE_SNAPSHOT_ADD_TO_META);
|
||||
|
@ -203,6 +216,37 @@ public class CloneSnapshotProcedure
|
|||
return Flow.HAS_MORE_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a StoreFileTracker is specified we strip the TableDescriptor from previous SFT config
|
||||
* and set the specified SFT on the table level
|
||||
*/
|
||||
private void updateTableDescriptorWithSFT() {
|
||||
if (StringUtils.isEmpty(customSFT)){
|
||||
return;
|
||||
}
|
||||
|
||||
TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor);
|
||||
builder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, customSFT);
|
||||
for (ColumnFamilyDescriptor family : tableDescriptor.getColumnFamilies()){
|
||||
ColumnFamilyDescriptorBuilder cfBuilder = ColumnFamilyDescriptorBuilder.newBuilder(family);
|
||||
cfBuilder.setConfiguration(StoreFileTrackerFactory.TRACKER_IMPL, null);
|
||||
cfBuilder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, null);
|
||||
builder.modifyColumnFamily(cfBuilder.build());
|
||||
}
|
||||
tableDescriptor = builder.build();
|
||||
}
|
||||
|
||||
private void validateSFT() {
|
||||
if (StringUtils.isEmpty(customSFT)){
|
||||
return;
|
||||
}
|
||||
|
||||
//if customSFT is invalid getTrackerClass will throw a RuntimeException
|
||||
Configuration sftConfig = new Configuration();
|
||||
sftConfig.set(StoreFileTrackerFactory.TRACKER_IMPL, customSFT);
|
||||
StoreFileTrackerFactory.getTrackerClass(sftConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void rollbackState(final MasterProcedureEnv env, final CloneSnapshotState state)
|
||||
throws IOException {
|
||||
|
@ -292,6 +336,9 @@ public class CloneSnapshotProcedure
|
|||
cloneSnapshotMsg.addParentToChildRegionsPairList(parentToChildrenPair);
|
||||
}
|
||||
}
|
||||
if (!StringUtils.isEmpty(customSFT)){
|
||||
cloneSnapshotMsg.setCustomSFT(customSFT);
|
||||
}
|
||||
serializer.serialize(cloneSnapshotMsg.build());
|
||||
}
|
||||
|
||||
|
@ -327,6 +374,9 @@ public class CloneSnapshotProcedure
|
|||
parentToChildrenPair.getChild2RegionName()));
|
||||
}
|
||||
}
|
||||
if (!StringUtils.isEmpty(cloneSnapshotMsg.getCustomSFT())){
|
||||
customSFT = cloneSnapshotMsg.getCustomSFT();
|
||||
}
|
||||
// Make sure that the monitor status is set up
|
||||
getMonitorStatus();
|
||||
}
|
||||
|
@ -340,6 +390,8 @@ public class CloneSnapshotProcedure
|
|||
if (env.getMasterServices().getTableDescriptors().exists(tableName)) {
|
||||
throw new TableExistsException(tableName);
|
||||
}
|
||||
|
||||
validateSFT();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||
|
@ -90,6 +91,7 @@ public class RestoreSnapshotProcedure
|
|||
throws HBaseIOException {
|
||||
this(env, tableDescriptor, snapshot, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param env MasterProcedureEnv
|
||||
|
@ -387,14 +389,15 @@ public class RestoreSnapshotProcedure
|
|||
FileSystem fs = fileSystemManager.getFileSystem();
|
||||
Path rootDir = fileSystemManager.getRootDir();
|
||||
final ForeignExceptionDispatcher monitorException = new ForeignExceptionDispatcher();
|
||||
final Configuration conf = new Configuration(env.getMasterConfiguration());
|
||||
|
||||
LOG.info("Starting restore snapshot=" + ClientSnapshotDescriptionUtils.toString(snapshot));
|
||||
try {
|
||||
Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
|
||||
SnapshotManifest manifest = SnapshotManifest.open(
|
||||
env.getMasterServices().getConfiguration(), fs, snapshotDir, snapshot);
|
||||
conf, fs, snapshotDir, snapshot);
|
||||
RestoreSnapshotHelper restoreHelper = new RestoreSnapshotHelper(
|
||||
env.getMasterServices().getConfiguration(),
|
||||
conf,
|
||||
fs,
|
||||
manifest,
|
||||
modifiedTableDescriptor,
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.apache.hadoop.hbase.procedure.ProcedureCoordinator;
|
|||
import org.apache.hadoop.hbase.procedure.ProcedureCoordinatorRpcs;
|
||||
import org.apache.hadoop.hbase.procedure.ZKProcedureCoordinator;
|
||||
import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
|
||||
import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
|
||||
import org.apache.hadoop.hbase.security.AccessDeniedException;
|
||||
import org.apache.hadoop.hbase.security.User;
|
||||
import org.apache.hadoop.hbase.security.access.AccessChecker;
|
||||
|
@ -751,8 +752,8 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
* @throws IOException
|
||||
*/
|
||||
private long cloneSnapshot(final SnapshotDescription reqSnapshot, final TableName tableName,
|
||||
final SnapshotDescription snapshot, final TableDescriptor snapshotTableDesc,
|
||||
final NonceKey nonceKey, final boolean restoreAcl) throws IOException {
|
||||
final SnapshotDescription snapshot, final TableDescriptor snapshotTableDesc,
|
||||
final NonceKey nonceKey, final boolean restoreAcl, final String customSFT) throws IOException {
|
||||
MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost();
|
||||
TableDescriptor htd = TableDescriptorBuilder.copy(tableName, snapshotTableDesc);
|
||||
org.apache.hadoop.hbase.client.SnapshotDescription snapshotPOJO = null;
|
||||
|
@ -762,7 +763,7 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
}
|
||||
long procId;
|
||||
try {
|
||||
procId = cloneSnapshot(snapshot, htd, nonceKey, restoreAcl);
|
||||
procId = cloneSnapshot(snapshot, htd, nonceKey, restoreAcl, customSFT);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Exception occurred while cloning the snapshot " + snapshot.getName()
|
||||
+ " as table " + tableName.getNameAsString(), e);
|
||||
|
@ -786,7 +787,8 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
* @return procId the ID of the clone snapshot procedure
|
||||
*/
|
||||
synchronized long cloneSnapshot(final SnapshotDescription snapshot,
|
||||
final TableDescriptor tableDescriptor, final NonceKey nonceKey, final boolean restoreAcl)
|
||||
final TableDescriptor tableDescriptor, final NonceKey nonceKey, final boolean restoreAcl,
|
||||
final String customSFT)
|
||||
throws HBaseSnapshotException {
|
||||
TableName tableName = tableDescriptor.getTableName();
|
||||
|
||||
|
@ -803,7 +805,7 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
try {
|
||||
long procId = master.getMasterProcedureExecutor().submitProcedure(
|
||||
new CloneSnapshotProcedure(master.getMasterProcedureExecutor().getEnvironment(),
|
||||
tableDescriptor, snapshot, restoreAcl),
|
||||
tableDescriptor, snapshot, restoreAcl, customSFT),
|
||||
nonceKey);
|
||||
this.restoreTableToProcIdMap.put(tableName, procId);
|
||||
return procId;
|
||||
|
@ -822,7 +824,7 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
* @throws IOException
|
||||
*/
|
||||
public long restoreOrCloneSnapshot(final SnapshotDescription reqSnapshot, final NonceKey nonceKey,
|
||||
final boolean restoreAcl) throws IOException {
|
||||
final boolean restoreAcl, String customSFT) throws IOException {
|
||||
FileSystem fs = master.getMasterFileSystem().getFileSystem();
|
||||
Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(reqSnapshot, rootDir);
|
||||
|
||||
|
@ -854,11 +856,12 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
// Execute the restore/clone operation
|
||||
long procId;
|
||||
if (master.getTableDescriptors().exists(tableName)) {
|
||||
procId = restoreSnapshot(reqSnapshot, tableName, snapshot, snapshotTableDesc, nonceKey,
|
||||
restoreAcl);
|
||||
procId =
|
||||
restoreSnapshot(reqSnapshot, tableName, snapshot, snapshotTableDesc, nonceKey, restoreAcl);
|
||||
} else {
|
||||
procId =
|
||||
cloneSnapshot(reqSnapshot, tableName, snapshot, snapshotTableDesc, nonceKey, restoreAcl);
|
||||
cloneSnapshot(reqSnapshot, tableName, snapshot, snapshotTableDesc, nonceKey, restoreAcl,
|
||||
customSFT);
|
||||
}
|
||||
return procId;
|
||||
}
|
||||
|
@ -880,6 +883,10 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
final NonceKey nonceKey, final boolean restoreAcl) throws IOException {
|
||||
MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost();
|
||||
|
||||
//have to check first if restoring the snapshot would break current SFT setup
|
||||
StoreFileTrackerFactory.validatePreRestoreSnapshot(master.getTableDescriptors().get(tableName),
|
||||
snapshotTableDesc, master.getConfiguration());
|
||||
|
||||
if (master.getTableStateManager().isTableState(
|
||||
TableName.valueOf(snapshot.getTable()), TableState.State.ENABLED)) {
|
||||
throw new UnsupportedOperationException("Table '" +
|
||||
|
@ -921,7 +928,7 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
* @return procId the ID of the restore snapshot procedure
|
||||
*/
|
||||
private synchronized long restoreSnapshot(final SnapshotDescription snapshot,
|
||||
final TableDescriptor tableDescriptor, final NonceKey nonceKey, final boolean restoreAcl)
|
||||
final TableDescriptor tableDescriptor, final NonceKey nonceKey, final boolean restoreAcl)
|
||||
throws HBaseSnapshotException {
|
||||
final TableName tableName = tableDescriptor.getTableName();
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
|
|||
import org.apache.hadoop.hbase.regionserver.StoreContext;
|
||||
|
||||
import org.apache.hadoop.hbase.regionserver.StoreUtils;
|
||||
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
|
||||
import org.apache.hadoop.hbase.util.ReflectionUtils;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -92,7 +93,7 @@ public final class StoreFileTrackerFactory {
|
|||
return name != null ? name.name() : clazz.getName();
|
||||
}
|
||||
|
||||
private static Class<? extends StoreFileTracker> getTrackerClass(Configuration conf) {
|
||||
public static Class<? extends StoreFileTracker> getTrackerClass(Configuration conf) {
|
||||
try {
|
||||
Trackers tracker = Trackers.valueOf(getStoreFileTrackerName(conf).toUpperCase());
|
||||
return tracker.clazz;
|
||||
|
@ -311,4 +312,40 @@ public final class StoreFileTrackerFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure restoring a snapshot does not break the current SFT setup
|
||||
* follows StoreUtils.createStoreConfiguration
|
||||
* @param currentTableDesc Existing Table's TableDescriptor
|
||||
* @param snapshotTableDesc Snapshot's TableDescriptor
|
||||
* @param baseConf Current global configuration
|
||||
* @throws RestoreSnapshotException if restore would break the current SFT setup
|
||||
*/
|
||||
public static void validatePreRestoreSnapshot(TableDescriptor currentTableDesc,
|
||||
TableDescriptor snapshotTableDesc, Configuration baseConf) throws RestoreSnapshotException {
|
||||
|
||||
for (ColumnFamilyDescriptor cfDesc : currentTableDesc.getColumnFamilies()) {
|
||||
ColumnFamilyDescriptor snapCFDesc = snapshotTableDesc.getColumnFamily(cfDesc.getName());
|
||||
// if there is no counterpart in the snapshot it will be just deleted so the config does
|
||||
// not matter
|
||||
if (snapCFDesc != null) {
|
||||
Configuration currentCompositeConf =
|
||||
StoreUtils.createStoreConfiguration(baseConf, currentTableDesc, cfDesc);
|
||||
Configuration snapCompositeConf =
|
||||
StoreUtils.createStoreConfiguration(baseConf, snapshotTableDesc, snapCFDesc);
|
||||
Class<? extends StoreFileTracker> currentSFT =
|
||||
StoreFileTrackerFactory.getTrackerClass(currentCompositeConf);
|
||||
Class<? extends StoreFileTracker> snapSFT =
|
||||
StoreFileTrackerFactory.getTrackerClass(snapCompositeConf);
|
||||
|
||||
//restoration is not possible if there is an SFT mismatch
|
||||
if (currentSFT != snapSFT) {
|
||||
throw new RestoreSnapshotException(
|
||||
"Restoring Snapshot is not possible because " + " the config for column family "
|
||||
+ cfDesc.getNameAsString() + " has incompatible configuration. Current SFT: "
|
||||
+ currentSFT + " SFT from snapshot: " + snapSFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import org.apache.hadoop.hbase.regionserver.HRegion;
|
|||
import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
|
||||
import org.apache.hadoop.hbase.regionserver.StoreContext;
|
||||
import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
|
||||
import org.apache.hadoop.hbase.regionserver.StoreUtils;
|
||||
import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTracker;
|
||||
import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
|
||||
import org.apache.hadoop.hbase.security.access.AccessControlClient;
|
||||
|
@ -72,9 +73,7 @@ import org.apache.hadoop.io.IOUtils;
|
|||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;
|
||||
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotRegionManifest;
|
||||
|
@ -200,8 +199,8 @@ public class RestoreSnapshotHelper {
|
|||
|
||||
List<RegionInfo> tableRegions = getTableRegions();
|
||||
|
||||
RegionInfo mobRegion = MobUtils.getMobRegionInfo(snapshotManifest.getTableDescriptor()
|
||||
.getTableName());
|
||||
RegionInfo mobRegion =
|
||||
MobUtils.getMobRegionInfo(snapshotManifest.getTableDescriptor().getTableName());
|
||||
if (tableRegions != null) {
|
||||
// restore the mob region in case
|
||||
if (regionNames.contains(mobRegion.getEncodedName())) {
|
||||
|
@ -707,7 +706,9 @@ public class RestoreSnapshotHelper {
|
|||
HRegionFileSystem.openRegionFromFileSystem(conf, fs, tableDir, newRegionInfo, false) :
|
||||
HRegionFileSystem.createRegionOnFileSystem(conf, fs, tableDir, newRegionInfo);
|
||||
|
||||
StoreFileTracker tracker = StoreFileTrackerFactory.create(conf, true,
|
||||
Configuration sftConf = StoreUtils.createStoreConfiguration(conf, tableDesc,
|
||||
tableDesc.getColumnFamily(familyFiles.getFamilyName().toByteArray()));
|
||||
StoreFileTracker tracker = StoreFileTrackerFactory.create(sftConf, true,
|
||||
StoreContext.getBuilder().withFamilyStoreDirectoryPath(familyDir).
|
||||
withRegionFileSystem(regionFS).build());
|
||||
tracker.set(clonedFiles);
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* 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.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory;
|
||||
import org.apache.hadoop.hbase.testclassification.ClientTests;
|
||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
|
||||
@Category({ LargeTests.class, ClientTests.class })
|
||||
public class TestCloneSnapshotFromClientCustomSFT extends CloneSnapshotFromClientTestBase{
|
||||
|
||||
@ClassRule
|
||||
public static final HBaseClassTestRule CLASS_RULE =
|
||||
HBaseClassTestRule.forClass(TestCloneSnapshotFromClientCustomSFT.class);
|
||||
|
||||
public static final String CLONE_SFT = "FILE";
|
||||
|
||||
@Test
|
||||
public void testCloneSnapshotWithCustomSFT() throws IOException, InterruptedException {
|
||||
TableName clonedTableName =
|
||||
TableName.valueOf(getValidMethodName() + "-" + EnvironmentEdgeManager.currentTime());
|
||||
|
||||
admin.cloneSnapshot(snapshotName1, clonedTableName, false, CLONE_SFT);
|
||||
verifyRowCount(TEST_UTIL, clonedTableName, snapshot1Rows);
|
||||
|
||||
TableDescriptor td = admin.getDescriptor(clonedTableName);
|
||||
assertEquals(CLONE_SFT, td.getValue(StoreFileTrackerFactory.TRACKER_IMPL));
|
||||
|
||||
TEST_UTIL.deleteTable(clonedTableName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneSnapshotWithIncorrectCustomSFT() throws IOException, InterruptedException {
|
||||
TableName clonedTableName =
|
||||
TableName.valueOf(getValidMethodName() + "-" + EnvironmentEdgeManager.currentTime());
|
||||
|
||||
IOException ioException = assertThrows(IOException.class, () -> {
|
||||
admin.cloneSnapshot(snapshotName1, clonedTableName, false, "IncorrectSFT");
|
||||
});
|
||||
|
||||
assertEquals(
|
||||
"java.lang.RuntimeException: java.lang.RuntimeException: " +
|
||||
"java.lang.ClassNotFoundException: Class IncorrectSFT not found",
|
||||
ioException.getMessage());
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ package org.apache.hadoop.hbase.regionserver.storefiletracker;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -28,7 +27,6 @@ import java.util.Map;
|
|||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.regionserver.StoreContext;
|
||||
import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
|
||||
import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -22,9 +22,16 @@ import static org.junit.Assert.assertThrows;
|
|||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||
import org.apache.hadoop.hbase.HBaseConfiguration;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
|
||||
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
|
||||
import org.apache.hadoop.hbase.client.TableDescriptor;
|
||||
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
|
||||
import org.apache.hadoop.hbase.regionserver.StoreContext;
|
||||
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
|
||||
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
|
||||
import org.apache.hadoop.hbase.testclassification.SmallTests;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
|
@ -55,4 +62,49 @@ public class TestStoreFileTrackerFactory {
|
|||
assertThrows(IllegalArgumentException.class, () -> StoreFileTrackerFactory
|
||||
.createForMigration(conf, configName, false, StoreContext.getBuilder().build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckSFTCompatibility() throws Exception {
|
||||
//checking default value change on different configuration levels
|
||||
Configuration conf = new Configuration();
|
||||
conf.set(StoreFileTrackerFactory.TRACKER_IMPL, "DEFAULT");
|
||||
|
||||
//creating a TD with only TableDescriptor level config
|
||||
TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf("TableX"));
|
||||
builder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, "FILE");
|
||||
ColumnFamilyDescriptor cf = ColumnFamilyDescriptorBuilder.of("cf");
|
||||
builder.setColumnFamily(cf);
|
||||
TableDescriptor td = builder.build();
|
||||
|
||||
//creating a TD with matching ColumnFamilyDescriptor level setting
|
||||
TableDescriptorBuilder snapBuilder =
|
||||
TableDescriptorBuilder.newBuilder(TableName.valueOf("TableY"));
|
||||
snapBuilder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, "FILE");
|
||||
ColumnFamilyDescriptorBuilder snapCFBuilder =
|
||||
ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("cf"));
|
||||
snapCFBuilder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, "FILE");
|
||||
snapBuilder.setColumnFamily(snapCFBuilder.build());
|
||||
TableDescriptor snapTd = snapBuilder.build();
|
||||
|
||||
// adding a cf config that matches the td config is fine even when it does not match the default
|
||||
StoreFileTrackerFactory.validatePreRestoreSnapshot(td, snapTd, conf);
|
||||
// removing cf level config is fine when it matches the td config
|
||||
StoreFileTrackerFactory.validatePreRestoreSnapshot(snapTd, td, conf);
|
||||
|
||||
TableDescriptorBuilder defaultBuilder =
|
||||
TableDescriptorBuilder.newBuilder(TableName.valueOf("TableY"));
|
||||
defaultBuilder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, "FILE");
|
||||
ColumnFamilyDescriptorBuilder defaultCFBuilder =
|
||||
ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("cf"));
|
||||
defaultCFBuilder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, "DEFAULT");
|
||||
defaultBuilder.setColumnFamily(defaultCFBuilder.build());
|
||||
TableDescriptor defaultTd = defaultBuilder.build();
|
||||
|
||||
assertThrows(RestoreSnapshotException.class, () -> {
|
||||
StoreFileTrackerFactory.validatePreRestoreSnapshot(td, defaultTd, conf);
|
||||
});
|
||||
assertThrows(RestoreSnapshotException.class, () -> {
|
||||
StoreFileTrackerFactory.validatePreRestoreSnapshot(snapTd, defaultTd, conf);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -546,8 +546,9 @@ public class VerifyingRSGroupAdmin implements Admin, Closeable {
|
|||
}
|
||||
|
||||
public Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName,
|
||||
boolean restoreAcl) throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
return admin.cloneSnapshotAsync(snapshotName, tableName, restoreAcl);
|
||||
boolean restoreAcl, String customSFT)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
return admin.cloneSnapshotAsync(snapshotName, tableName, restoreAcl, customSFT);
|
||||
}
|
||||
|
||||
public void execProcedure(String signature, String instance, Map<String, String> props)
|
||||
|
|
|
@ -1259,8 +1259,8 @@ module Hbase
|
|||
|
||||
#----------------------------------------------------------------------------------------------
|
||||
# Create a new table by cloning the snapshot content
|
||||
def clone_snapshot(snapshot_name, table, restore_acl = false)
|
||||
@admin.cloneSnapshot(snapshot_name, TableName.valueOf(table), restore_acl)
|
||||
def clone_snapshot(snapshot_name, table, restore_acl = false, clone_sft = nil)
|
||||
@admin.cloneSnapshot(snapshot_name, TableName.valueOf(table), restore_acl, clone_sft)
|
||||
end
|
||||
|
||||
#----------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -40,6 +40,7 @@ module HBaseConstants
|
|||
CACHE = 'CACHE'.freeze
|
||||
CACHE_BLOCKS = 'CACHE_BLOCKS'.freeze
|
||||
CLASSNAME = 'CLASSNAME'.freeze
|
||||
CLONE_SFT = 'CLONE_SFT'.freeze
|
||||
CLUSTER_KEY = 'CLUSTER_KEY'.freeze
|
||||
COLUMN = 'COLUMN'.freeze
|
||||
COLUMNS = 'COLUMNS'.freeze
|
||||
|
|
|
@ -33,13 +33,17 @@ Following command will restore all acl from origin snapshot table into the
|
|||
newly created table.
|
||||
|
||||
hbase> clone_snapshot 'snapshotName', 'namespace:tableName', {RESTORE_ACL=>true}
|
||||
|
||||
StoreFileTracker implementation used after restore can be set by the following command.
|
||||
hbase> clone_snapshot 'snapshotName', 'namespace:tableName', {CLONE_SFT=>'FILE'}
|
||||
EOF
|
||||
end
|
||||
|
||||
def command(snapshot_name, table, args = {})
|
||||
raise(ArgumentError, 'Arguments should be a Hash') unless args.is_a?(Hash)
|
||||
restore_acl = args.delete(::HBaseConstants::RESTORE_ACL) || false
|
||||
admin.clone_snapshot(snapshot_name, table, restore_acl)
|
||||
clone_sft = args.delete(::HBaseConstants::CLONE_SFT) || nil
|
||||
admin.clone_snapshot(snapshot_name, table, restore_acl, clone_sft)
|
||||
end
|
||||
|
||||
def handle_exceptions(cause, *args)
|
||||
|
|
|
@ -869,8 +869,8 @@ public class ThriftAdmin implements Admin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName, boolean cloneAcl)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
public Future<Void> cloneSnapshotAsync(String snapshotName, TableName tableName, boolean cloneAcl,
|
||||
String customSFT) throws IOException, TableExistsException, RestoreSnapshotException {
|
||||
throw new NotImplementedException("cloneSnapshotAsync not supported in ThriftAdmin");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue