1717 */
1818package org .apache .hadoop .hbase .client ;
1919
20+ import static org .junit .Assert .assertEquals ;
21+ import static org .junit .Assert .assertFalse ;
22+ import static org .junit .Assert .assertThrows ;
23+
2024import java .io .IOException ;
2125import java .util .List ;
2226import java .util .regex .Pattern ;
2327import org .apache .hadoop .conf .Configuration ;
28+ import org .apache .hadoop .fs .FileSystem ;
29+ import org .apache .hadoop .fs .Path ;
2430import org .apache .hadoop .hbase .Coprocessor ;
2531import org .apache .hadoop .hbase .HBaseCommonTestingUtil ;
2632import org .apache .hadoop .hbase .HBaseTestingUtil ;
33+ import org .apache .hadoop .hbase .HConstants ;
2734import org .apache .hadoop .hbase .TableName ;
2835import org .apache .hadoop .hbase .coprocessor .CoprocessorHost ;
2936import org .apache .hadoop .hbase .master .MasterCoprocessorHost ;
3340import org .apache .hadoop .hbase .security .access .Permission ;
3441import org .apache .hadoop .hbase .security .access .PermissionStorage ;
3542import org .apache .hadoop .hbase .security .access .SecureTestUtil ;
43+ import org .apache .hadoop .hbase .snapshot .SnapshotDescriptionUtils ;
44+ import org .apache .hadoop .hbase .snapshot .SnapshotManifest ;
3645import org .apache .hadoop .hbase .util .Bytes ;
3746import org .junit .AfterClass ;
3847import org .junit .Assert ;
@@ -110,6 +119,8 @@ public static void setupBeforeClass() throws Exception {
110119 verifyConfiguration (conf );
111120 // Enable EXEC permission checking
112121 conf .setBoolean (AccessControlConstants .EXEC_PERMISSION_CHECKS_KEY , true );
122+ TEST_UTIL .getConfiguration ().set (HConstants .SNAPSHOT_RESTORE_FAILSAFE_NAME ,
123+ "hbase-failsafe-{snapshot.name}-{restore.timestamp}" );
113124 TEST_UTIL .startMiniCluster ();
114125 TEST_UTIL .waitUntilAllRegionsAssigned (PermissionStorage .ACL_TABLE_NAME );
115126 MasterCoprocessorHost cpHost =
@@ -168,7 +179,7 @@ private void verifyRows(TableName tableName) throws IOException {
168179 byte [] value = result .getValue (TEST_FAMILY , TEST_QUALIFIER );
169180 Assert .assertArrayEquals (value , Bytes .toBytes (rowCount ++));
170181 }
171- Assert . assertEquals (ROW_COUNT , rowCount );
182+ assertEquals (ROW_COUNT , rowCount );
172183 }
173184 }
174185
@@ -177,7 +188,8 @@ private void verifyRows(TableName tableName) throws IOException {
177188 protected abstract void cloneSnapshot (String snapshotName , TableName tableName ,
178189 boolean restoreAcl ) throws Exception ;
179190
180- protected abstract void restoreSnapshot (String snapshotName , boolean restoreAcl ) throws Exception ;
191+ protected abstract void restoreSnapshot (String snapshotName , boolean takeFailSafeSnapshot ,
192+ boolean restoreAcl ) throws Exception ;
181193
182194 @ Test
183195 public void testRestoreSnapshot () throws Exception {
@@ -220,7 +232,7 @@ public void testRestoreSnapshot() throws Exception {
220232
221233 // restore snapshot with restoreAcl false.
222234 TEST_UTIL .getAdmin ().disableTable (TEST_TABLE );
223- restoreSnapshot (snapshotName1 , false );
235+ restoreSnapshot (snapshotName1 , false , false );
224236 TEST_UTIL .getAdmin ().enableTable (TEST_TABLE );
225237 verifyAllowed (new AccessReadAction (TEST_TABLE ), USER_OWNER , USER_RW );
226238 verifyDenied (new AccessReadAction (TEST_TABLE ), USER_RO , USER_NONE );
@@ -229,12 +241,36 @@ public void testRestoreSnapshot() throws Exception {
229241
230242 // restore snapshot with restoreAcl true.
231243 TEST_UTIL .getAdmin ().disableTable (TEST_TABLE );
232- restoreSnapshot (snapshotName1 , true );
244+ restoreSnapshot (snapshotName1 , false , true );
233245 TEST_UTIL .getAdmin ().enableTable (TEST_TABLE );
234246 verifyAllowed (new AccessReadAction (TEST_TABLE ), USER_OWNER , USER_RO , USER_RW );
235247 verifyDenied (new AccessReadAction (TEST_TABLE ), USER_NONE );
236248 verifyAllowed (new AccessWriteAction (TEST_TABLE ), USER_OWNER , USER_RW );
237249 verifyDenied (new AccessWriteAction (TEST_TABLE ), USER_RO , USER_NONE );
250+
251+ // Delete data.manifest of the snapshot to simulate an invalid snapshot.
252+ Configuration configuration = TEST_UTIL .getConfiguration ();
253+ Path rootDir = new Path (configuration .get (HConstants .HBASE_DIR ));
254+ Path snapshotDir = SnapshotDescriptionUtils .getCompletedSnapshotDir (snapshotName1 , rootDir );
255+ FileSystem fileSystem = FileSystem .get (rootDir .toUri (), configuration );
256+ Path maniFestPath = new Path (snapshotDir , SnapshotManifest .DATA_MANIFEST_NAME );
257+ fileSystem .delete (maniFestPath , false );
258+ assertFalse (fileSystem .exists (maniFestPath ));
259+ assertEquals (1 , TEST_UTIL .getAdmin ().listSnapshots (Pattern .compile (snapshotName1 )).size ());
260+ // There is no failsafe snapshot before restoring.
261+ int failsafeSnapshotCount = TEST_UTIL .getAdmin ()
262+ .listSnapshots (Pattern .compile ("hbase-failsafe-" + snapshotName1 + ".*" )).size ();
263+ assertEquals (0 , failsafeSnapshotCount );
264+ TEST_UTIL .getAdmin ().disableTable (TEST_TABLE );
265+ // We would get Exception when restoring data by this an invalid snapshot.
266+ assertThrows (Exception .class , () -> restoreSnapshot (snapshotName1 , true , true ));
267+ TEST_UTIL .getAdmin ().enableTable (TEST_TABLE );
268+ verifyRows (TEST_TABLE );
269+ // Fail to store snapshot but rollback successfully, so there is no failsafe snapshot after
270+ // restoring.
271+ failsafeSnapshotCount = TEST_UTIL .getAdmin ()
272+ .listSnapshots (Pattern .compile ("hbase-failsafe-" + snapshotName1 + ".*" )).size ();
273+ assertEquals (0 , failsafeSnapshotCount );
238274 }
239275
240276 final class AccessSnapshotAction implements AccessTestAction {
@@ -262,8 +298,8 @@ public void testDeleteSnapshot() throws Exception {
262298 USER_RO , USER_RW , USER_NONE );
263299 List <SnapshotDescription > snapshotDescriptions =
264300 TEST_UTIL .getAdmin ().listSnapshots (Pattern .compile (testSnapshotName ));
265- Assert . assertEquals (1 , snapshotDescriptions .size ());
266- Assert . assertEquals (USER_OWNER .getShortName (), snapshotDescriptions .get (0 ).getOwner ());
301+ assertEquals (1 , snapshotDescriptions .size ());
302+ assertEquals (USER_OWNER .getShortName (), snapshotDescriptions .get (0 ).getOwner ());
267303 AccessTestAction deleteSnapshotAction = () -> {
268304 try (Connection conn = ConnectionFactory .createConnection (TEST_UTIL .getConfiguration ());
269305 Admin admin = conn .getAdmin ()) {
@@ -276,6 +312,6 @@ public void testDeleteSnapshot() throws Exception {
276312
277313 List <SnapshotDescription > snapshotsAfterDelete =
278314 TEST_UTIL .getAdmin ().listSnapshots (Pattern .compile (testSnapshotName ));
279- Assert . assertEquals (0 , snapshotsAfterDelete .size ());
315+ assertEquals (0 , snapshotsAfterDelete .size ());
280316 }
281317}
0 commit comments