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.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.fs.Path;
31 import org.apache.hadoop.hbase.TableName;
32 import org.apache.hadoop.hbase.HBaseTestingUtility;
33 import org.apache.hadoop.hbase.HColumnDescriptor;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.HTableDescriptor;
36 import org.apache.hadoop.hbase.LargeTests;
37 import org.apache.hadoop.hbase.master.MasterFileSystem;
38 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
39 import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
40 import org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException;
41 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.apache.hadoop.hbase.util.FSUtils;
44 import org.junit.After;
45 import org.junit.AfterClass;
46 import org.junit.Before;
47 import org.junit.BeforeClass;
48 import org.junit.Test;
49 import org.junit.experimental.categories.Category;
50
51
52
53
54 @Category(LargeTests.class)
55 public class TestRestoreSnapshotFromClient {
56 final Log LOG = LogFactory.getLog(getClass());
57
58 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
59
60 private final byte[] FAMILY = Bytes.toBytes("cf");
61
62 private byte[] emptySnapshot;
63 private byte[] snapshotName0;
64 private byte[] snapshotName1;
65 private byte[] snapshotName2;
66 private int snapshot0Rows;
67 private int snapshot1Rows;
68 private TableName tableName;
69 private HBaseAdmin admin;
70
71 @BeforeClass
72 public static void setUpBeforeClass() throws Exception {
73 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
74 TEST_UTIL.getConfiguration().setBoolean("hbase.online.schema.update.enable", true);
75 TEST_UTIL.getConfiguration().setInt("hbase.hstore.compactionThreshold", 10);
76 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
77 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
78 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6);
79 TEST_UTIL.getConfiguration().setBoolean(
80 "hbase.master.enabletable.roundrobin", true);
81 TEST_UTIL.startMiniCluster(3);
82 }
83
84 @AfterClass
85 public static void tearDownAfterClass() throws Exception {
86 TEST_UTIL.shutdownMiniCluster();
87 }
88
89
90
91
92
93
94 @Before
95 public void setup() throws Exception {
96 this.admin = TEST_UTIL.getHBaseAdmin();
97
98 long tid = System.currentTimeMillis();
99 tableName =
100 TableName.valueOf("testtb-" + tid);
101 emptySnapshot = Bytes.toBytes("emptySnaptb-" + tid);
102 snapshotName0 = Bytes.toBytes("snaptb0-" + tid);
103 snapshotName1 = Bytes.toBytes("snaptb1-" + tid);
104 snapshotName2 = Bytes.toBytes("snaptb2-" + tid);
105
106
107 SnapshotTestingUtils.createTable(TEST_UTIL, tableName, FAMILY);
108 admin.disableTable(tableName);
109
110
111 admin.snapshot(emptySnapshot, tableName);
112
113 HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
114
115 admin.enableTable(tableName);
116 SnapshotTestingUtils.loadData(TEST_UTIL, table, 500, FAMILY);
117 snapshot0Rows = TEST_UTIL.countRows(table);
118 admin.disableTable(tableName);
119
120
121 admin.snapshot(snapshotName0, tableName);
122
123
124 admin.enableTable(tableName);
125 SnapshotTestingUtils.loadData(TEST_UTIL, table, 500, FAMILY);
126 snapshot1Rows = TEST_UTIL.countRows(table);
127 admin.disableTable(tableName);
128
129
130 admin.snapshot(snapshotName1, tableName);
131
132
133 admin.enableTable(tableName);
134 table.close();
135 }
136
137 @After
138 public void tearDown() throws Exception {
139 TEST_UTIL.deleteTable(tableName);
140 SnapshotTestingUtils.deleteAllSnapshots(TEST_UTIL.getHBaseAdmin());
141 SnapshotTestingUtils.deleteArchiveDirectory(TEST_UTIL);
142 }
143
144 @Test
145 public void testRestoreSnapshot() throws IOException {
146 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
147
148
149 admin.disableTable(tableName);
150 admin.restoreSnapshot(snapshotName0);
151 admin.enableTable(tableName);
152 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
153
154
155 admin.disableTable(tableName);
156 admin.restoreSnapshot(emptySnapshot);
157 admin.enableTable(tableName);
158 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, 0);
159
160
161 admin.disableTable(tableName);
162 admin.restoreSnapshot(snapshotName1);
163 admin.enableTable(tableName);
164 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
165
166
167 TEST_UTIL.deleteTable(tableName);
168 admin.restoreSnapshot(snapshotName1);
169 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
170 }
171
172 @Test
173 public void testRestoreSchemaChange() throws Exception {
174 byte[] TEST_FAMILY2 = Bytes.toBytes("cf2");
175
176 HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
177
178
179 admin.disableTable(tableName);
180 admin.addColumn(tableName, new HColumnDescriptor(TEST_FAMILY2));
181 admin.enableTable(tableName);
182 assertEquals(2, table.getTableDescriptor().getFamilies().size());
183 HTableDescriptor htd = admin.getTableDescriptor(tableName);
184 assertEquals(2, htd.getFamilies().size());
185 SnapshotTestingUtils.loadData(TEST_UTIL, table, 500, TEST_FAMILY2);
186 long snapshot2Rows = snapshot1Rows + 500;
187 assertEquals(snapshot2Rows, TEST_UTIL.countRows(table));
188 assertEquals(500, TEST_UTIL.countRows(table, TEST_FAMILY2));
189 Set<String> fsFamilies = getFamiliesFromFS(tableName);
190 assertEquals(2, fsFamilies.size());
191 table.close();
192
193
194 admin.disableTable(tableName);
195 admin.snapshot(snapshotName2, tableName);
196
197
198 admin.restoreSnapshot(snapshotName0);
199 admin.enableTable(tableName);
200 assertEquals(1, table.getTableDescriptor().getFamilies().size());
201 try {
202 TEST_UTIL.countRows(table, TEST_FAMILY2);
203 fail("family '" + Bytes.toString(TEST_FAMILY2) + "' should not exists");
204 } catch (NoSuchColumnFamilyException e) {
205
206 }
207 assertEquals(snapshot0Rows, TEST_UTIL.countRows(table));
208 htd = admin.getTableDescriptor(tableName);
209 assertEquals(1, htd.getFamilies().size());
210 fsFamilies = getFamiliesFromFS(tableName);
211 assertEquals(1, fsFamilies.size());
212 table.close();
213
214
215 admin.disableTable(tableName);
216 admin.restoreSnapshot(snapshotName2);
217 admin.enableTable(tableName);
218 htd = admin.getTableDescriptor(tableName);
219 assertEquals(2, htd.getFamilies().size());
220 assertEquals(2, table.getTableDescriptor().getFamilies().size());
221 assertEquals(500, TEST_UTIL.countRows(table, TEST_FAMILY2));
222 assertEquals(snapshot2Rows, TEST_UTIL.countRows(table));
223 fsFamilies = getFamiliesFromFS(tableName);
224 assertEquals(2, fsFamilies.size());
225 table.close();
226 }
227
228 @Test
229 public void testCloneSnapshotOfCloned() throws IOException, InterruptedException {
230 TableName clonedTableName =
231 TableName.valueOf("clonedtb-" + System.currentTimeMillis());
232 admin.cloneSnapshot(snapshotName0, clonedTableName);
233 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
234 admin.disableTable(clonedTableName);
235 admin.snapshot(snapshotName2, clonedTableName);
236 TEST_UTIL.deleteTable(clonedTableName);
237 waitCleanerRun();
238
239 admin.cloneSnapshot(snapshotName2, clonedTableName);
240 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
241 TEST_UTIL.deleteTable(clonedTableName);
242 }
243
244 @Test
245 public void testCloneAndRestoreSnapshot() throws IOException, InterruptedException {
246 TEST_UTIL.deleteTable(tableName);
247 waitCleanerRun();
248
249 admin.cloneSnapshot(snapshotName0, tableName);
250 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
251 waitCleanerRun();
252
253 admin.disableTable(tableName);
254 admin.restoreSnapshot(snapshotName0);
255 admin.enableTable(tableName);
256 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
257 }
258
259 @Test
260 public void testCorruptedSnapshot() throws IOException, InterruptedException {
261 SnapshotTestingUtils.corruptSnapshot(TEST_UTIL, Bytes.toString(snapshotName0));
262 TableName cloneName = TableName.valueOf("corruptedClone-" + System.currentTimeMillis());
263 try {
264 admin.cloneSnapshot(snapshotName0, cloneName);
265 fail("Expected CorruptedSnapshotException, got succeeded cloneSnapshot()");
266 } catch (CorruptedSnapshotException e) {
267
268
269 assertFalse(admin.tableExists(cloneName));
270 } catch (Exception e) {
271 fail("Expected CorruptedSnapshotException got: " + e);
272 }
273 }
274
275
276
277
278 private void waitCleanerRun() throws InterruptedException {
279 TEST_UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().choreForTesting();
280 }
281
282 private Set<String> getFamiliesFromFS(final TableName tableName) throws IOException {
283 MasterFileSystem mfs = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem();
284 Set<String> families = new HashSet<String>();
285 Path tableDir = FSUtils.getTableDir(mfs.getRootDir(), tableName);
286 for (Path regionDir: FSUtils.getRegionDirs(mfs.getFileSystem(), tableDir)) {
287 for (Path familyDir: FSUtils.getFamilyDirs(mfs.getFileSystem(), regionDir)) {
288 families.add(familyDir.getName());
289 }
290 }
291 return families;
292 }
293 }