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  package org.apache.hadoop.hbase.client;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.fail;
22  
23  import java.util.List;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.fs.FileSystem;
29  import org.apache.hadoop.fs.Path;
30  import org.apache.hadoop.hbase.HBaseTestingUtility;
31  import org.apache.hadoop.hbase.HConstants;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.TableNotFoundException;
34  import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
35  import org.apache.hadoop.hbase.mob.MobConstants;
36  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
37  import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;
38  import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils;
39  import org.apache.hadoop.hbase.snapshot.SnapshotCreationException;
40  import org.apache.hadoop.hbase.snapshot.SnapshotManifestV1;
41  import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
42  import org.apache.hadoop.hbase.testclassification.LargeTests;
43  import org.apache.hadoop.hbase.util.Bytes;
44  import org.apache.hadoop.hbase.util.FSUtils;
45  import org.junit.After;
46  import org.junit.AfterClass;
47  import org.junit.Before;
48  import org.junit.BeforeClass;
49  import org.junit.Test;
50  import org.junit.experimental.categories.Category;
51  
52  import com.google.common.collect.Lists;
53  
54  /**
55   * Test create/using/deleting snapshots from the client
56   * <p>
57   * This is an end-to-end test for the snapshot utility
58   */
59  @Category(LargeTests.class)
60  public class TestMobSnapshotFromClient {
61    private static final Log LOG = LogFactory.getLog(TestSnapshotFromClient.class);
62    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
63    private static final int NUM_RS = 2;
64    private static final String STRING_TABLE_NAME = "test";
65    protected static final byte[] TEST_FAM = Bytes.toBytes("fam");
66    protected static final TableName TABLE_NAME =
67        TableName.valueOf(STRING_TABLE_NAME);
68  
69    /**
70     * Setup the config for the cluster
71     * @throws Exception on failure
72     */
73    @BeforeClass
74    public static void setupCluster() throws Exception {
75      setupConf(UTIL.getConfiguration());
76      UTIL.startMiniCluster(NUM_RS);
77    }
78  
79    private static void setupConf(Configuration conf) {
80      // disable the ui
81      conf.setInt("hbase.regionsever.info.port", -1);
82      // change the flush size to a small amount, regulating number of store files
83      conf.setInt("hbase.hregion.memstore.flush.size", 25000);
84      // so make sure we get a compaction when doing a load, but keep around some
85      // files in the store
86      conf.setInt("hbase.hstore.compaction.min", 10);
87      conf.setInt("hbase.hstore.compactionThreshold", 10);
88      // block writes if we get to 12 store files
89      conf.setInt("hbase.hstore.blockingStoreFiles", 12);
90      // Enable snapshot
91      conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
92      conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
93        ConstantSizeRegionSplitPolicy.class.getName());
94      conf.setInt(MobConstants.MOB_FILE_CACHE_SIZE_KEY, 0);
95      conf.setInt("hfile.format.version", 3);
96    }
97  
98    @Before
99    public void setup() throws Exception {
100     MobSnapshotTestingUtils.createMobTable(UTIL, TABLE_NAME, getNumReplicas(), TEST_FAM);
101   }
102 
103   protected int getNumReplicas() {
104     return 1;
105   }
106 
107   @After
108   public void tearDown() throws Exception {
109     UTIL.deleteTable(TABLE_NAME);
110     SnapshotTestingUtils.deleteAllSnapshots(UTIL.getHBaseAdmin());
111     SnapshotTestingUtils.deleteArchiveDirectory(UTIL);
112   }
113 
114   @AfterClass
115   public static void cleanupTest() throws Exception {
116     try {
117       UTIL.shutdownMiniCluster();
118     } catch (Exception e) {
119       LOG.warn("failure shutting down cluster", e);
120     }
121   }
122 
123   /**
124    * Test snapshotting not allowed hbase:meta and -ROOT-
125    * @throws Exception
126    */
127   @Test (timeout=300000)
128   public void testMetaTablesSnapshot() throws Exception {
129     Admin admin = UTIL.getHBaseAdmin();
130     byte[] snapshotName = Bytes.toBytes("metaSnapshot");
131 
132     try {
133       admin.snapshot(snapshotName, TableName.META_TABLE_NAME);
134       fail("taking a snapshot of hbase:meta should not be allowed");
135     } catch (IllegalArgumentException e) {
136       // expected
137     }
138   }
139 
140   /**
141    * Test HBaseAdmin#deleteSnapshots(String) which deletes snapshots whose names match the parameter
142    *
143    * @throws Exception
144    */
145   @Test (timeout=300000)
146   public void testSnapshotDeletionWithRegex() throws Exception {
147     Admin admin = UTIL.getHBaseAdmin();
148     // make sure we don't fail on listing snapshots
149     SnapshotTestingUtils.assertNoSnapshots(admin);
150 
151     // put some stuff in the table
152     HTable table = new HTable(UTIL.getConfiguration(), TABLE_NAME);
153     UTIL.loadTable(table, TEST_FAM);
154     table.close();
155 
156     byte[] snapshot1 = Bytes.toBytes("TableSnapshot1");
157     admin.snapshot(snapshot1, TABLE_NAME);
158     LOG.debug("Snapshot1 completed.");
159 
160     byte[] snapshot2 = Bytes.toBytes("TableSnapshot2");
161     admin.snapshot(snapshot2, TABLE_NAME);
162     LOG.debug("Snapshot2 completed.");
163 
164     String snapshot3 = "3rdTableSnapshot";
165     admin.snapshot(Bytes.toBytes(snapshot3), TABLE_NAME);
166     LOG.debug(snapshot3 + " completed.");
167 
168     // delete the first two snapshots
169     admin.deleteSnapshots("TableSnapshot.*");
170     List<SnapshotDescription> snapshots = admin.listSnapshots();
171     assertEquals(1, snapshots.size());
172     assertEquals(snapshots.get(0).getName(), snapshot3);
173 
174     admin.deleteSnapshot(snapshot3);
175     admin.close();
176   }
177   /**
178    * Test snapshotting a table that is offline
179    * @throws Exception
180    */
181   @Test (timeout=300000)
182   public void testOfflineTableSnapshot() throws Exception {
183     Admin admin = UTIL.getHBaseAdmin();
184     // make sure we don't fail on listing snapshots
185     SnapshotTestingUtils.assertNoSnapshots(admin);
186 
187     // put some stuff in the table
188     HTable table = new HTable(UTIL.getConfiguration(), TABLE_NAME);
189     UTIL.loadTable(table, TEST_FAM, false);
190 
191     LOG.debug("FS state before disable:");
192     FSUtils.logFileSystemState(UTIL.getTestFileSystem(),
193       FSUtils.getRootDir(UTIL.getConfiguration()), LOG);
194     // XXX if this is flakey, might want to consider using the async version and looping as
195     // disableTable can succeed and still timeout.
196     admin.disableTable(TABLE_NAME);
197 
198     LOG.debug("FS state before snapshot:");
199     FSUtils.logFileSystemState(UTIL.getTestFileSystem(),
200       FSUtils.getRootDir(UTIL.getConfiguration()), LOG);
201 
202     // take a snapshot of the disabled table
203     final String SNAPSHOT_NAME = "offlineTableSnapshot";
204     byte[] snapshot = Bytes.toBytes(SNAPSHOT_NAME);
205 
206     SnapshotDescription desc = SnapshotDescription.newBuilder()
207       .setType(SnapshotDescription.Type.DISABLED)
208       .setTable(STRING_TABLE_NAME)
209       .setName(SNAPSHOT_NAME)
210       .setVersion(SnapshotManifestV1.DESCRIPTOR_VERSION)
211       .build();
212     admin.snapshot(desc);
213     LOG.debug("Snapshot completed.");
214 
215     // make sure we have the snapshot
216     List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertOneSnapshotThatMatches(admin,
217       snapshot, TABLE_NAME);
218 
219     // make sure its a valid snapshot
220     FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
221     Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
222     LOG.debug("FS state after snapshot:");
223     FSUtils.logFileSystemState(UTIL.getTestFileSystem(),
224       FSUtils.getRootDir(UTIL.getConfiguration()), LOG);
225 
226     SnapshotTestingUtils.confirmSnapshotValid(snapshots.get(0), TABLE_NAME, TEST_FAM, rootDir,
227       admin, fs);
228 
229     admin.deleteSnapshot(snapshot);
230     snapshots = admin.listSnapshots();
231     SnapshotTestingUtils.assertNoSnapshots(admin);
232   }
233 
234   @Test (timeout=300000)
235   public void testSnapshotFailsOnNonExistantTable() throws Exception {
236     Admin admin = UTIL.getHBaseAdmin();
237     // make sure we don't fail on listing snapshots
238     SnapshotTestingUtils.assertNoSnapshots(admin);
239     String tableName = "_not_a_table";
240 
241     // make sure the table doesn't exist
242     boolean fail = false;
243     do {
244     try {
245       admin.getTableDescriptor(TableName.valueOf(tableName));
246       fail = true;
247           LOG.error("Table:" + tableName + " already exists, checking a new name");
248       tableName = tableName+"!";
249     } catch (TableNotFoundException e) {
250       fail = false;
251       }
252     } while (fail);
253 
254     // snapshot the non-existant table
255     try {
256       admin.snapshot("fail", TableName.valueOf(tableName));
257       fail("Snapshot succeeded even though there is not table.");
258     } catch (SnapshotCreationException e) {
259       LOG.info("Correctly failed to snapshot a non-existant table:" + e.getMessage());
260     }
261   }
262 
263   @Test (timeout=300000)
264   public void testOfflineTableSnapshotWithEmptyRegions() throws Exception {
265     // test with an empty table with one region
266 
267     Admin admin = UTIL.getHBaseAdmin();
268     // make sure we don't fail on listing snapshots
269     SnapshotTestingUtils.assertNoSnapshots(admin);
270 
271     LOG.debug("FS state before disable:");
272     FSUtils.logFileSystemState(UTIL.getTestFileSystem(),
273       FSUtils.getRootDir(UTIL.getConfiguration()), LOG);
274     admin.disableTable(TABLE_NAME);
275 
276     LOG.debug("FS state before snapshot:");
277     FSUtils.logFileSystemState(UTIL.getTestFileSystem(),
278       FSUtils.getRootDir(UTIL.getConfiguration()), LOG);
279 
280     // take a snapshot of the disabled table
281     byte[] snapshot = Bytes.toBytes("testOfflineTableSnapshotWithEmptyRegions");
282     admin.snapshot(snapshot, TABLE_NAME);
283     LOG.debug("Snapshot completed.");
284 
285     // make sure we have the snapshot
286     List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertOneSnapshotThatMatches(admin,
287       snapshot, TABLE_NAME);
288 
289     // make sure its a valid snapshot
290     FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
291     Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
292     LOG.debug("FS state after snapshot:");
293     FSUtils.logFileSystemState(UTIL.getTestFileSystem(),
294       FSUtils.getRootDir(UTIL.getConfiguration()), LOG);
295 
296     List<byte[]> emptyCfs = Lists.newArrayList(TEST_FAM); // no file in the region
297     List<byte[]> nonEmptyCfs = Lists.newArrayList();
298     SnapshotTestingUtils.confirmSnapshotValid(snapshots.get(0), TABLE_NAME, nonEmptyCfs, emptyCfs,
299       rootDir, admin, fs);
300 
301     admin.deleteSnapshot(snapshot);
302     snapshots = admin.listSnapshots();
303     SnapshotTestingUtils.assertNoSnapshots(admin);
304   }
305 }