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.snapshot;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.io.IOException;
24  import java.util.List;
25  
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.fs.FSDataOutputStream;
28  import org.apache.hadoop.fs.FileSystem;
29  import org.apache.hadoop.fs.Path;
30  import org.apache.hadoop.hbase.Cell;
31  import org.apache.hadoop.hbase.CellUtil;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HColumnDescriptor;
34  import org.apache.hadoop.hbase.HRegionInfo;
35  import org.apache.hadoop.hbase.HTableDescriptor;
36  import org.apache.hadoop.hbase.TableName;
37  import org.apache.hadoop.hbase.client.HTable;
38  import org.apache.hadoop.hbase.client.Result;
39  import org.apache.hadoop.hbase.client.ResultScanner;
40  import org.apache.hadoop.hbase.client.Scan;
41  import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
42  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
43  import org.apache.hadoop.hbase.regionserver.BloomType;
44  import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
45  import org.apache.hadoop.hbase.util.Bytes;
46  import org.apache.hadoop.hbase.util.FSTableDescriptors;
47  import org.apache.hadoop.hbase.util.FSUtils;
48  import org.junit.Assert;
49  
50  public class MobSnapshotTestingUtils {
51  
52    /**
53     * Create the Mob Table.
54     */
55    public static void createMobTable(final HBaseTestingUtility util,
56        final TableName tableName, int regionReplication,
57        final byte[]... families) throws IOException, InterruptedException {
58      HTableDescriptor htd = new HTableDescriptor(tableName);
59      htd.setRegionReplication(regionReplication);
60      for (byte[] family : families) {
61        HColumnDescriptor hcd = new HColumnDescriptor(family);
62        hcd.setMobEnabled(true);
63        hcd.setMobThreshold(0L);
64        htd.addFamily(hcd);
65      }
66      byte[][] splitKeys = SnapshotTestingUtils.getSplitKeys();
67      util.getHBaseAdmin().createTable(htd, splitKeys);
68      SnapshotTestingUtils.waitForTableToBeOnline(util, tableName);
69      assertEquals((splitKeys.length + 1) * regionReplication, util
70          .getHBaseAdmin().getTableRegions(tableName).size());
71    }
72  
73    /**
74     * Create a Mob table.
75     *
76     * @param util
77     * @param tableName
78     * @param families
79     * @return An HTable instance for the created table.
80     * @throws IOException
81     */
82    public static HTable createMobTable(final HBaseTestingUtility util,
83        final TableName tableName, final byte[]... families) throws IOException {
84      HTableDescriptor htd = new HTableDescriptor(tableName);
85      for (byte[] family : families) {
86        HColumnDescriptor hcd = new HColumnDescriptor(family);
87        // Disable blooms (they are on by default as of 0.95) but we disable them
88        // here because
89        // tests have hard coded counts of what to expect in block cache, etc.,
90        // and blooms being
91        // on is interfering.
92        hcd.setBloomFilterType(BloomType.NONE);
93        hcd.setMobEnabled(true);
94        hcd.setMobThreshold(0L);
95        htd.addFamily(hcd);
96      }
97      util.getHBaseAdmin().createTable(htd);
98      // HBaseAdmin only waits for regions to appear in hbase:meta we should wait
99      // until they are assigned
100     util.waitUntilAllRegionsAssigned(htd.getTableName());
101     return new HTable(util.getConfiguration(), htd.getTableName());
102   }
103 
104   /**
105    * Return the number of rows in the given table.
106    */
107   public static int countMobRows(final HTable table) throws IOException {
108     Scan scan = new Scan();
109     ResultScanner results = table.getScanner(scan);
110     int count = 0;
111     for (Result res : results) {
112       count++;
113       List<Cell> cells = res.listCells();
114       for (Cell cell : cells) {
115         // Verify the value
116         Assert.assertTrue(CellUtil.cloneValue(cell).length > 0);
117       }
118     }
119     results.close();
120     return count;
121   }
122 
123   /**
124    * Return the number of rows in the given table.
125    */
126   public static int countMobRows(final HTable table, final byte[]... families)
127       throws IOException {
128     Scan scan = new Scan();
129     for (byte[] family : families) {
130       scan.addFamily(family);
131     }
132     ResultScanner results = table.getScanner(scan);
133     int count = 0;
134     for (Result res : results) {
135       count++;
136       List<Cell> cells = res.listCells();
137       for (Cell cell : cells) {
138         // Verify the value
139         Assert.assertTrue(CellUtil.cloneValue(cell).length > 0);
140       }
141     }
142     results.close();
143     return count;
144   }
145 
146   public static void verifyMobRowCount(final HBaseTestingUtility util,
147       final TableName tableName, long expectedRows) throws IOException {
148     HTable table = new HTable(util.getConfiguration(), tableName);
149     try {
150       assertEquals(expectedRows, countMobRows(table));
151     } finally {
152       table.close();
153     }
154   }
155 
156   // ==========================================================================
157   // Snapshot Mock
158   // ==========================================================================
159   public static class SnapshotMock {
160     private final static String TEST_FAMILY = "cf";
161     public final static int TEST_NUM_REGIONS = 4;
162 
163     private final Configuration conf;
164     private final FileSystem fs;
165     private final Path rootDir;
166 
167     static class RegionData {
168       public HRegionInfo hri;
169       public Path tableDir;
170       public Path[] files;
171 
172       public RegionData(final Path tableDir, final HRegionInfo hri,
173           final int nfiles) {
174         this.tableDir = tableDir;
175         this.hri = hri;
176         this.files = new Path[nfiles];
177       }
178     }
179 
180     public static class SnapshotBuilder {
181       private final RegionData[] tableRegions;
182       private final SnapshotDescription desc;
183       private final HTableDescriptor htd;
184       private final Configuration conf;
185       private final FileSystem fs;
186       private final Path rootDir;
187       private Path snapshotDir;
188       private int snapshotted = 0;
189 
190       public SnapshotBuilder(final Configuration conf, final FileSystem fs,
191           final Path rootDir, final HTableDescriptor htd,
192           final SnapshotDescription desc, final RegionData[] tableRegions)
193           throws IOException {
194         this.fs = fs;
195         this.conf = conf;
196         this.rootDir = rootDir;
197         this.htd = htd;
198         this.desc = desc;
199         this.tableRegions = tableRegions;
200         this.snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc,
201             rootDir);
202         new FSTableDescriptors(conf).createTableDescriptorForTableDirectory(
203             snapshotDir, htd, false);
204       }
205 
206       public HTableDescriptor getTableDescriptor() {
207         return this.htd;
208       }
209 
210       public SnapshotDescription getSnapshotDescription() {
211         return this.desc;
212       }
213 
214       public Path getSnapshotsDir() {
215         return this.snapshotDir;
216       }
217 
218       public Path[] addRegion() throws IOException {
219         return addRegion(desc);
220       }
221 
222       public Path[] addRegionV1() throws IOException {
223         return addRegion(desc.toBuilder()
224             .setVersion(SnapshotManifestV1.DESCRIPTOR_VERSION).build());
225       }
226 
227       public Path[] addRegionV2() throws IOException {
228         return addRegion(desc.toBuilder()
229             .setVersion(SnapshotManifestV2.DESCRIPTOR_VERSION).build());
230       }
231 
232       private Path[] addRegion(final SnapshotDescription desc)
233           throws IOException {
234         if (this.snapshotted == tableRegions.length) {
235           throw new UnsupportedOperationException(
236               "No more regions in the table");
237         }
238 
239         RegionData regionData = tableRegions[this.snapshotted++];
240         ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher(
241             desc.getName());
242         SnapshotManifest manifest = SnapshotManifest.create(conf, fs,
243             snapshotDir, desc, monitor);
244         manifest.addRegion(regionData.tableDir, regionData.hri);
245         return regionData.files;
246       }
247 
248       public Path commit() throws IOException {
249         ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher(
250             desc.getName());
251         SnapshotManifest manifest = SnapshotManifest.create(conf, fs,
252             snapshotDir, desc, monitor);
253         manifest.addTableDescriptor(htd);
254         manifest.consolidate();
255         SnapshotDescriptionUtils.completeSnapshot(desc, rootDir, snapshotDir,
256             fs);
257         snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(desc,
258             rootDir);
259         return snapshotDir;
260       }
261     }
262 
263     public SnapshotMock(final Configuration conf, final FileSystem fs,
264         final Path rootDir) {
265       this.fs = fs;
266       this.conf = conf;
267       this.rootDir = rootDir;
268     }
269 
270     public SnapshotBuilder createSnapshotV1(final String snapshotName)
271         throws IOException {
272       return createSnapshot(snapshotName, SnapshotManifestV1.DESCRIPTOR_VERSION);
273     }
274 
275     public SnapshotBuilder createSnapshotV2(final String snapshotName)
276         throws IOException {
277       return createSnapshot(snapshotName, SnapshotManifestV2.DESCRIPTOR_VERSION);
278     }
279 
280     private SnapshotBuilder createSnapshot(final String snapshotName,
281         final int version) throws IOException {
282       HTableDescriptor htd = createHtd(snapshotName);
283 
284       RegionData[] regions = createTable(htd, TEST_NUM_REGIONS);
285 
286       SnapshotDescription desc = SnapshotDescription.newBuilder()
287           .setTable(htd.getNameAsString()).setName(snapshotName)
288           .setVersion(version).build();
289 
290       Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc,
291           rootDir);
292       SnapshotDescriptionUtils.writeSnapshotInfo(desc, workingDir, fs);
293       return new SnapshotBuilder(conf, fs, rootDir, htd, desc, regions);
294     }
295 
296     public HTableDescriptor createHtd(final String tableName) {
297       HTableDescriptor htd = new HTableDescriptor(tableName);
298       HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY);
299       hcd.setMobEnabled(true);
300       hcd.setMobThreshold(0L);
301       htd.addFamily(hcd);
302       return htd;
303     }
304 
305     private RegionData[] createTable(final HTableDescriptor htd,
306         final int nregions) throws IOException {
307       Path tableDir = FSUtils.getTableDir(rootDir, htd.getTableName());
308       new FSTableDescriptors(conf).createTableDescriptorForTableDirectory(
309           tableDir, htd, false);
310 
311       assertTrue(nregions % 2 == 0);
312       RegionData[] regions = new RegionData[nregions];
313       for (int i = 0; i < regions.length; i += 2) {
314         byte[] startKey = Bytes.toBytes(0 + i * 2);
315         byte[] endKey = Bytes.toBytes(1 + i * 2);
316 
317         // First region, simple with one plain hfile.
318         HRegionInfo hri = new HRegionInfo(htd.getTableName(), startKey, endKey);
319         HRegionFileSystem rfs = HRegionFileSystem.createRegionOnFileSystem(
320             conf, fs, tableDir, hri);
321         regions[i] = new RegionData(tableDir, hri, 3);
322         for (int j = 0; j < regions[i].files.length; ++j) {
323           Path storeFile = createStoreFile(rfs.createTempName());
324           regions[i].files[j] = rfs.commitStoreFile(TEST_FAMILY, storeFile);
325         }
326 
327         // Second region, used to test the split case.
328         // This region contains a reference to the hfile in the first region.
329         startKey = Bytes.toBytes(2 + i * 2);
330         endKey = Bytes.toBytes(3 + i * 2);
331         hri = new HRegionInfo(htd.getTableName());
332         rfs = HRegionFileSystem.createRegionOnFileSystem(conf, fs, tableDir,
333             hri);
334         regions[i + 1] = new RegionData(tableDir, hri, regions[i].files.length);
335         for (int j = 0; j < regions[i].files.length; ++j) {
336           String refName = regions[i].files[j].getName() + '.'
337               + regions[i].hri.getEncodedName();
338           Path refFile = createStoreFile(new Path(rootDir, refName));
339           regions[i + 1].files[j] = rfs.commitStoreFile(TEST_FAMILY, refFile);
340         }
341       }
342       return regions;
343     }
344 
345     private Path createStoreFile(final Path storeFile) throws IOException {
346       FSDataOutputStream out = fs.create(storeFile);
347       try {
348         out.write(Bytes.toBytes(storeFile.toString()));
349       } finally {
350         out.close();
351       }
352       return storeFile;
353     }
354   }
355 }