View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver;
20  
21  import static org.junit.Assert.assertEquals;
22  
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.util.List;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.HBaseTestingUtility;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.Waiter;
33  import org.apache.hadoop.hbase.client.Admin;
34  import org.apache.hadoop.hbase.client.Put;
35  import org.apache.hadoop.hbase.client.Table;
36  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.GetRegionInfoResponse.CompactionState;
37  import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
38  import org.apache.hadoop.hbase.testclassification.MediumTests;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
41  import org.junit.After;
42  import org.junit.AfterClass;
43  import org.junit.Assert;
44  import org.junit.BeforeClass;
45  import org.junit.Test;
46  import org.junit.experimental.categories.Category;
47  
48  /**
49   * This class tests the scenario where a store refresh happens due to a file not found during scan,
50   * after a compaction but before the compacted files are archived. At this state we test for a split
51   * and compaction
52   */
53  @Category(MediumTests.class)
54  public class TestCompactionFileNotFound {
55    private static final Log LOG = LogFactory.getLog(TestCompactionFileNotFound.class);
56    private static final HBaseTestingUtility util = new HBaseTestingUtility();
57  
58    private static final TableName TEST_TABLE = TableName.valueOf("test");
59    private static final byte[] TEST_FAMILY = Bytes.toBytes("f1");
60  
61    private static final byte[] ROW_A = Bytes.toBytes("aaa");
62    private static final byte[] ROW_B = Bytes.toBytes("bbb");
63    private static final byte[] ROW_C = Bytes.toBytes("ccc");
64  
65    private static final byte[] qualifierCol1 = Bytes.toBytes("col1");
66  
67    private static final byte[] bytes1 = Bytes.toBytes(1);
68    private static final byte[] bytes2 = Bytes.toBytes(2);
69    private static final byte[] bytes3 = Bytes.toBytes(3);
70  
71    private Table table;
72  
73    @BeforeClass
74    public static void setupBeforeClass() throws Exception {
75      Configuration conf = util.getConfiguration();
76      conf.setInt(CompactionConfiguration.HBASE_HFILE_COMPACTION_DISCHARGER_INTERVAL,
77        Integer.MAX_VALUE);
78      util.startMiniCluster(3);
79    }
80  
81    @AfterClass
82    public static void tearDownAfterClass() throws Exception {
83      util.shutdownMiniCluster();
84    }
85  
86    @After
87    public void after() throws Exception {
88      try {
89        if (table != null) {
90          table.close();
91        }
92      } finally {
93        util.deleteTable(TEST_TABLE);
94      }
95    }
96  
97    @Test
98    public void testSplitAfterRefresh() throws Exception {
99      final Admin admin = util.getHBaseAdmin();
100     table = util.createTable(TEST_TABLE, TEST_FAMILY);
101 
102     try {
103       // Create Multiple store files
104       Put puta = new Put(ROW_A);
105       puta.addColumn(TEST_FAMILY, qualifierCol1, bytes1);
106       table.put(puta);
107       admin.flush(TEST_TABLE);
108 
109       Put putb = new Put(ROW_B);
110       putb.addColumn(TEST_FAMILY, qualifierCol1, bytes2);
111       table.put(putb);
112       admin.flush(TEST_TABLE);
113 
114       Put putc = new Put(ROW_C);
115       putc.addColumn(TEST_FAMILY, qualifierCol1, bytes3);
116       table.put(putc);
117       admin.flush(TEST_TABLE);
118 
119       admin.compact(TEST_TABLE);
120       while (admin.getCompactionState(TEST_TABLE) != CompactionState.NONE) {
121         Thread.sleep(1000);
122       }
123       table.put(putb);
124       HRegion hr1 = (HRegion) util.getRSForFirstRegionInTable(TEST_TABLE)
125           .getRegionByEncodedName(admin.getTableRegions(TEST_TABLE).get(0).getEncodedName());
126       // Refresh store files post compaction, this should not open already compacted files
127       hr1.refreshStoreFiles();
128       final int numRegionsBeforeSplit = admin.getTableRegions(TEST_TABLE).size();
129       // Check if we can successfully split after compaction
130       admin.splitRegion(admin.getTableRegions(TEST_TABLE).get(0).getEncodedNameAsBytes(), ROW_C);
131       util.waitFor(20000, new Waiter.Predicate<Exception>() {
132         @Override
133         public boolean evaluate() throws Exception {
134           int numRegionsAfterSplit = 0;
135           List<RegionServerThread> rst = util.getMiniHBaseCluster().getLiveRegionServerThreads();
136           for (RegionServerThread t : rst) {
137             numRegionsAfterSplit += t.getRegionServer().getOnlineRegions(TEST_TABLE).size();
138           }
139           // Make sure that the split went through and all the regions are assigned
140           return (numRegionsAfterSplit == numRegionsBeforeSplit + 1
141               && admin.isTableAvailable(TEST_TABLE));
142         }
143       });
144       // Split at this point should not result in the RS being aborted
145       assertEquals(util.getMiniHBaseCluster().getLiveRegionServerThreads().size(), 3);
146     } finally {
147       if (admin != null) {
148         admin.close();
149       }
150     }
151   }
152 
153   @Test
154   public void testCompactionAfterRefresh() throws Exception {
155     Admin admin = util.getHBaseAdmin();
156     table = util.createTable(TEST_TABLE, TEST_FAMILY);
157     try {
158       // Create Multiple store files
159       Put puta = new Put(ROW_A);
160       puta.addColumn(TEST_FAMILY, qualifierCol1, bytes1);
161       table.put(puta);
162       admin.flush(TEST_TABLE);
163 
164       Put putb = new Put(ROW_B);
165       putb.addColumn(TEST_FAMILY, qualifierCol1, bytes2);
166       table.put(putb);
167       admin.flush(TEST_TABLE);
168 
169       Put putc = new Put(ROW_C);
170       putc.addColumn(TEST_FAMILY, qualifierCol1, bytes3);
171       table.put(putc);
172       admin.flush(TEST_TABLE);
173 
174       admin.compact(TEST_TABLE);
175       while (admin.getCompactionState(TEST_TABLE) != CompactionState.NONE) {
176         Thread.sleep(1000);
177       }
178       table.put(putb);
179       HRegion hr1 = (HRegion) util.getRSForFirstRegionInTable(TEST_TABLE)
180           .getRegionByEncodedName(admin.getTableRegions(TEST_TABLE).get(0).getEncodedName());
181       // Refresh store files post compaction, this should not open already compacted files
182       hr1.refreshStoreFiles();
183       // Archive the store files and try another compaction to see if all is good
184       for (Store store : hr1.getStores()) {
185         store.closeAndArchiveCompactedFiles();
186       }
187       try {
188         hr1.compact(false);
189       } catch (IOException e) {
190         LOG.error("Got an exception during compaction", e);
191         if (e instanceof FileNotFoundException) {
192           Assert.fail("Got a FNFE during compaction");
193         } else {
194           Assert.fail();
195         }
196       }
197     } finally {
198       if (admin != null) {
199         admin.close();
200       }
201     }
202   }
203 }