View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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      // Enable snapshot
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        // ignore
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      // put some stuff in the table
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     // load different values
109     byte[] value = Bytes.toBytes("after_snapshot_value");
110     util.loadTable(table, FAMILIES, value);
111 
112     // cause flush to create new files in the region
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       // put some stuff in the table
131       Table table = UTIL.getConnection().getTable(tableName);
132       UTIL.loadTable(table, FAMILIES);
133 
134       // split to 2 regions
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       // load different values
145       byte[] value = Bytes.toBytes("after_snapshot_value");
146       UTIL.loadTable(table, FAMILIES, value);
147 
148       // cause flush to create new files in the region
149       admin.flush(tableName);
150       table.close();
151 
152       Path restoreDir = UTIL.getDataTestDirOnTestFS(snapshotName);
153       Scan scan = new Scan().withStartRow(bbb).withStopRow(yyy); // limit the scan
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); // limit the scan
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); // limit the scan
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     // validate all rows are seen
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       //assert that all Cells in the Result have the same key
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 }