2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.client
;
20 import static org
.junit
.Assert
.assertEquals
;
21 import static org
.junit
.Assert
.assertFalse
;
22 import static org
.junit
.Assert
.assertTrue
;
23 import static org
.junit
.Assert
.fail
;
25 import java
.util
.ArrayList
;
26 import java
.util
.Arrays
;
27 import java
.util
.List
;
28 import java
.util
.regex
.Pattern
;
29 import org
.apache
.hadoop
.conf
.Configuration
;
30 import org
.apache
.hadoop
.fs
.FileSystem
;
31 import org
.apache
.hadoop
.fs
.Path
;
32 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
33 import org
.apache
.hadoop
.hbase
.HBaseTestingUtil
;
34 import org
.apache
.hadoop
.hbase
.HConstants
;
35 import org
.apache
.hadoop
.hbase
.TableName
;
36 import org
.apache
.hadoop
.hbase
.TableNameTestRule
;
37 import org
.apache
.hadoop
.hbase
.TableNotFoundException
;
38 import org
.apache
.hadoop
.hbase
.master
.snapshot
.SnapshotManager
;
39 import org
.apache
.hadoop
.hbase
.regionserver
.ConstantSizeRegionSplitPolicy
;
40 import org
.apache
.hadoop
.hbase
.regionserver
.storefiletracker
.StoreFileTrackerFactory
;
41 import org
.apache
.hadoop
.hbase
.snapshot
.SnapshotCreationException
;
42 import org
.apache
.hadoop
.hbase
.snapshot
.SnapshotDoesNotExistException
;
43 import org
.apache
.hadoop
.hbase
.snapshot
.SnapshotManifestV1
;
44 import org
.apache
.hadoop
.hbase
.snapshot
.SnapshotTestingUtils
;
45 import org
.apache
.hadoop
.hbase
.testclassification
.ClientTests
;
46 import org
.apache
.hadoop
.hbase
.testclassification
.LargeTests
;
47 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
48 import org
.apache
.hadoop
.hbase
.util
.CommonFSUtils
;
49 import org
.junit
.After
;
50 import org
.junit
.AfterClass
;
51 import org
.junit
.Before
;
52 import org
.junit
.BeforeClass
;
53 import org
.junit
.ClassRule
;
54 import org
.junit
.Rule
;
55 import org
.junit
.Test
;
56 import org
.junit
.experimental
.categories
.Category
;
57 import org
.junit
.runner
.RunWith
;
58 import org
.junit
.runners
.Parameterized
;
59 import org
.junit
.runners
.Parameterized
.Parameter
;
60 import org
.junit
.runners
.Parameterized
.Parameters
;
61 import org
.slf4j
.Logger
;
62 import org
.slf4j
.LoggerFactory
;
64 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.collect
.Lists
;
66 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.ProtobufUtil
;
69 * Test create/using/deleting snapshots from the client
71 * This is an end-to-end test for the snapshot utility
73 @RunWith(Parameterized
.class)
74 @Category({ LargeTests
.class, ClientTests
.class })
75 public class TestSnapshotFromClient
{
78 public static final HBaseClassTestRule CLASS_RULE
=
79 HBaseClassTestRule
.forClass(TestSnapshotFromClient
.class);
81 private static final Logger LOG
= LoggerFactory
.getLogger(TestSnapshotFromClient
.class);
83 protected static final HBaseTestingUtil UTIL
= new HBaseTestingUtil();
84 protected static final int NUM_RS
= 2;
85 protected static final String STRING_TABLE_NAME
= "test";
86 protected static final byte[] TEST_FAM
= Bytes
.toBytes("fam");
87 protected static final TableName TABLE_NAME
=
88 TableName
.valueOf(STRING_TABLE_NAME
);
89 private static final Pattern MATCH_ALL
= Pattern
.compile(".*");
92 public TableNameTestRule name
= new TableNameTestRule();
95 public StoreFileTrackerFactory
.Trackers trackerImpl
;
97 @Parameters(name
= "{index}: tracker={0}")
98 public static List
<Object
[]> params() {
99 return Arrays
.asList(new Object
[] { StoreFileTrackerFactory
.Trackers
.DEFAULT
},
100 new Object
[] { StoreFileTrackerFactory
.Trackers
.FILE
});
104 * Setup the config for the cluster
105 * @throws Exception on failure
108 public static void setupCluster() throws Exception
{
109 setupConf(UTIL
.getConfiguration());
110 UTIL
.startMiniCluster(NUM_RS
);
113 protected static void setupConf(Configuration conf
) {
115 conf
.setInt("hbase.regionsever.info.port", -1);
116 // change the flush size to a small amount, regulating number of store files
117 conf
.setInt("hbase.hregion.memstore.flush.size", 25000);
118 // so make sure we get a compaction when doing a load, but keep around some
119 // files in the store
120 conf
.setInt("hbase.hstore.compaction.min", 10);
121 conf
.setInt("hbase.hstore.compactionThreshold", 10);
122 // block writes if we get to 12 store files
123 conf
.setInt("hbase.hstore.blockingStoreFiles", 12);
125 conf
.setBoolean(SnapshotManager
.HBASE_SNAPSHOT_ENABLED
, true);
126 conf
.set(HConstants
.HBASE_REGION_SPLIT_POLICY_KEY
,
127 ConstantSizeRegionSplitPolicy
.class.getName());
131 public void setup() throws Exception
{
135 protected void createTable() throws Exception
{
136 TableDescriptor htd
=
137 TableDescriptorBuilder
.newBuilder(TABLE_NAME
).setRegionReplication(getNumReplicas())
138 .setValue(StoreFileTrackerFactory
.TRACKER_IMPL
, trackerImpl
.name()).build();
139 UTIL
.createTable(htd
, new byte[][] { TEST_FAM
}, null);
142 protected int getNumReplicas() {
147 public void tearDown() throws Exception
{
148 UTIL
.deleteTable(TABLE_NAME
);
149 SnapshotTestingUtils
.deleteAllSnapshots(UTIL
.getAdmin());
150 SnapshotTestingUtils
.deleteArchiveDirectory(UTIL
);
154 public static void cleanupTest() throws Exception
{
156 UTIL
.shutdownMiniCluster();
157 } catch (Exception e
) {
158 LOG
.warn("failure shutting down cluster", e
);
163 * Test snapshotting not allowed hbase:meta and -ROOT-
165 @Test(expected
= IllegalArgumentException
.class)
166 public void testMetaTablesSnapshot() throws Exception
{
167 UTIL
.getAdmin().snapshot("metaSnapshot", TableName
.META_TABLE_NAME
);
171 * Test HBaseAdmin#deleteSnapshots(String) which deletes snapshots whose names match the parameter
176 public void testSnapshotDeletionWithRegex() throws Exception
{
177 Admin admin
= UTIL
.getAdmin();
178 // make sure we don't fail on listing snapshots
179 SnapshotTestingUtils
.assertNoSnapshots(admin
);
181 // put some stuff in the table
182 Table table
= UTIL
.getConnection().getTable(TABLE_NAME
);
183 UTIL
.loadTable(table
, TEST_FAM
);
186 String snapshot1
= "TableSnapshot1";
187 admin
.snapshot(snapshot1
, TABLE_NAME
);
188 LOG
.debug("Snapshot1 completed.");
190 String snapshot2
= "TableSnapshot2";
191 admin
.snapshot(snapshot2
, TABLE_NAME
);
192 LOG
.debug("Snapshot2 completed.");
194 String snapshot3
= "3rdTableSnapshot";
195 admin
.snapshot(snapshot3
, TABLE_NAME
);
196 LOG
.debug(snapshot3
+ " completed.");
198 // delete the first two snapshots
199 admin
.deleteSnapshots(Pattern
.compile("TableSnapshot.*"));
200 List
<SnapshotDescription
> snapshots
= admin
.listSnapshots();
201 assertEquals(1, snapshots
.size());
202 assertEquals(snapshot3
, snapshots
.get(0).getName());
204 admin
.deleteSnapshot(snapshot3
);
208 * Test snapshotting a table that is offline
212 public void testOfflineTableSnapshot() throws Exception
{
213 Admin admin
= UTIL
.getAdmin();
214 // make sure we don't fail on listing snapshots
215 SnapshotTestingUtils
.assertNoSnapshots(admin
);
217 // put some stuff in the table
218 Table table
= UTIL
.getConnection().getTable(TABLE_NAME
);
219 UTIL
.loadTable(table
, TEST_FAM
, false);
221 LOG
.debug("FS state before disable:");
222 CommonFSUtils
.logFileSystemState(UTIL
.getTestFileSystem(),
223 CommonFSUtils
.getRootDir(UTIL
.getConfiguration()), LOG
);
224 // XXX if this is flakey, might want to consider using the async version and looping as
225 // disableTable can succeed and still timeout.
226 admin
.disableTable(TABLE_NAME
);
228 LOG
.debug("FS state before snapshot:");
229 CommonFSUtils
.logFileSystemState(UTIL
.getTestFileSystem(),
230 CommonFSUtils
.getRootDir(UTIL
.getConfiguration()), LOG
);
232 // take a snapshot of the disabled table
233 final String SNAPSHOT_NAME
= "offlineTableSnapshot";
234 String snapshot
= SNAPSHOT_NAME
;
236 admin
.snapshot(new SnapshotDescription(SNAPSHOT_NAME
, TABLE_NAME
,
237 SnapshotType
.DISABLED
, null, -1, SnapshotManifestV1
.DESCRIPTOR_VERSION
, null));
238 LOG
.debug("Snapshot completed.");
240 // make sure we have the snapshot
241 List
<SnapshotDescription
> snapshots
=
242 SnapshotTestingUtils
.assertOneSnapshotThatMatches(admin
, snapshot
, TABLE_NAME
);
244 // make sure its a valid snapshot
245 FileSystem fs
= UTIL
.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
246 Path rootDir
= UTIL
.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
247 LOG
.debug("FS state after snapshot:");
248 CommonFSUtils
.logFileSystemState(UTIL
.getTestFileSystem(),
249 CommonFSUtils
.getRootDir(UTIL
.getConfiguration()), LOG
);
250 SnapshotTestingUtils
.confirmSnapshotValid(
251 ProtobufUtil
.createHBaseProtosSnapshotDesc(snapshots
.get(0)), TABLE_NAME
, TEST_FAM
,
254 admin
.deleteSnapshot(snapshot
);
255 snapshots
= admin
.listSnapshots();
256 SnapshotTestingUtils
.assertNoSnapshots(admin
);
260 public void testSnapshotFailsOnNonExistantTable() throws Exception
{
261 Admin admin
= UTIL
.getAdmin();
262 // make sure we don't fail on listing snapshots
263 SnapshotTestingUtils
.assertNoSnapshots(admin
);
264 String tableName
= "_not_a_table";
266 // make sure the table doesn't exist
267 boolean fail
= false;
270 admin
.getDescriptor(TableName
.valueOf(tableName
));
272 LOG
.error("Table:" + tableName
+ " already exists, checking a new name");
273 tableName
= tableName
+ "!";
274 } catch (TableNotFoundException e
) {
279 // snapshot the non-existant table
281 admin
.snapshot("fail", TableName
.valueOf(tableName
));
282 fail("Snapshot succeeded even though there is not table.");
283 } catch (SnapshotCreationException e
) {
284 LOG
.info("Correctly failed to snapshot a non-existant table:" + e
.getMessage());
289 public void testOfflineTableSnapshotWithEmptyRegions() throws Exception
{
290 // test with an empty table with one region
292 Admin admin
= UTIL
.getAdmin();
293 // make sure we don't fail on listing snapshots
294 SnapshotTestingUtils
.assertNoSnapshots(admin
);
296 LOG
.debug("FS state before disable:");
297 CommonFSUtils
.logFileSystemState(UTIL
.getTestFileSystem(),
298 CommonFSUtils
.getRootDir(UTIL
.getConfiguration()), LOG
);
299 admin
.disableTable(TABLE_NAME
);
301 LOG
.debug("FS state before snapshot:");
302 CommonFSUtils
.logFileSystemState(UTIL
.getTestFileSystem(),
303 CommonFSUtils
.getRootDir(UTIL
.getConfiguration()), LOG
);
305 // take a snapshot of the disabled table
306 String snapshot
= "testOfflineTableSnapshotWithEmptyRegions";
307 admin
.snapshot(snapshot
, TABLE_NAME
);
308 LOG
.debug("Snapshot completed.");
310 // make sure we have the snapshot
311 List
<SnapshotDescription
> snapshots
=
312 SnapshotTestingUtils
.assertOneSnapshotThatMatches(admin
, snapshot
, TABLE_NAME
);
314 // make sure its a valid snapshot
315 FileSystem fs
= UTIL
.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
316 Path rootDir
= UTIL
.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
317 LOG
.debug("FS state after snapshot:");
318 CommonFSUtils
.logFileSystemState(UTIL
.getTestFileSystem(),
319 CommonFSUtils
.getRootDir(UTIL
.getConfiguration()), LOG
);
321 List
<byte[]> emptyCfs
= Lists
.newArrayList(TEST_FAM
); // no file in the region
322 List
<byte[]> nonEmptyCfs
= Lists
.newArrayList();
323 SnapshotTestingUtils
.confirmSnapshotValid(
324 ProtobufUtil
.createHBaseProtosSnapshotDesc(snapshots
.get(0)), TABLE_NAME
, nonEmptyCfs
,
325 emptyCfs
, rootDir
, admin
, fs
);
327 admin
.deleteSnapshot(snapshot
);
328 snapshots
= admin
.listSnapshots();
329 SnapshotTestingUtils
.assertNoSnapshots(admin
);
333 public void testListTableSnapshots() throws Exception
{
335 final TableName tableName
= name
.getTableName();
337 admin
= UTIL
.getAdmin();
339 TableDescriptor htd
= TableDescriptorBuilder
.newBuilder(tableName
).build();
340 UTIL
.createTable(htd
, new byte[][] { TEST_FAM
}, UTIL
.getConfiguration());
342 String table1Snapshot1
= "Table1Snapshot1";
343 admin
.snapshot(table1Snapshot1
, TABLE_NAME
);
344 LOG
.debug("Snapshot1 completed.");
346 String table1Snapshot2
= "Table1Snapshot2";
347 admin
.snapshot(table1Snapshot2
, TABLE_NAME
);
348 LOG
.debug("Snapshot2 completed.");
350 String table2Snapshot1
= "Table2Snapshot1";
351 admin
.snapshot(table2Snapshot1
, tableName
);
352 LOG
.debug(table2Snapshot1
+ " completed.");
354 List
<SnapshotDescription
> listTableSnapshots
=
355 admin
.listTableSnapshots(Pattern
.compile("test.*"), MATCH_ALL
);
356 List
<String
> listTableSnapshotNames
= new ArrayList
<>();
357 assertEquals(3, listTableSnapshots
.size());
358 for (SnapshotDescription s
: listTableSnapshots
) {
359 listTableSnapshotNames
.add(s
.getName());
361 assertTrue(listTableSnapshotNames
.contains(table1Snapshot1
));
362 assertTrue(listTableSnapshotNames
.contains(table1Snapshot2
));
363 assertTrue(listTableSnapshotNames
.contains(table2Snapshot1
));
367 admin
.deleteSnapshots(Pattern
.compile("Table.*"));
368 } catch (SnapshotDoesNotExistException ignore
) {
370 if (admin
.tableExists(tableName
)) {
371 UTIL
.deleteTable(tableName
);
379 public void testListTableSnapshotsWithRegex() throws Exception
{
382 admin
= UTIL
.getAdmin();
384 String table1Snapshot1
= "Table1Snapshot1";
385 admin
.snapshot(table1Snapshot1
, TABLE_NAME
);
386 LOG
.debug("Snapshot1 completed.");
388 String table1Snapshot2
= "Table1Snapshot2";
389 admin
.snapshot(table1Snapshot2
, TABLE_NAME
);
390 LOG
.debug("Snapshot2 completed.");
392 String table2Snapshot1
= "Table2Snapshot1";
393 admin
.snapshot(table2Snapshot1
, TABLE_NAME
);
394 LOG
.debug(table2Snapshot1
+ " completed.");
396 List
<SnapshotDescription
> listTableSnapshots
=
397 admin
.listTableSnapshots(Pattern
.compile("test.*"), Pattern
.compile("Table1.*"));
398 List
<String
> listTableSnapshotNames
= new ArrayList
<>();
399 assertEquals(2, listTableSnapshots
.size());
400 for (SnapshotDescription s
: listTableSnapshots
) {
401 listTableSnapshotNames
.add(s
.getName());
403 assertTrue(listTableSnapshotNames
.contains(table1Snapshot1
));
404 assertTrue(listTableSnapshotNames
.contains(table1Snapshot2
));
405 assertFalse(listTableSnapshotNames
.contains(table2Snapshot1
));
409 admin
.deleteSnapshots(Pattern
.compile("Table.*"));
410 } catch (SnapshotDoesNotExistException ignore
) {
418 public void testDeleteTableSnapshots() throws Exception
{
420 final TableName tableName
= name
.getTableName();
422 admin
= UTIL
.getAdmin();
424 TableDescriptor htd
= TableDescriptorBuilder
.newBuilder(tableName
).build();
425 UTIL
.createTable(htd
, new byte[][] { TEST_FAM
}, UTIL
.getConfiguration());
427 String table1Snapshot1
= "Table1Snapshot1";
428 admin
.snapshot(table1Snapshot1
, TABLE_NAME
);
429 LOG
.debug("Snapshot1 completed.");
431 String table1Snapshot2
= "Table1Snapshot2";
432 admin
.snapshot(table1Snapshot2
, TABLE_NAME
);
433 LOG
.debug("Snapshot2 completed.");
435 String table2Snapshot1
= "Table2Snapshot1";
436 admin
.snapshot(table2Snapshot1
, tableName
);
437 LOG
.debug(table2Snapshot1
+ " completed.");
439 Pattern tableNamePattern
= Pattern
.compile("test.*");
440 admin
.deleteTableSnapshots(tableNamePattern
, MATCH_ALL
);
441 assertEquals(0, admin
.listTableSnapshots(tableNamePattern
, MATCH_ALL
).size());
444 if (admin
.tableExists(tableName
)) {
445 UTIL
.deleteTable(tableName
);
453 public void testDeleteTableSnapshotsWithRegex() throws Exception
{
455 Pattern tableNamePattern
= Pattern
.compile("test.*");
457 admin
= UTIL
.getAdmin();
459 String table1Snapshot1
= "Table1Snapshot1";
460 admin
.snapshot(table1Snapshot1
, TABLE_NAME
);
461 LOG
.debug("Snapshot1 completed.");
463 String table1Snapshot2
= "Table1Snapshot2";
464 admin
.snapshot(table1Snapshot2
, TABLE_NAME
);
465 LOG
.debug("Snapshot2 completed.");
467 String table2Snapshot1
= "Table2Snapshot1";
468 admin
.snapshot(table2Snapshot1
, TABLE_NAME
);
469 LOG
.debug(table2Snapshot1
+ " completed.");
471 admin
.deleteTableSnapshots(tableNamePattern
, Pattern
.compile("Table1.*"));
472 assertEquals(1, admin
.listTableSnapshots(tableNamePattern
, MATCH_ALL
).size());
476 admin
.deleteTableSnapshots(tableNamePattern
, MATCH_ALL
);
477 } catch (SnapshotDoesNotExistException ignore
) {