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 junit.framework.TestCase.assertNull;
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertTrue;
26  import static org.junit.Assert.fail;
27  
28  import java.io.IOException;
29  import java.util.Collection;
30  
31  import org.apache.hadoop.hbase.HBaseTestingUtility;
32  import org.apache.hadoop.hbase.KeyValue;
33  import org.apache.hadoop.hbase.TableName;
34  import org.apache.hadoop.hbase.client.Delete;
35  import org.apache.hadoop.hbase.client.Get;
36  import org.apache.hadoop.hbase.client.HBaseAdmin;
37  import org.apache.hadoop.hbase.client.IsolationLevel;
38  import org.apache.hadoop.hbase.client.Put;
39  import org.apache.hadoop.hbase.client.Result;
40  import org.apache.hadoop.hbase.client.ResultScanner;
41  import org.apache.hadoop.hbase.client.Scan;
42  import org.apache.hadoop.hbase.client.Table;
43  import org.apache.hadoop.hbase.master.cleaner.TimeToLiveHFileCleaner;
44  import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
45  import org.apache.hadoop.hbase.testclassification.MediumTests;
46  import org.apache.hadoop.hbase.util.Bytes;
47  
48  import org.junit.AfterClass;
49  import org.junit.BeforeClass;
50  import org.junit.Test;
51  import org.junit.experimental.categories.Category;
52  
53  @Category({MediumTests.class})
54  public class TestCleanupCompactedFileOnRegionClose {
55  
56    private static HBaseTestingUtility util;
57  
58    @BeforeClass
59    public static void beforeClass() throws Exception {
60      util = new HBaseTestingUtility();
61      util.getConfiguration().setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY,100);
62      util.getConfiguration().set("dfs.blocksize", "64000");
63      util.getConfiguration().set("dfs.namenode.fs-limits.min-block-size", "1024");
64      util.getConfiguration().set(TimeToLiveHFileCleaner.TTL_CONF_KEY,"0");
65      util.startMiniCluster(2);
66    }
67  
68    @AfterClass
69    public static void afterclass() throws Exception {
70      util.shutdownMiniCluster();
71    }
72  
73    @Test
74    public void testCleanupOnClose() throws Exception {
75      TableName tableName = TableName.valueOf("testCleanupOnClose");
76      String familyName = "f";
77      byte[] familyNameBytes = Bytes.toBytes(familyName);
78      util.createTable(tableName, familyName);
79  
80      HBaseAdmin hBaseAdmin = util.getHBaseAdmin();
81      Table table = util.getConnection().getTable(tableName);
82  
83      HRegionServer rs = util.getRSForFirstRegionInTable(tableName);
84      Region region = rs.getOnlineRegions(tableName).get(0);
85  
86      int refSFCount = 4;
87      for (int i = 0; i < refSFCount; i++) {
88        for (int j = 0; j < refSFCount; j++) {
89          Put put = new Put(Bytes.toBytes(j));
90          put.addColumn(familyNameBytes, Bytes.toBytes(i), Bytes.toBytes(j));
91          table.put(put);
92        }
93        util.flush(tableName);
94      }
95      assertEquals(refSFCount, region.getStoreFileList(new byte[][]{familyNameBytes}).size());
96  
97      //add a delete, to test wether we end up with an inconsistency post region close
98      Delete delete = new Delete(Bytes.toBytes(refSFCount-1));
99      table.delete(delete);
100     util.flush(tableName);
101     assertFalse(table.exists(new Get(Bytes.toBytes(refSFCount-1))));
102 
103     //Create a scanner and keep it open to add references to StoreFileReaders
104     Scan scan = new Scan();
105     scan.setStopRow(Bytes.toBytes(refSFCount-2));
106     scan.setCaching(1);
107     ResultScanner scanner = table.getScanner(scan);
108     Result res = scanner.next();
109     assertNotNull(res);
110     assertEquals(refSFCount, res.getFamilyMap(familyNameBytes).size());
111 
112 
113     //Verify the references
114     int count = 0;
115     for (StoreFile sf : (Collection<StoreFile>)region.getStore(familyNameBytes).getStorefiles()) {
116       synchronized (sf) {
117         if (count < refSFCount) {
118           assertTrue(sf.getReader().isReferencedInReads());
119         } else {
120           assertFalse(sf.getReader().isReferencedInReads());
121         }
122       }
123       count++;
124     }
125 
126     //Major compact to produce compacted storefiles that need to be cleaned up
127     util.compact(tableName, true);
128     assertEquals(1, region.getStoreFileList(new byte[][]{familyNameBytes}).size());
129     assertEquals(refSFCount+1,
130       ((HStore)region.getStore(familyNameBytes)).getStoreEngine().getStoreFileManager()
131           .getCompactedfiles().size());
132 
133     //close then open the region to determine wether compacted storefiles get cleaned up on close
134     hBaseAdmin.unassign(region.getRegionInfo().getRegionName(), false);
135     hBaseAdmin.assign(region.getRegionInfo().getRegionName());
136     util.waitUntilNoRegionsInTransition(10000);
137 
138 
139     assertFalse("Deleted row should not exist",
140         table.exists(new Get(Bytes.toBytes(refSFCount-1))));
141 
142     rs = util.getRSForFirstRegionInTable(tableName);
143     region = rs.getOnlineRegions(tableName).get(0);
144     assertEquals(1, region.getStoreFileList(new byte[][]{familyNameBytes}).size());
145     assertNull(((HStore)region.getStore(familyNameBytes)).getStoreEngine().getStoreFileManager()
146         .getCompactedfiles());
147   }
148 
149   @Test
150   public void testIOExceptionThrownOnClose() throws Exception {
151     byte[] filler = new byte[128000];
152     TableName tableName = TableName.valueOf("testIOExceptionThrownOnClose");
153     String familyName = "f";
154     byte[] familyNameBytes = Bytes.toBytes(familyName);
155     util.createTable(tableName, familyName);
156 
157     Table table = util.getConnection().getTable(tableName);
158 
159     HRegionServer rs = util.getRSForFirstRegionInTable(tableName);
160     Region region = rs.getOnlineRegions(tableName).get(0);
161 
162     int refSFCount = 4;
163     for (int i = 0; i < refSFCount; i++) {
164       for (int j = 0; j < refSFCount; j++) {
165         Put put = new Put(Bytes.toBytes(j));
166         put.addColumn(familyNameBytes, Bytes.toBytes(i), filler);
167         table.put(put);
168       }
169       util.flush(tableName);
170     }
171     assertEquals(refSFCount, region.getStoreFileList(new byte[][]{familyNameBytes}).size());
172 
173     HStore store = (HStore)region.getStore(familyNameBytes);
174     StoreFile hsf = region.getStore(familyNameBytes).getStorefiles().iterator().next();
175     long readPt = region.getReadpoint(IsolationLevel.READ_COMMITTED);
176     StoreFileScanner preadScanner = hsf.getReader().getStoreFileScanner(
177         false, true, false, readPt, 0, false);
178     preadScanner.seek(KeyValue.LOWESTKEY);
179 
180     //Major compact to produce compacted storefiles that need to be cleaned up
181     util.compact(tableName, true);
182     assertNotNull(preadScanner.next());
183     store.closeAndArchiveCompactedFiles(true);
184 
185     try {
186       assertNotNull(preadScanner.next());
187       fail("Expected IOException");
188     }catch (IOException ex) {
189       ex.printStackTrace();
190     }
191   }
192 }