1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.client;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.fail;
23
24 import java.io.IOException;
25 import java.util.HashSet;
26 import java.util.Set;
27
28 import org.apache.hadoop.fs.Path;
29 import org.apache.hadoop.hbase.CategoryBasedTimeout;
30 import org.apache.hadoop.hbase.HBaseTestingUtility;
31 import org.apache.hadoop.hbase.HColumnDescriptor;
32 import org.apache.hadoop.hbase.HConstants;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.HTableDescriptor;
35 import org.apache.hadoop.hbase.MetaTableAccessor;
36 import org.apache.hadoop.hbase.testclassification.LargeTests;
37 import org.apache.hadoop.hbase.TableName;
38 import org.apache.hadoop.hbase.Waiter;
39 import org.apache.hadoop.hbase.master.AssignmentManager;
40 import org.apache.hadoop.hbase.master.MasterFileSystem;
41 import org.apache.hadoop.hbase.master.RegionState;
42 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
43 import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
44 import org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException;
45 import org.apache.hadoop.hbase.snapshot.SnapshotDoesNotExistException;
46 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
47 import org.apache.hadoop.hbase.util.Bytes;
48 import org.apache.hadoop.hbase.util.FSUtils;
49 import org.junit.After;
50 import org.junit.AfterClass;
51 import org.junit.Before;
52 import org.junit.BeforeClass;
53 import org.junit.Rule;
54 import org.junit.Test;
55 import org.junit.experimental.categories.Category;
56 import org.junit.rules.TestRule;
57
58
59
60
61 @Category(LargeTests.class)
62 public class TestRestoreSnapshotFromClient {
63 @Rule public final TestRule timeout = CategoryBasedTimeout.builder()
64 .withTimeout(this.getClass())
65 .withLookingForStuckThread(true)
66 .build();
67
68 protected final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
69
70 protected final byte[] FAMILY = Bytes.toBytes("cf");
71
72 protected byte[] emptySnapshot;
73 protected byte[] snapshotName0;
74 protected byte[] snapshotName1;
75 protected byte[] snapshotName2;
76 protected int snapshot0Rows;
77 protected int snapshot1Rows;
78 protected TableName tableName;
79 protected Admin admin;
80
81 @BeforeClass
82 public static void setUpBeforeClass() throws Exception {
83 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
84 TEST_UTIL.getConfiguration().setBoolean("hbase.online.schema.update.enable", true);
85 TEST_UTIL.getConfiguration().setInt("hbase.hstore.compactionThreshold", 10);
86 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
87 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
88 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6);
89 TEST_UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true);
90
91 TEST_UTIL.getConfiguration().setLong("hbase.catalogjanitor.interval", 1800000);
92 TEST_UTIL.startMiniCluster(3);
93 }
94
95 @AfterClass
96 public static void tearDownAfterClass() throws Exception {
97 TEST_UTIL.shutdownMiniCluster();
98 }
99
100
101
102
103
104
105 @Before
106 public void setup() throws Exception {
107 this.admin = TEST_UTIL.getHBaseAdmin();
108
109 long tid = System.currentTimeMillis();
110 tableName =
111 TableName.valueOf("testtb-" + tid);
112 emptySnapshot = Bytes.toBytes("emptySnaptb-" + tid);
113 snapshotName0 = Bytes.toBytes("snaptb0-" + tid);
114 snapshotName1 = Bytes.toBytes("snaptb1-" + tid);
115 snapshotName2 = Bytes.toBytes("snaptb2-" + tid);
116
117
118 SnapshotTestingUtils.createTable(TEST_UTIL, tableName, getNumReplicas(), FAMILY);
119 admin.disableTable(tableName);
120
121
122 admin.snapshot(emptySnapshot, tableName);
123
124
125 admin.enableTable(tableName);
126 SnapshotTestingUtils.loadData(TEST_UTIL, tableName, 500, FAMILY);
127 try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
128 snapshot0Rows = TEST_UTIL.countRows(table);
129 }
130 admin.disableTable(tableName);
131
132
133 admin.snapshot(snapshotName0, tableName);
134
135
136 admin.enableTable(tableName);
137 SnapshotTestingUtils.loadData(TEST_UTIL, tableName, 500, FAMILY);
138 try (Table table = TEST_UTIL.getConnection().getTable(tableName)) {
139 snapshot1Rows = TEST_UTIL.countRows(table);
140 }
141 }
142
143 @After
144 public void tearDown() throws Exception {
145 TEST_UTIL.deleteTable(tableName);
146 SnapshotTestingUtils.deleteAllSnapshots(TEST_UTIL.getHBaseAdmin());
147 SnapshotTestingUtils.deleteArchiveDirectory(TEST_UTIL);
148 }
149
150 @Test
151 public void testRestoreSnapshot() throws IOException {
152 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
153 admin.disableTable(tableName);
154 admin.snapshot(snapshotName1, tableName);
155
156 admin.restoreSnapshot(snapshotName0);
157 admin.enableTable(tableName);
158 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
159 SnapshotTestingUtils.verifyReplicasCameOnline(tableName, admin, getNumReplicas());
160
161
162 admin.disableTable(tableName);
163 admin.restoreSnapshot(emptySnapshot);
164 admin.enableTable(tableName);
165 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, 0);
166 SnapshotTestingUtils.verifyReplicasCameOnline(tableName, admin, getNumReplicas());
167
168
169 admin.disableTable(tableName);
170 admin.restoreSnapshot(snapshotName1);
171 admin.enableTable(tableName);
172 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
173 SnapshotTestingUtils.verifyReplicasCameOnline(tableName, admin, getNumReplicas());
174
175
176 TEST_UTIL.deleteTable(tableName);
177 admin.restoreSnapshot(snapshotName1);
178 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
179 SnapshotTestingUtils.verifyReplicasCameOnline(tableName, admin, getNumReplicas());
180 }
181
182 protected int getNumReplicas() {
183 return 1;
184 }
185
186 @Test
187 public void testRestoreSchemaChange() throws Exception {
188 byte[] TEST_FAMILY2 = Bytes.toBytes("cf2");
189
190 HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
191
192
193 admin.disableTable(tableName);
194 admin.addColumn(tableName, new HColumnDescriptor(TEST_FAMILY2));
195 admin.enableTable(tableName);
196 assertEquals(2, table.getTableDescriptor().getFamilies().size());
197 HTableDescriptor htd = admin.getTableDescriptor(tableName);
198 assertEquals(2, htd.getFamilies().size());
199 SnapshotTestingUtils.loadData(TEST_UTIL, tableName, 500, TEST_FAMILY2);
200 long snapshot2Rows = snapshot1Rows + 500;
201 assertEquals(snapshot2Rows, TEST_UTIL.countRows(table));
202 assertEquals(500, TEST_UTIL.countRows(table, TEST_FAMILY2));
203 Set<String> fsFamilies = getFamiliesFromFS(tableName);
204 assertEquals(2, fsFamilies.size());
205
206
207 admin.disableTable(tableName);
208 admin.snapshot(snapshotName2, tableName);
209
210
211 admin.restoreSnapshot(snapshotName0);
212 admin.enableTable(tableName);
213 assertEquals(1, table.getTableDescriptor().getFamilies().size());
214 try {
215 TEST_UTIL.countRows(table, TEST_FAMILY2);
216 fail("family '" + Bytes.toString(TEST_FAMILY2) + "' should not exists");
217 } catch (NoSuchColumnFamilyException e) {
218
219 }
220 assertEquals(snapshot0Rows, TEST_UTIL.countRows(table));
221 htd = admin.getTableDescriptor(tableName);
222 assertEquals(1, htd.getFamilies().size());
223 fsFamilies = getFamiliesFromFS(tableName);
224 assertEquals(1, fsFamilies.size());
225
226
227 admin.disableTable(tableName);
228 admin.restoreSnapshot(snapshotName2);
229 admin.enableTable(tableName);
230 htd = admin.getTableDescriptor(tableName);
231 assertEquals(2, htd.getFamilies().size());
232 assertEquals(2, table.getTableDescriptor().getFamilies().size());
233 assertEquals(500, TEST_UTIL.countRows(table, TEST_FAMILY2));
234 assertEquals(snapshot2Rows, TEST_UTIL.countRows(table));
235 fsFamilies = getFamiliesFromFS(tableName);
236 assertEquals(2, fsFamilies.size());
237 table.close();
238 }
239
240 @Test
241 public void testCloneSnapshotOfCloned() throws IOException, InterruptedException {
242 TableName clonedTableName =
243 TableName.valueOf("clonedtb-" + System.currentTimeMillis());
244 admin.cloneSnapshot(snapshotName0, clonedTableName);
245 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
246 SnapshotTestingUtils.verifyReplicasCameOnline(clonedTableName, admin, getNumReplicas());
247 admin.disableTable(clonedTableName);
248 admin.snapshot(snapshotName2, clonedTableName);
249 TEST_UTIL.deleteTable(clonedTableName);
250 waitCleanerRun();
251
252 admin.cloneSnapshot(snapshotName2, clonedTableName);
253 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
254 SnapshotTestingUtils.verifyReplicasCameOnline(clonedTableName, admin, getNumReplicas());
255 TEST_UTIL.deleteTable(clonedTableName);
256 }
257
258 @Test
259 public void testCloneAndRestoreSnapshot() throws IOException, InterruptedException {
260 TEST_UTIL.deleteTable(tableName);
261 waitCleanerRun();
262
263 admin.cloneSnapshot(snapshotName0, tableName);
264 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
265 SnapshotTestingUtils.verifyReplicasCameOnline(tableName, admin, getNumReplicas());
266 waitCleanerRun();
267
268 admin.disableTable(tableName);
269 admin.restoreSnapshot(snapshotName0);
270 admin.enableTable(tableName);
271 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
272 SnapshotTestingUtils.verifyReplicasCameOnline(tableName, admin, getNumReplicas());
273 }
274
275 @Test
276 public void testCorruptedSnapshot() throws IOException, InterruptedException {
277 SnapshotTestingUtils.corruptSnapshot(TEST_UTIL, Bytes.toString(snapshotName0));
278 TableName cloneName = TableName.valueOf("corruptedClone-" + System.currentTimeMillis());
279 try {
280 admin.cloneSnapshot(snapshotName0, cloneName);
281 fail("Expected CorruptedSnapshotException, got succeeded cloneSnapshot()");
282 } catch (CorruptedSnapshotException e) {
283
284
285 assertFalse(admin.tableExists(cloneName));
286 } catch (Exception e) {
287 fail("Expected CorruptedSnapshotException got: " + e);
288 }
289 }
290
291 @Test(timeout = 300000)
292 public void testRestoreSnapshotAfterSplit() throws Exception {
293 Admin admin = null;
294 try {
295 admin = TEST_UTIL.getHBaseAdmin();
296 final int regionReplication = admin.getTableDescriptor(tableName).getRegionReplication();
297
298 final int primaryRegionCountBeforeSplit = MetaTableAccessor
299 .getTableRegions(TEST_UTIL.getZooKeeperWatcher(), TEST_UTIL.getConnection(), tableName)
300 .size() / regionReplication;
301
302 admin.split(tableName, "m".getBytes());
303 final AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager();
304
305 TEST_UTIL.waitFor(60000, 500, new Waiter.Predicate<IOException>() {
306 @Override
307 public boolean evaluate() throws IOException {
308 return am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OPEN)
309 .size() == ((primaryRegionCountBeforeSplit + 1) * regionReplication);
310 }
311 });
312
313 int regionCountAfterSplit = MetaTableAccessor
314 .getTableRegions(TEST_UTIL.getZooKeeperWatcher(), TEST_UTIL.getConnection(), tableName)
315 .size() / regionReplication;
316
317 assertEquals(primaryRegionCountBeforeSplit + 2, regionCountAfterSplit);
318
319 String snapshotName = "testRestoreSnapshotAfterSplit-snap";
320
321 admin.snapshot(snapshotName, tableName);
322 assertEquals(1,
323 admin.listTableSnapshots("testtb-.*", "testRestoreSnapshotAfterSplit-snap*").size());
324
325 admin.disableTable(tableName);
326 admin.restoreSnapshot(snapshotName);
327
328 int regionCountAfterRestoreSnapshot = MetaTableAccessor
329 .getTableRegions(TEST_UTIL.getZooKeeperWatcher(), TEST_UTIL.getConnection(), tableName)
330 .size();
331 assertEquals(primaryRegionCountBeforeSplit + 2, regionCountAfterRestoreSnapshot);
332
333
334 admin.enableTable(tableName);
335 assertEquals((primaryRegionCountBeforeSplit + 1) * regionReplication,
336 am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OPEN).size());
337
338 } finally {
339 if (admin != null) {
340 try {
341 admin.deleteTableSnapshots("testtb-.*", "testRestoreSnapshotAfterSplit-snap*");
342 } catch (SnapshotDoesNotExistException ignore) {
343 }
344 admin.close();
345 }
346 }
347 }
348
349
350
351
352 private void waitCleanerRun() throws InterruptedException {
353 TEST_UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().choreForTesting();
354 }
355
356 private Set<String> getFamiliesFromFS(final TableName tableName) throws IOException {
357 MasterFileSystem mfs = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem();
358 Set<String> families = new HashSet<String>();
359 Path tableDir = FSUtils.getTableDir(mfs.getRootDir(), tableName);
360 for (Path regionDir: FSUtils.getRegionDirs(mfs.getFileSystem(), tableDir)) {
361 for (Path familyDir: FSUtils.getFamilyDirs(mfs.getFileSystem(), regionDir)) {
362 families.add(familyDir.getName());
363 }
364 }
365 return families;
366 }
367
368 protected void splitRegion(final HRegionInfo regionInfo) throws IOException {
369 byte[][] splitPoints = Bytes.split(regionInfo.getStartKey(), regionInfo.getEndKey(), 1);
370 admin.split(regionInfo.getTable(), splitPoints[1]);
371 }
372 }