001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import static org.apache.hadoop.hbase.regionserver.CustomTieringMultiFileWriter.CUSTOM_TIERING_TIME_RANGE;
021import static org.junit.jupiter.api.Assertions.assertEquals;
022import static org.junit.jupiter.api.Assertions.assertFalse;
023import static org.junit.jupiter.api.Assertions.assertTrue;
024import static org.mockito.Mockito.mock;
025import static org.mockito.Mockito.when;
026
027import java.io.IOException;
028import java.util.ArrayList;
029import java.util.UUID;
030import org.apache.hadoop.fs.FileSystem;
031import org.apache.hadoop.fs.Path;
032import org.apache.hadoop.hbase.HBaseTestingUtil;
033import org.apache.hadoop.hbase.HConstants;
034import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
035import org.apache.hadoop.hbase.client.RegionInfo;
036import org.apache.hadoop.hbase.regionserver.compactions.CustomDateTieredCompactionPolicy;
037import org.apache.hadoop.hbase.regionserver.compactions.DateTieredCompactionRequest;
038import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerForTest;
039import org.apache.hadoop.hbase.testclassification.RegionServerTests;
040import org.apache.hadoop.hbase.testclassification.SmallTests;
041import org.apache.hadoop.hbase.util.Bytes;
042import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
043import org.apache.hadoop.hbase.util.ManualEnvironmentEdge;
044import org.junit.jupiter.api.Tag;
045import org.junit.jupiter.api.Test;
046
047@Tag(RegionServerTests.TAG)
048@Tag(SmallTests.TAG)
049public class TestCustomCellTieredCompactionPolicy {
050
051  private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
052
053  public static final byte[] FAMILY = Bytes.toBytes("cf");
054
055  private HStoreFile createFile(Path file, long minValue, long maxValue, long size, int seqId)
056    throws IOException {
057    return createFile(mockRegionInfo(), file, minValue, maxValue, size, seqId, 0);
058  }
059
060  private HStoreFile createFile(RegionInfo regionInfo, Path file, long minValue, long maxValue,
061    long size, int seqId, long ageInDisk) throws IOException {
062    FileSystem fs = FileSystem.get(TEST_UTIL.getConfiguration());
063    HRegionFileSystem regionFileSystem =
064      new HRegionFileSystem(TEST_UTIL.getConfiguration(), fs, file, regionInfo);
065    StoreContext ctx = new StoreContext.Builder()
066      .withColumnFamilyDescriptor(ColumnFamilyDescriptorBuilder.newBuilder(FAMILY).build())
067      .withRegionFileSystem(regionFileSystem).build();
068    StoreFileTrackerForTest sftForTest =
069      new StoreFileTrackerForTest(TEST_UTIL.getConfiguration(), true, ctx);
070    MockHStoreFile msf =
071      new MockHStoreFile(TEST_UTIL, file, size, ageInDisk, false, (long) seqId, sftForTest);
072    TimeRangeTracker timeRangeTracker = TimeRangeTracker.create(TimeRangeTracker.Type.NON_SYNC);
073    timeRangeTracker.setMin(minValue);
074    timeRangeTracker.setMax(maxValue);
075    msf.setMetadataValue(CUSTOM_TIERING_TIME_RANGE, TimeRangeTracker.toByteArray(timeRangeTracker));
076    return msf;
077  }
078
079  private CustomDateTieredCompactionPolicy mockAndCreatePolicy() throws Exception {
080    RegionInfo mockedRegionInfo = mockRegionInfo();
081    return mockAndCreatePolicy(mockedRegionInfo);
082  }
083
084  private CustomDateTieredCompactionPolicy mockAndCreatePolicy(RegionInfo regionInfo)
085    throws Exception {
086    StoreConfigInformation mockedStoreConfig = mock(StoreConfigInformation.class);
087    when(mockedStoreConfig.getRegionInfo()).thenReturn(regionInfo);
088    CustomDateTieredCompactionPolicy policy =
089      new CustomDateTieredCompactionPolicy(TEST_UTIL.getConfiguration(), mockedStoreConfig);
090    return policy;
091  }
092
093  private RegionInfo mockRegionInfo() {
094    RegionInfo mockedRegionInfo = mock(RegionInfo.class);
095    when(mockedRegionInfo.getEncodedName()).thenReturn("1234567890987654321");
096    return mockedRegionInfo;
097  }
098
099  private Path preparePath() throws Exception {
100    FileSystem fs = FileSystem.get(TEST_UTIL.getConfiguration());
101    Path file =
102      new Path(TEST_UTIL.getDataTestDir(), UUID.randomUUID().toString().replaceAll("-", ""));
103    fs.create(file);
104    return file;
105  }
106
107  @Test
108  public void testGetCompactBoundariesForMajorNoOld() throws Exception {
109    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
110    Path file = preparePath();
111    ArrayList<HStoreFile> files = new ArrayList<>();
112    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
113      EnvironmentEdgeManager.currentTime(), 1024, 0));
114    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
115      EnvironmentEdgeManager.currentTime(), 1024, 1));
116    assertEquals(1,
117      ((DateTieredCompactionRequest) policy.selectMajorCompaction(files)).getBoundaries().size());
118  }
119
120  @Test
121  public void testGetCompactBoundariesForMajorAllOld() throws Exception {
122    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
123    Path file = preparePath();
124    ArrayList<HStoreFile> files = new ArrayList<>();
125    // The default cut off age is 10 years, so any of the min/max value there should get in the old
126    // tier
127    files.add(createFile(file, 0, 1, 1024, 0));
128    files.add(createFile(file, 2, 3, 1024, 1));
129    assertEquals(2,
130      ((DateTieredCompactionRequest) policy.selectMajorCompaction(files)).getBoundaries().size());
131  }
132
133  @Test
134  public void testGetCompactBoundariesForMajorOneOnEachSide() throws Exception {
135    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
136    Path file = preparePath();
137    ArrayList<HStoreFile> files = new ArrayList<>();
138    files.add(createFile(file, 0, 1, 1024, 0));
139    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
140      EnvironmentEdgeManager.currentTime(), 1024, 1));
141    assertEquals(3,
142      ((DateTieredCompactionRequest) policy.selectMajorCompaction(files)).getBoundaries().size());
143  }
144
145  @Test
146  public void testGetCompactBoundariesForMajorOneCrossing() throws Exception {
147    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
148    Path file = preparePath();
149    ArrayList<HStoreFile> files = new ArrayList<>();
150    files.add(createFile(file, 0, EnvironmentEdgeManager.currentTime(), 1024, 0));
151    assertEquals(3,
152      ((DateTieredCompactionRequest) policy.selectMajorCompaction(files)).getBoundaries().size());
153  }
154
155  @FunctionalInterface
156  interface PolicyValidator<T, U> {
157    void accept(T t, U u) throws Exception;
158  }
159
160  private void testShouldPerformMajorCompaction(long min, long max, int numFiles,
161    PolicyValidator<CustomDateTieredCompactionPolicy, ArrayList<HStoreFile>> validation)
162    throws Exception {
163    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
164    RegionInfo mockedRegionInfo = mockRegionInfo();
165    Path file = preparePath();
166    ArrayList<HStoreFile> files = new ArrayList<>();
167    ManualEnvironmentEdge timeMachine = new ManualEnvironmentEdge();
168    EnvironmentEdgeManager.injectEdge(timeMachine);
169    for (int i = 0; i < numFiles; i++) {
170      MockHStoreFile mockedSFile = (MockHStoreFile) createFile(mockedRegionInfo, file, min, max,
171        1024, 0, HConstants.DEFAULT_MAJOR_COMPACTION_PERIOD);
172      mockedSFile.setIsMajor(true);
173      files.add(mockedSFile);
174    }
175    EnvironmentEdgeManager.reset();
176    validation.accept(policy, files);
177  }
178
179  @Test
180  public void testShouldPerformMajorCompactionOneFileCrossing() throws Exception {
181    long max = EnvironmentEdgeManager.currentTime();
182    testShouldPerformMajorCompaction(0, max, 1,
183      (p, f) -> assertTrue(p.shouldPerformMajorCompaction(f)));
184  }
185
186  @Test
187  public void testShouldPerformMajorCompactionOneFileMinMaxLow() throws Exception {
188    testShouldPerformMajorCompaction(0, 1, 1,
189      (p, f) -> assertFalse(p.shouldPerformMajorCompaction(f)));
190  }
191
192  @Test
193  public void testShouldPerformMajorCompactionOneFileMinMaxHigh() throws Exception {
194    long currentTime = EnvironmentEdgeManager.currentTime();
195    testShouldPerformMajorCompaction(currentTime, currentTime, 1,
196      (p, f) -> assertFalse(p.shouldPerformMajorCompaction(f)));
197  }
198
199  @Test
200  public void testShouldPerformMajorCompactionTwoFilesMinMaxHigh() throws Exception {
201    long currentTime = EnvironmentEdgeManager.currentTime();
202    testShouldPerformMajorCompaction(currentTime, currentTime, 2,
203      (p, f) -> assertTrue(p.shouldPerformMajorCompaction(f)));
204  }
205
206  @Test
207  public void testSelectMinorCompactionTwoFilesNoOld() throws Exception {
208    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
209    Path file = preparePath();
210    ArrayList<HStoreFile> files = new ArrayList<>();
211    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
212      EnvironmentEdgeManager.currentTime(), 1024, 0));
213    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
214      EnvironmentEdgeManager.currentTime(), 1024, 1));
215    // Shouldn't do minor compaction, as minimum number of files
216    // for minor compactions is 3
217    assertEquals(0, policy.selectMinorCompaction(files, true, true).getFiles().size());
218  }
219
220  @Test
221  public void testSelectMinorCompactionThreeFilesNoOld() throws Exception {
222    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
223    Path file = preparePath();
224    ArrayList<HStoreFile> files = new ArrayList<>();
225    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
226      EnvironmentEdgeManager.currentTime(), 1024, 0));
227    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
228      EnvironmentEdgeManager.currentTime(), 1024, 1));
229    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
230      EnvironmentEdgeManager.currentTime(), 1024, 2));
231    assertEquals(3, policy.selectMinorCompaction(files, true, true).getFiles().size());
232  }
233
234  @Test
235  public void testSelectMinorCompactionThreeFilesAllOld() throws Exception {
236    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
237    Path file = preparePath();
238    ArrayList<HStoreFile> files = new ArrayList<>();
239    files.add(createFile(file, 0, 1, 1024, 0));
240    files.add(createFile(file, 1, 2, 1024, 1));
241    files.add(createFile(file, 3, 4, 1024, 2));
242    assertEquals(3, policy.selectMinorCompaction(files, true, true).getFiles().size());
243  }
244
245  @Test
246  public void testSelectMinorCompactionThreeFilesOneOldTwoNew() throws Exception {
247    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
248    Path file = preparePath();
249    ArrayList<HStoreFile> files = new ArrayList<>();
250    files.add(createFile(file, 0, 1, 1024, 0));
251    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
252      EnvironmentEdgeManager.currentTime(), 1024, 1));
253    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
254      EnvironmentEdgeManager.currentTime(), 1024, 2));
255    assertEquals(3, policy.selectMinorCompaction(files, true, true).getFiles().size());
256  }
257
258  @Test
259  public void testSelectMinorCompactionThreeFilesTwoOldOneNew() throws Exception {
260    CustomDateTieredCompactionPolicy policy = mockAndCreatePolicy();
261    Path file = preparePath();
262    ArrayList<HStoreFile> files = new ArrayList<>();
263    files.add(createFile(file, 0, 1, 1024, 0));
264    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
265      EnvironmentEdgeManager.currentTime(), 1024, 1));
266    files.add(createFile(file, EnvironmentEdgeManager.currentTime(),
267      EnvironmentEdgeManager.currentTime(), 1024, 2));
268    assertEquals(3, policy.selectMinorCompaction(files, true, true).getFiles().size());
269  }
270}