1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import java.io.IOException;
22 import java.util.Arrays;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.fs.FileSystem;
28 import org.apache.hadoop.fs.Path;
29 import org.apache.hadoop.hbase.Cell;
30 import org.apache.hadoop.hbase.CellScanner;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.testclassification.LargeTests;
33 import org.apache.hadoop.hbase.TableName;
34 import org.apache.hadoop.hbase.mapreduce.TestTableSnapshotInputFormat;
35 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
36 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
37 import org.apache.hadoop.hbase.util.Bytes;
38 import org.apache.hadoop.hbase.util.FSUtils;
39 import org.junit.After;
40 import org.junit.Assert;
41 import org.junit.Test;
42 import org.junit.experimental.categories.Category;
43 import org.junit.Rule;
44 import org.junit.rules.TestName;
45
46 @Category(LargeTests.class)
47 public class TestTableSnapshotScanner {
48
49 private static final Log LOG = LogFactory.getLog(TestTableSnapshotInputFormat.class);
50 private final HBaseTestingUtility UTIL = new HBaseTestingUtility();
51 private static final int NUM_REGION_SERVERS = 2;
52 private static final byte[][] FAMILIES = {Bytes.toBytes("f1"), Bytes.toBytes("f2")};
53 public static byte[] bbb = Bytes.toBytes("bbb");
54 public static byte[] yyy = Bytes.toBytes("yyy");
55
56 private FileSystem fs;
57 private Path rootDir;
58
59 @Rule
60 public TestName name = new TestName();
61
62 public void setupCluster() throws Exception {
63 setupConf(UTIL.getConfiguration());
64 UTIL.startMiniCluster(NUM_REGION_SERVERS, true);
65 rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
66 fs = rootDir.getFileSystem(UTIL.getConfiguration());
67 }
68
69 public void tearDownCluster() throws Exception {
70 UTIL.shutdownMiniCluster();
71 }
72
73 private static void setupConf(Configuration conf) {
74
75 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
76 }
77
78 @After
79 public void tearDown() throws Exception {
80 }
81
82 public static void createTableAndSnapshot(HBaseTestingUtility util, TableName tableName,
83 String snapshotName, int numRegions)
84 throws Exception {
85 try {
86 util.deleteTable(tableName);
87 } catch(Exception ex) {
88
89 }
90
91 if (numRegions > 1) {
92 util.createTable(tableName, FAMILIES, 1, bbb, yyy, numRegions);
93 } else {
94 util.createTable(tableName, FAMILIES);
95 }
96 Admin admin = util.getHBaseAdmin();
97
98
99 HTable table = new HTable(util.getConfiguration(), tableName);
100 util.loadTable(table, FAMILIES);
101
102 Path rootDir = FSUtils.getRootDir(util.getConfiguration());
103 FileSystem fs = rootDir.getFileSystem(util.getConfiguration());
104
105 SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName,
106 Arrays.asList(FAMILIES), null, snapshotName, rootDir, fs, true);
107
108
109 byte[] value = Bytes.toBytes("after_snapshot_value");
110 util.loadTable(table, FAMILIES, value);
111
112
113 admin.flush(tableName);
114 table.close();
115 }
116
117 @Test
118 public void testNoDuplicateResultsWhenSplitting() throws Exception {
119 setupCluster();
120 TableName tableName = TableName.valueOf("testNoDuplicateResultsWhenSplitting");
121 String snapshotName = "testSnapshotBug";
122 try {
123 if (UTIL.getHBaseAdmin().tableExists(tableName)) {
124 UTIL.deleteTable(tableName);
125 }
126
127 UTIL.createTable(tableName, FAMILIES);
128 Admin admin = UTIL.getHBaseAdmin();
129
130
131 Table table = UTIL.getConnection().getTable(tableName);
132 UTIL.loadTable(table, FAMILIES);
133
134
135 admin.split(tableName, Bytes.toBytes("eee"));
136 TestTableSnapshotInputFormat.blockUntilSplitFinished(UTIL, tableName, 2);
137
138 Path rootDir = FSUtils.getRootDir(UTIL.getConfiguration());
139 FileSystem fs = rootDir.getFileSystem(UTIL.getConfiguration());
140
141 SnapshotTestingUtils.createSnapshotAndValidate(admin, tableName,
142 Arrays.asList(FAMILIES), null, snapshotName, rootDir, fs, true);
143
144
145 byte[] value = Bytes.toBytes("after_snapshot_value");
146 UTIL.loadTable(table, FAMILIES, value);
147
148
149 admin.flush(tableName);
150 table.close();
151
152 Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);
153 Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy);
154
155 TableSnapshotScanner scanner =
156 new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);
157
158 verifyScanner(scanner, bbb, yyy);
159 scanner.close();
160 } finally {
161 UTIL.getHBaseAdmin().deleteSnapshot(snapshotName);
162 UTIL.deleteTable(tableName);
163 tearDownCluster();
164 }
165 }
166
167
168 @Test
169 public void testScanLimit() throws Exception {
170 setupCluster();
171 final TableName tableName = TableName.valueOf(name.getMethodName());
172 final String snapshotName = tableName + "Snapshot";
173 TableSnapshotScanner scanner = null;
174 try {
175 createTableAndSnapshot(UTIL, tableName, snapshotName, 50);
176 Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);
177 Scan scan = new Scan().withStartRow(bbb).setLimit(100);
178
179 scanner = new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir, snapshotName, scan);
180 int count = 0;
181 while (true) {
182 Result result = scanner.next();
183 if (result == null) {
184 break;
185 }
186 count++;
187 }
188 Assert.assertEquals(100, count);
189 } finally {
190 if (scanner != null) {
191 scanner.close();
192 }
193 UTIL.getHBaseAdmin().deleteSnapshot(snapshotName);
194 UTIL.deleteTable(tableName);
195 tearDownCluster();
196 }
197 }
198
199 @Test
200 public void testWithSingleRegion() throws Exception {
201 testScanner(UTIL, "testWithSingleRegion", 1, false);
202 }
203
204 @Test
205 public void testWithMultiRegion() throws Exception {
206 testScanner(UTIL, "testWithMultiRegion", 10, false);
207 }
208
209 @Test
210 public void testWithOfflineHBaseMultiRegion() throws Exception {
211 testScanner(UTIL, "testWithMultiRegion", 20, true);
212 }
213
214 private void testScanner(HBaseTestingUtility util, String snapshotName, int numRegions,
215 boolean shutdownCluster) throws Exception {
216 setupCluster();
217 TableName tableName = TableName.valueOf("testScanner");
218 try {
219 createTableAndSnapshot(util, tableName, snapshotName, numRegions);
220
221 if (shutdownCluster) {
222 util.shutdownMiniHBaseCluster();
223 }
224
225 Path restoreDir = util.getDataTestDirOnTestFS(snapshotName);
226 Scan scan = new Scan(bbb, yyy);
227
228 TableSnapshotScanner scanner = new TableSnapshotScanner(UTIL.getConfiguration(), restoreDir,
229 snapshotName, scan);
230
231 verifyScanner(scanner, bbb, yyy);
232 scanner.close();
233 } finally {
234 if (!shutdownCluster) {
235 util.getHBaseAdmin().deleteSnapshot(snapshotName);
236 util.deleteTable(tableName);
237 tearDownCluster();
238 }
239 }
240 }
241
242 private void verifyScanner(ResultScanner scanner, byte[] startRow, byte[] stopRow)
243 throws IOException, InterruptedException {
244
245 HBaseTestingUtility.SeenRowTracker rowTracker =
246 new HBaseTestingUtility.SeenRowTracker(startRow, stopRow);
247
248 while (true) {
249 Result result = scanner.next();
250 if (result == null) {
251 break;
252 }
253 verifyRow(result);
254 rowTracker.addRow(result.getRow());
255 }
256
257
258 rowTracker.validate();
259 }
260
261 private static void verifyRow(Result result) throws IOException {
262 byte[] row = result.getRow();
263 CellScanner scanner = result.cellScanner();
264 while (scanner.advance()) {
265 Cell cell = scanner.current();
266
267
268 Assert.assertEquals(0, Bytes.compareTo(row, 0, row.length,
269 cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
270 }
271
272 for (int j = 0; j < FAMILIES.length; j++) {
273 byte[] actual = result.getValue(FAMILIES[j], FAMILIES[j]);
274 Assert.assertArrayEquals("Row in snapshot does not match, expected:" + Bytes.toString(row)
275 + " ,actual:" + Bytes.toString(actual), row, actual);
276 }
277 }
278
279 }