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.util.compaction;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Set;
25  import com.google.common.base.Optional;
26  import com.google.common.collect.Iterables;
27  import com.google.common.collect.Lists;
28  import com.google.common.collect.Sets;
29  import org.apache.commons.lang.RandomStringUtils;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.fs.FileStatus;
32  import org.apache.hadoop.fs.FileSystem;
33  import org.apache.hadoop.fs.Path;
34  import org.apache.hadoop.hbase.HBaseTestingUtility;
35  import org.apache.hadoop.hbase.HRegionInfo;
36  import org.apache.hadoop.hbase.HTableDescriptor;
37  import org.apache.hadoop.hbase.TableName;
38  import org.apache.hadoop.hbase.client.Connection;
39  import org.apache.hadoop.hbase.regionserver.HRegion;
40  import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
41  import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
42  import org.apache.hadoop.hbase.testclassification.SmallTests;
43  import org.apache.hadoop.hbase.util.Bytes;
44  import static org.junit.Assert.assertEquals;
45  import static org.junit.Assert.assertFalse;
46  import static org.junit.Assert.assertTrue;
47  import org.junit.Before;
48  import org.junit.Test;
49  import org.junit.experimental.categories.Category;
50  import static org.mockito.Matchers.any;
51  import static org.mockito.Matchers.anyString;
52  import static org.mockito.Matchers.eq;
53  import static org.mockito.Matchers.isA;
54  import static org.mockito.Mockito.doReturn;
55  import static org.mockito.Mockito.mock;
56  import static org.mockito.Mockito.spy;
57  import static org.mockito.Mockito.when;
58  
59  @Category({SmallTests.class})
60  public class MajorCompactionRequestTest {
61  
62    protected static final HBaseTestingUtility UTILITY = new HBaseTestingUtility();
63    protected static final String FAMILY = "a";
64    protected Path rootRegionDir;
65    protected Path regionStoreDir;
66  
67    @Before public void setUp() throws Exception {
68      rootRegionDir = UTILITY.getDataTestDirOnTestFS("MajorCompactionRequestTest");
69      regionStoreDir = new Path(rootRegionDir, FAMILY);
70    }
71  
72    @Test public void testStoresNeedingCompaction() throws Exception {
73      // store files older than timestamp
74      List<StoreFileInfo> storeFiles = mockStoreFiles(regionStoreDir, 5, 10);
75      MajorCompactionRequest request = makeMockRequest(storeFiles, false);
76      Optional<MajorCompactionRequest> result =
77          request.createRequest(mock(Configuration.class), Sets.newHashSet(FAMILY), 100);
78      assertTrue(result.isPresent());
79  
80      // store files newer than timestamp
81      storeFiles = mockStoreFiles(regionStoreDir, 5, 101);
82      request = makeMockRequest(storeFiles, false);
83      result = request.createRequest(mock(Configuration.class), Sets.newHashSet(FAMILY), 100);
84      assertFalse(result.isPresent());
85    }
86  
87    @Test public void testIfWeHaveNewReferenceFilesButOldStoreFiles() throws Exception {
88      // this tests that reference files that are new, but have older timestamps for the files
89      // they reference still will get compacted.
90      TableName table = TableName.valueOf("MajorCompactorTest");
91      HTableDescriptor htd = UTILITY.createTableDescriptor(table, Bytes.toBytes(FAMILY));
92      HRegionInfo hri = new HRegionInfo(htd.getTableName());
93      HRegion region =
94          HBaseTestingUtility.createRegionAndWAL(hri, rootRegionDir, UTILITY.getRandomDir(),
95              UTILITY.getConfiguration(), htd);
96  
97      Configuration configuration = mock(Configuration.class);
98      // the reference file timestamp is newer
99      List<StoreFileInfo> storeFiles = mockStoreFiles(regionStoreDir, 4, 101);
100     List<Path> paths = new ArrayList<>();
101     for (StoreFileInfo storeFile : storeFiles) {
102       Path path = storeFile.getPath();
103       paths.add(path);
104     }
105     // the files that are referenced are older, thus we still compact.
106     HRegionFileSystem fileSystem =
107         mockFileSystem(region.getRegionInfo(), true, storeFiles, 50);
108     MajorCompactionRequest majorCompactionRequest = spy(new MajorCompactionRequest(configuration,
109         region.getRegionInfo()));
110     doReturn(mock(Connection.class)).when(majorCompactionRequest).getConnection(eq(configuration));
111     doReturn(paths).when(majorCompactionRequest).getReferenceFilePaths(any(FileSystem.class),
112         any(Path.class));
113     doReturn(fileSystem).when(majorCompactionRequest).getFileSystem(any(Connection.class));
114     Set<String> result = majorCompactionRequest
115         .getStoresRequiringCompaction(Sets.newHashSet("a"), 100);
116     assertEquals(FAMILY, Iterables.getOnlyElement(result));
117   }
118 
119   private HRegionFileSystem mockFileSystem(HRegionInfo info, boolean hasReferenceFiles,
120       List<StoreFileInfo> storeFiles) throws IOException {
121     Optional<StoreFileInfo> found = Optional.absent();
122     for (StoreFileInfo storeFile : storeFiles) {
123       found = Optional.of(storeFile);
124       break;
125     }
126     long timestamp = found.get().getModificationTime();
127     return mockFileSystem(info, hasReferenceFiles, storeFiles, timestamp);
128   }
129 
130   private HRegionFileSystem mockFileSystem(HRegionInfo info, boolean hasReferenceFiles,
131       List<StoreFileInfo> storeFiles, long referenceFileTimestamp) throws IOException {
132     FileSystem fileSystem = mock(FileSystem.class);
133     if (hasReferenceFiles) {
134       FileStatus fileStatus = mock(FileStatus.class);
135       doReturn(referenceFileTimestamp).when(fileStatus).getModificationTime();
136       doReturn(fileStatus).when(fileSystem).getFileLinkStatus(isA(Path.class));
137     }
138     HRegionFileSystem mockSystem = mock(HRegionFileSystem.class);
139     doReturn(info).when(mockSystem).getRegionInfo();
140     doReturn(regionStoreDir).when(mockSystem).getStoreDir(FAMILY);
141     doReturn(hasReferenceFiles).when(mockSystem).hasReferences(anyString());
142     doReturn(storeFiles).when(mockSystem).getStoreFiles(anyString());
143     doReturn(fileSystem).when(mockSystem).getFileSystem();
144     return mockSystem;
145   }
146 
147   List<StoreFileInfo> mockStoreFiles(Path regionStoreDir, int howMany, long timestamp)
148       throws IOException {
149     List<StoreFileInfo> infos = Lists.newArrayList();
150     int i = 0;
151     while (i < howMany) {
152       StoreFileInfo storeFileInfo = mock(StoreFileInfo.class);
153       doReturn(timestamp).doReturn(timestamp).when(storeFileInfo).getModificationTime();
154       doReturn(new Path(regionStoreDir, RandomStringUtils.randomAlphabetic(10))).when(storeFileInfo)
155           .getPath();
156       infos.add(storeFileInfo);
157       i++;
158     }
159     return infos;
160   }
161 
162   private MajorCompactionRequest makeMockRequest(List<StoreFileInfo> storeFiles,
163       boolean references) throws IOException {
164     Configuration configuration = mock(Configuration.class);
165     HRegionInfo regionInfo = mock(HRegionInfo.class);
166     when(regionInfo.getEncodedName()).thenReturn("HBase");
167     when(regionInfo.getTable()).thenReturn(TableName.valueOf("foo"));
168     MajorCompactionRequest request =
169         new MajorCompactionRequest(configuration, regionInfo, Sets.newHashSet("a"));
170     MajorCompactionRequest spy = spy(request);
171     HRegionFileSystem fileSystem = mockFileSystem(regionInfo, references, storeFiles);
172     doReturn(fileSystem).when(spy).getFileSystem(isA(Connection.class));
173     doReturn(mock(Connection.class)).when(spy).getConnection(eq(configuration));
174     return spy;
175   }
176 }