HBASE-6777 Snapshot Restore Interface (Matteo Bertozzi)
git-svn-id: https://svn.apache.org/repos/asf/hbase/branches/hbase-7290@1445784 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
77ef4a85d2
commit
eb4346f144
File diff suppressed because it is too large
Load Diff
|
@ -199,6 +199,14 @@ message DeleteSnapshotRequest{
|
|||
message DeleteSnapshotResponse{
|
||||
}
|
||||
|
||||
message RestoreSnapshotRequest {
|
||||
required SnapshotDescription snapshot = 1;
|
||||
}
|
||||
|
||||
message RestoreSnapshotResponse {
|
||||
required int64 expectedTimeout = 1;
|
||||
}
|
||||
|
||||
/* if you don't send the snapshot, then you will get it back
|
||||
* in the response (if the snapshot is done) so you can check the snapshot
|
||||
*/
|
||||
|
@ -211,6 +219,14 @@ message IsSnapshotDoneResponse{
|
|||
optional SnapshotDescription snapshot = 2;
|
||||
}
|
||||
|
||||
message IsRestoreSnapshotDoneRequest {
|
||||
optional SnapshotDescription snapshot = 1;
|
||||
}
|
||||
|
||||
message IsRestoreSnapshotDoneResponse {
|
||||
optional bool done = 1 [default = false];
|
||||
}
|
||||
|
||||
service MasterAdminService {
|
||||
/** Adds a column to the specified table. */
|
||||
rpc addColumn(AddColumnRequest)
|
||||
|
@ -337,4 +353,15 @@ service MasterAdminService {
|
|||
* Determine if the snapshot is done yet.
|
||||
*/
|
||||
rpc isSnapshotDone(IsSnapshotDoneRequest) returns(IsSnapshotDoneResponse);
|
||||
|
||||
/**
|
||||
* Restore a snapshot
|
||||
* @param snapshot description of the snapshot to restore
|
||||
*/
|
||||
rpc restoreSnapshot(RestoreSnapshotRequest) returns(RestoreSnapshotResponse);
|
||||
|
||||
/**
|
||||
* Determine if the snapshot restore is done yet.
|
||||
*/
|
||||
rpc isRestoreSnapshotDone(IsRestoreSnapshotDoneRequest) returns(IsRestoreSnapshotDoneResponse);
|
||||
}
|
||||
|
|
|
@ -85,12 +85,16 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DeleteSnapsh
|
|||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DeleteTableRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.DisableTableRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableTableRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsRestoreSnapshotDoneRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsRestoreSnapshotDoneResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsSnapshotDoneRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsSnapshotDoneResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ListSnapshotRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ModifyColumnRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ModifyTableRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.MoveRegionRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.RestoreSnapshotRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.RestoreSnapshotResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.SetBalancerRunningRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ShutdownRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.StopMasterRequest;
|
||||
|
@ -105,6 +109,7 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterMonitorProtos.GetTableDe
|
|||
import org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException;
|
||||
import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
|
||||
import org.apache.hadoop.hbase.snapshot.exception.HBaseSnapshotException;
|
||||
import org.apache.hadoop.hbase.snapshot.exception.RestoreSnapshotException;
|
||||
import org.apache.hadoop.hbase.snapshot.exception.SnapshotCreationException;
|
||||
import org.apache.hadoop.hbase.snapshot.exception.UnknownSnapshotException;
|
||||
import org.apache.hadoop.hbase.util.Addressing;
|
||||
|
@ -2309,6 +2314,178 @@ public class HBaseAdmin implements Abortable, Closeable {
|
|||
}).getDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified snapshot on the original table. (The table must be disabled)
|
||||
* Before restoring the table, a new snapshot with the current table state is created.
|
||||
* In case of failure, the table will be rolled back to the its original state.
|
||||
*
|
||||
* @param snapshotName name of the snapshot to restore
|
||||
* @throws IOException if a remote or network exception occurs
|
||||
* @throws RestoreSnapshotException if snapshot failed to be restored
|
||||
* @throws IllegalArgumentException if the restore request is formatted incorrectly
|
||||
*/
|
||||
public void restoreSnapshot(final byte[] snapshotName)
|
||||
throws IOException, RestoreSnapshotException {
|
||||
restoreSnapshot(Bytes.toString(snapshotName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified snapshot on the original table. (The table must be disabled)
|
||||
* Before restoring the table, a new snapshot with the current table state is created.
|
||||
* In case of failure, the table will be rolled back to the its original state.
|
||||
*
|
||||
* @param snapshotName name of the snapshot to restore
|
||||
* @throws IOException if a remote or network exception occurs
|
||||
* @throws RestoreSnapshotException if snapshot failed to be restored
|
||||
* @throws IllegalArgumentException if the restore request is formatted incorrectly
|
||||
*/
|
||||
public void restoreSnapshot(final String snapshotName)
|
||||
throws IOException, RestoreSnapshotException {
|
||||
String rollbackSnapshot = snapshotName + "-" + EnvironmentEdgeManager.currentTimeMillis();
|
||||
|
||||
String tableName = null;
|
||||
for (SnapshotDescription snapshotInfo: listSnapshots()) {
|
||||
if (snapshotInfo.getName().equals(snapshotName)) {
|
||||
tableName = snapshotInfo.getTable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tableName == null) {
|
||||
throw new RestoreSnapshotException(
|
||||
"Unable to find the table name for snapshot=" + snapshotName);
|
||||
}
|
||||
|
||||
// Take a snapshot of the current state
|
||||
snapshot(rollbackSnapshot, tableName);
|
||||
|
||||
// Restore snapshot
|
||||
try {
|
||||
internalRestoreSnapshot(snapshotName, tableName);
|
||||
} catch (IOException e) {
|
||||
// Try to rollback
|
||||
try {
|
||||
String msg = "Restore snapshot=" + snapshotName +
|
||||
" failed. Rollback to snapshot=" + rollbackSnapshot + " succeded.";
|
||||
LOG.error(msg, e);
|
||||
internalRestoreSnapshot(rollbackSnapshot, tableName);
|
||||
throw new RestoreSnapshotException(msg, e);
|
||||
} catch (IOException ex) {
|
||||
String msg = "Failed to restore and rollback to snapshot=" + rollbackSnapshot;
|
||||
LOG.error(msg, ex);
|
||||
throw new RestoreSnapshotException(msg, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
*/
|
||||
public void cloneSnapshot(final byte[] snapshotName, final byte[] tableName)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException, InterruptedException {
|
||||
cloneSnapshot(Bytes.toString(snapshotName), Bytes.toString(tableName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
*/
|
||||
public void cloneSnapshot(final String snapshotName, final String tableName)
|
||||
throws IOException, TableExistsException, RestoreSnapshotException, InterruptedException {
|
||||
if (tableExists(tableName)) {
|
||||
throw new TableExistsException("Table '" + tableName + " already exists");
|
||||
}
|
||||
internalRestoreSnapshot(snapshotName, tableName);
|
||||
for (int tries = 0; !isTableEnabled(tableName); ++tries) {
|
||||
Thread.sleep(this.pause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Restore/Clone snapshot and wait for the server to complete (blocking).
|
||||
*
|
||||
* @param snapshot snapshot to restore
|
||||
* @param tableName table name to restore the snapshot on
|
||||
* @throws IOException if a remote or network exception occurs
|
||||
* @throws RestoreSnapshotException if snapshot failed to be restored
|
||||
* @throws IllegalArgumentException if the restore request is formatted incorrectly
|
||||
*/
|
||||
private void internalRestoreSnapshot(final String snapshotName, final String tableName)
|
||||
throws IOException, RestoreSnapshotException {
|
||||
SnapshotDescription snapshot = SnapshotDescription.newBuilder()
|
||||
.setName(snapshotName).setTable(tableName).build();
|
||||
|
||||
// actually restore the snapshot
|
||||
RestoreSnapshotResponse response = internalRestoreSnapshotAsync(snapshot);
|
||||
|
||||
final IsRestoreSnapshotDoneRequest request = IsRestoreSnapshotDoneRequest.newBuilder()
|
||||
.setSnapshot(snapshot).build();
|
||||
IsRestoreSnapshotDoneResponse done = IsRestoreSnapshotDoneResponse.newBuilder().buildPartial();
|
||||
final long maxPauseTime = 5000;
|
||||
int tries = 0;
|
||||
while (!done.getDone()) {
|
||||
try {
|
||||
// sleep a backoff <= pauseTime amount
|
||||
long sleep = getPauseTime(tries++);
|
||||
sleep = sleep > maxPauseTime ? maxPauseTime : sleep;
|
||||
LOG.debug(tries + ") Sleeping: " + sleep + " ms while we wait for snapshot restore to complete.");
|
||||
Thread.sleep(sleep);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.debug("Interrupted while waiting for snapshot " + snapshot + " restore to complete");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LOG.debug("Getting current status of snapshot restore from master...");
|
||||
done = execute(new MasterAdminCallable<IsRestoreSnapshotDoneResponse>() {
|
||||
@Override
|
||||
public IsRestoreSnapshotDoneResponse call() throws ServiceException {
|
||||
return masterAdmin.isRestoreSnapshotDone(null, request);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!done.getDone()) {
|
||||
throw new RestoreSnapshotException("Snapshot '" + snapshot.getName() + "' wasn't restored.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute Restore/Clone snapshot and wait for the server to complete (asynchronous)
|
||||
* <p>
|
||||
* Only a single snapshot should be restored at a time, or results may be undefined.
|
||||
* @param snapshot snapshot to restore
|
||||
* @return response from the server indicating the max time to wait for the snapshot
|
||||
* @throws IOException if a remote or network exception occurs
|
||||
* @throws RestoreSnapshotException if snapshot failed to be restored
|
||||
* @throws IllegalArgumentException if the restore request is formatted incorrectly
|
||||
*/
|
||||
private RestoreSnapshotResponse internalRestoreSnapshotAsync(final SnapshotDescription snapshot)
|
||||
throws IOException, RestoreSnapshotException {
|
||||
SnapshotDescriptionUtils.assertSnapshotRequestIsValid(snapshot);
|
||||
|
||||
final RestoreSnapshotRequest request = RestoreSnapshotRequest.newBuilder().setSnapshot(snapshot)
|
||||
.build();
|
||||
|
||||
// run the snapshot restore on the master
|
||||
return execute(new MasterAdminCallable<RestoreSnapshotResponse>() {
|
||||
@Override
|
||||
public RestoreSnapshotResponse call() throws ServiceException {
|
||||
return masterAdmin.restoreSnapshot(null, request);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List existing snapshots.
|
||||
* @return a list of snapshot descriptor for existing snapshots
|
||||
|
|
|
@ -143,6 +143,8 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableTableR
|
|||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.EnableTableResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsCatalogJanitorEnabledRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsCatalogJanitorEnabledResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsRestoreSnapshotDoneRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsRestoreSnapshotDoneResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsSnapshotDoneRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.IsSnapshotDoneResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ListSnapshotRequest;
|
||||
|
@ -155,6 +157,8 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.MoveRegionRe
|
|||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.MoveRegionResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.OfflineRegionRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.OfflineRegionResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.RestoreSnapshotRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.RestoreSnapshotResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.SetBalancerRunningRequest;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.SetBalancerRunningResponse;
|
||||
import org.apache.hadoop.hbase.protobuf.generated.MasterAdminProtos.ShutdownRequest;
|
||||
|
@ -2652,4 +2656,19 @@ Server {
|
|||
throw new ServiceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestoreSnapshotResponse restoreSnapshot(RpcController controller,
|
||||
RestoreSnapshotRequest request) throws ServiceException {
|
||||
throw new ServiceException(new UnsupportedOperationException(
|
||||
"Snapshots restore is not implemented yet."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRestoreSnapshotDoneResponse isRestoreSnapshotDone(RpcController controller,
|
||||
IsRestoreSnapshotDoneRequest request) throws ServiceException {
|
||||
throw new ServiceException(new UnsupportedOperationException(
|
||||
"Snapshots restore is not implemented yet."));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* 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.snapshot.exception;
|
||||
|
||||
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
|
||||
|
||||
/**
|
||||
* Thrown when a snapshot could not be restored due to a server-side error when restoring it.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RestoreSnapshotException extends HBaseSnapshotException {
|
||||
public RestoreSnapshotException(String msg, SnapshotDescription desc) {
|
||||
super(msg, desc);
|
||||
}
|
||||
|
||||
public RestoreSnapshotException(String msg, Throwable cause, SnapshotDescription desc) {
|
||||
super(msg, cause, desc);
|
||||
}
|
||||
|
||||
public RestoreSnapshotException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public RestoreSnapshotException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue