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