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:
Jonathan Hsieh 2013-02-13 18:07:57 +00:00
parent 77ef4a85d2
commit eb4346f144
5 changed files with 2197 additions and 47 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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."));
}
}

View File

@ -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);
}
}