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 table.close();
128 }
129
130 @After
131 public void tearDown() throws Exception {
132 TEST_UTIL.deleteTable(tableName);
133 SnapshotTestingUtils.deleteAllSnapshots(TEST_UTIL.getHBaseAdmin());
134 SnapshotTestingUtils.deleteArchiveDirectory(TEST_UTIL);
135 }
136
137 @Test
138 public void testRestoreSnapshot() throws IOException {
139 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
140 admin.disableTable(tableName);
141 admin.snapshot(snapshotName1, tableName);
142
143 admin.restoreSnapshot(snapshotName0);
144 admin.enableTable(tableName);
145 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
146
147
148 admin.disableTable(tableName);
149 admin.restoreSnapshot(emptySnapshot);
150 admin.enableTable(tableName);
151 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, 0);
152
153
154 admin.disableTable(tableName);
155 admin.restoreSnapshot(snapshotName1);
156 admin.enableTable(tableName);
157 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
158
159
160 TEST_UTIL.deleteTable(tableName);
161 admin.restoreSnapshot(snapshotName1);
162 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot1Rows);
163 }
164
165 @Test
166 public void testRestoreSchemaChange() throws Exception {
167 byte[] TEST_FAMILY2 = Bytes.toBytes("cf2");
168
169 HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
170
171
172 admin.disableTable(tableName);
173 admin.addColumn(tableName, new HColumnDescriptor(TEST_FAMILY2));
174 admin.enableTable(tableName);
175 assertEquals(2, table.getTableDescriptor().getFamilies().size());
176 HTableDescriptor htd = admin.getTableDescriptor(tableName);
177 assertEquals(2, htd.getFamilies().size());
178 SnapshotTestingUtils.loadData(TEST_UTIL, table, 500, TEST_FAMILY2);
179 long snapshot2Rows = snapshot1Rows + 500;
180 assertEquals(snapshot2Rows, TEST_UTIL.countRows(table));
181 assertEquals(500, TEST_UTIL.countRows(table, TEST_FAMILY2));
182 Set<String> fsFamilies = getFamiliesFromFS(tableName);
183 assertEquals(2, fsFamilies.size());
184 table.close();
185
186
187 admin.disableTable(tableName);
188 admin.snapshot(snapshotName2, tableName);
189
190
191 admin.restoreSnapshot(snapshotName0);
192 admin.enableTable(tableName);
193 assertEquals(1, table.getTableDescriptor().getFamilies().size());
194 try {
195 TEST_UTIL.countRows(table, TEST_FAMILY2);
196 fail("family '" + Bytes.toString(TEST_FAMILY2) + "' should not exists");
197 } catch (NoSuchColumnFamilyException e) {
198
199 }
200 assertEquals(snapshot0Rows, TEST_UTIL.countRows(table));
201 htd = admin.getTableDescriptor(tableName);
202 assertEquals(1, htd.getFamilies().size());
203 fsFamilies = getFamiliesFromFS(tableName);
204 assertEquals(1, fsFamilies.size());
205 table.close();
206
207
208 admin.disableTable(tableName);
209 admin.restoreSnapshot(snapshotName2);
210 admin.enableTable(tableName);
211 htd = admin.getTableDescriptor(tableName);
212 assertEquals(2, htd.getFamilies().size());
213 assertEquals(2, table.getTableDescriptor().getFamilies().size());
214 assertEquals(500, TEST_UTIL.countRows(table, TEST_FAMILY2));
215 assertEquals(snapshot2Rows, TEST_UTIL.countRows(table));
216 fsFamilies = getFamiliesFromFS(tableName);
217 assertEquals(2, fsFamilies.size());
218 table.close();
219 }
220
221 @Test
222 public void testCloneSnapshotOfCloned() throws IOException, InterruptedException {
223 TableName clonedTableName =
224 TableName.valueOf("clonedtb-" + System.currentTimeMillis());
225 admin.cloneSnapshot(snapshotName0, clonedTableName);
226 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
227 admin.disableTable(clonedTableName);
228 admin.snapshot(snapshotName2, clonedTableName);
229 TEST_UTIL.deleteTable(clonedTableName);
230 waitCleanerRun();
231
232 admin.cloneSnapshot(snapshotName2, clonedTableName);
233 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
234 TEST_UTIL.deleteTable(clonedTableName);
235 }
236
237 @Test
238 public void testCloneAndRestoreSnapshot() throws IOException, InterruptedException {
239 TEST_UTIL.deleteTable(tableName);
240 waitCleanerRun();
241
242 admin.cloneSnapshot(snapshotName0, tableName);
243 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
244 waitCleanerRun();
245
246 admin.disableTable(tableName);
247 admin.restoreSnapshot(snapshotName0);
248 admin.enableTable(tableName);
249 SnapshotTestingUtils.verifyRowCount(TEST_UTIL, tableName, snapshot0Rows);
250 }
251
252 @Test
253 public void testCorruptedSnapshot() throws IOException, InterruptedException {
254 SnapshotTestingUtils.corruptSnapshot(TEST_UTIL, Bytes.toString(snapshotName0));
255 TableName cloneName = TableName.valueOf("corruptedClone-" + System.currentTimeMillis());
256 try {
257 admin.cloneSnapshot(snapshotName0, cloneName);
258 fail("Expected CorruptedSnapshotException, got succeeded cloneSnapshot()");
259 } catch (CorruptedSnapshotException e) {
260
261
262 assertFalse(admin.tableExists(cloneName));
263 } catch (Exception e) {
264 fail("Expected CorruptedSnapshotException got: " + e);
265 }
266 }
267
268
269
270
271 private void waitCleanerRun() throws InterruptedException {
272 TEST_UTIL.getMiniHBaseCluster().getMaster().getHFileCleaner().choreForTesting();
273 }
274
275 private Set<String> getFamiliesFromFS(final TableName tableName) throws IOException {
276 MasterFileSystem mfs = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem();
277 Set<String> families = new HashSet<String>();
278 Path tableDir = FSUtils.getTableDir(mfs.getRootDir(), tableName);
279 for (Path regionDir: FSUtils.getRegionDirs(mfs.getFileSystem(), tableDir)) {
280 for (Path familyDir: FSUtils.getFamilyDirs(mfs.getFileSystem(), regionDir)) {
281 families.add(familyDir.getName());
282 }
283 }
284 return families;
285 }
286 }