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 java.io.IOException;
021import org.apache.hadoop.hbase.HBaseClassTestRule;
022import org.apache.hadoop.hbase.HConstants;
023import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
024import org.apache.hadoop.hbase.regionserver.compactions.ExponentialCompactionWindowFactory;
025import org.apache.hadoop.hbase.testclassification.RegionServerTests;
026import org.apache.hadoop.hbase.testclassification.SmallTests;
027import org.junit.ClassRule;
028import org.junit.Test;
029import org.junit.experimental.categories.Category;
030
031@Category({ RegionServerTests.class, SmallTests.class })
032public class TestDateTieredCompactionPolicy extends AbstractTestDateTieredCompactionPolicy {
033
034  @ClassRule
035  public static final HBaseClassTestRule CLASS_RULE =
036    HBaseClassTestRule.forClass(TestDateTieredCompactionPolicy.class);
037
038  @Override
039  protected void config() {
040    super.config();
041
042    // Set up policy
043    conf.set(StoreEngine.STORE_ENGINE_CLASS_KEY,
044      "org.apache.hadoop.hbase.regionserver.DateTieredStoreEngine");
045    conf.setLong(CompactionConfiguration.DATE_TIERED_MAX_AGE_MILLIS_KEY, 100);
046    conf.setLong(CompactionConfiguration.DATE_TIERED_INCOMING_WINDOW_MIN_KEY, 3);
047    conf.setLong(ExponentialCompactionWindowFactory.BASE_WINDOW_MILLIS_KEY, 6);
048    conf.setInt(ExponentialCompactionWindowFactory.WINDOWS_PER_TIER_KEY, 4);
049    conf.setBoolean(CompactionConfiguration.DATE_TIERED_SINGLE_OUTPUT_FOR_MINOR_COMPACTION_KEY,
050      false);
051
052    // Special settings for compaction policy per window
053    this.conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY, 2);
054    this.conf.setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MAX_KEY, 12);
055    this.conf.setFloat(CompactionConfiguration.HBASE_HSTORE_COMPACTION_RATIO_KEY, 1.2F);
056
057    conf.setInt(HStore.BLOCKING_STOREFILES_KEY, 20);
058    conf.setLong(HConstants.MAJOR_COMPACTION_PERIOD, 5);
059  }
060
061  /**
062   * Test for incoming window
063   * @throws IOException with error
064   */
065  @Test
066  public void incomingWindow() throws IOException {
067    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
068    long[] maxTimestamps = new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
069    long[] sizes = new long[] { 30, 31, 32, 33, 34, 20, 21, 22, 23, 24, 25, 10, 11, 12, 13 };
070
071    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 10, 11, 12, 13 },
072      new long[] { Long.MIN_VALUE, 12 }, false, true);
073  }
074
075  /**
076   * Not enough files in incoming window
077   * @throws IOException with error
078   */
079  @Test
080  public void NotIncomingWindow() throws IOException {
081    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
082    long[] maxTimestamps = new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
083    long[] sizes = new long[] { 30, 31, 32, 33, 34, 20, 21, 22, 23, 24, 25, 10, 11 };
084
085    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes),
086      new long[] { 20, 21, 22, 23, 24, 25 }, new long[] { Long.MIN_VALUE, 6 }, false, true);
087  }
088
089  /**
090   * Test for file on the upper bound of incoming window
091   * @throws IOException with error
092   */
093  @Test
094  public void OnUpperBoundOfIncomingWindow() throws IOException {
095    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
096    long[] maxTimestamps = new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 18 };
097    long[] sizes = new long[] { 30, 31, 32, 33, 34, 20, 21, 22, 23, 24, 25, 10, 11, 12, 13 };
098
099    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 10, 11, 12, 13 },
100      new long[] { Long.MIN_VALUE, 12 }, false, true);
101  }
102
103  /**
104   * Test for file newer than incoming window
105   * @throws IOException with error
106   */
107  @Test
108  public void NewerThanIncomingWindow() throws IOException {
109    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
110    long[] maxTimestamps = new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19 };
111    long[] sizes = new long[] { 30, 31, 32, 33, 34, 20, 21, 22, 23, 24, 25, 10, 11, 12, 13 };
112
113    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 10, 11, 12, 13 },
114      new long[] { Long.MIN_VALUE, 12 }, false, true);
115  }
116
117  /**
118   * If there is no T1 window, we don't build T2
119   * @throws IOException with error
120   */
121  @Test
122  public void NoT2() throws IOException {
123    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
124    long[] maxTimestamps = new long[] { 44, 60, 61, 97, 100, 193 };
125    long[] sizes = new long[] { 0, 20, 21, 22, 23, 1 };
126
127    compactEquals(194, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 22, 23 },
128      new long[] { Long.MIN_VALUE, 96 }, false, true);
129  }
130
131  @Test
132  public void T1() throws IOException {
133    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
134    long[] maxTimestamps = new long[] { 44, 60, 61, 96, 100, 104, 120, 124, 143, 145, 157 };
135    long[] sizes = new long[] { 0, 50, 51, 40, 41, 42, 30, 31, 32, 2, 1 };
136
137    compactEquals(161, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 30, 31, 32 },
138      new long[] { Long.MIN_VALUE, 120 }, false, true);
139  }
140
141  /**
142   * Apply exploring logic on non-incoming window
143   * @throws IOException with error
144   */
145  @Test
146  public void RatioT0() throws IOException {
147    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
148    long[] maxTimestamps = new long[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
149    long[] sizes = new long[] { 30, 31, 32, 33, 34, 20, 21, 22, 280, 23, 24, 1 };
150
151    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 20, 21, 22 },
152      new long[] { Long.MIN_VALUE }, false, true);
153  }
154
155  /**
156   * Also apply ratio-based logic on t2 window
157   * @throws IOException with error
158   */
159  @Test
160  public void RatioT2() throws IOException {
161    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
162    long[] maxTimestamps = new long[] { 44, 60, 61, 96, 100, 104, 120, 124, 143, 145, 157 };
163    long[] sizes = new long[] { 0, 50, 51, 40, 41, 42, 350, 30, 31, 2, 1 };
164
165    compactEquals(161, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 30, 31 },
166      new long[] { Long.MIN_VALUE }, false, true);
167  }
168
169  /**
170   * The next compaction call after testTieredCompactionRatioT0 is compacted
171   * @throws IOException with error
172   */
173  @Test
174  public void RatioT0Next() throws IOException {
175    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
176    long[] maxTimestamps = new long[] { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12 };
177    long[] sizes = new long[] { 30, 31, 32, 33, 34, 22, 280, 23, 24, 1 };
178
179    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes), new long[] { 23, 24 },
180      new long[] { Long.MIN_VALUE }, false, true);
181  }
182
183  /**
184   * Older than now(161) - maxAge(100)
185   * @throws IOException with error
186   */
187  @Test
188  public void olderThanMaxAge() throws IOException {
189    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
190    long[] maxTimestamps = new long[] { 44, 60, 61, 96, 100, 104, 105, 106, 113, 145, 157 };
191    long[] sizes = new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2, 1 };
192
193    compactEquals(161, sfCreate(minTimestamps, maxTimestamps, sizes),
194      new long[] { 40, 41, 42, 33, 30, 31 }, new long[] { Long.MIN_VALUE, 96 }, false, true);
195  }
196
197  /**
198   * Out-of-order data
199   * @throws IOException with error
200   */
201  @Test
202  public void outOfOrder() throws IOException {
203    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
204    long[] maxTimestamps = new long[] { 0, 13, 3, 10, 11, 1, 2, 12, 14, 15 };
205    long[] sizes = new long[] { 30, 31, 32, 33, 34, 22, 28, 23, 24, 1 };
206
207    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes),
208      new long[] { 31, 32, 33, 34, 22, 28, 23, 24, 1 }, new long[] { Long.MIN_VALUE, 12 }, false,
209      true);
210  }
211
212  /**
213   * Negative epoch time
214   * @throws IOException with error
215   */
216  @Test
217  public void negativeEpochtime() throws IOException {
218    long[] minTimestamps =
219      new long[] { -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000 };
220    long[] maxTimestamps = new long[] { -28, -11, -10, -9, -8, -7, -6, -5, -4, -3 };
221    long[] sizes = new long[] { 30, 31, 32, 33, 34, 22, 25, 23, 24, 1 };
222
223    compactEquals(1, sfCreate(minTimestamps, maxTimestamps, sizes),
224      new long[] { 31, 32, 33, 34, 22, 25, 23, 24, 1 }, new long[] { Long.MIN_VALUE, -24 }, false,
225      true);
226  }
227
228  /**
229   * Major compaction
230   * @throws IOException with error
231   */
232  @Test
233  public void majorCompation() throws IOException {
234    long[] minTimestamps = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
235    long[] maxTimestamps = new long[] { 44, 60, 61, 96, 100, 104, 105, 106, 113, 145, 157 };
236    long[] sizes = new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2, 1 };
237
238    compactEquals(161, sfCreate(minTimestamps, maxTimestamps, sizes),
239      new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2, 1 },
240      new long[] { Long.MIN_VALUE, 24, 48, 72, 96, 120, 144, 150, 156 }, true, true);
241  }
242
243  /**
244   * Major Compaction to check min max timestamp falling in the same window and also to check
245   * boundary condition in which case binary sort gives insertion point as length of the array
246   */
247  @Test
248  public void checkMinMaxTimestampSameBoundary() throws IOException {
249    long[] minTimestamps = new long[] { 0, 26, 50, 90, 98, 122, 145, 151, 158, 166 };
250    long[] maxTimestamps = new long[] { 12, 46, 70, 95, 100, 140, 148, 155, 162, 174 };
251    long[] sizes = new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2 };
252
253    compactEquals(161, sfCreate(minTimestamps, maxTimestamps, sizes),
254      new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2 },
255      new long[] { Long.MIN_VALUE, 24, 48, 72, 96, 120, 144, 150, 156 }, true, true);
256  }
257
258  /**
259   * Major compaction with negative numbers
260   * @throws IOException with error
261   */
262  @Test
263  public void negativeForMajor() throws IOException {
264    long[] minTimestamps =
265      new long[] { -155, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100 };
266    long[] maxTimestamps = new long[] { -8, -7, -6, -5, -4, -3, -2, -1, 0, 6, 13 };
267    long[] sizes = new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2, 1 };
268
269    compactEquals(16, sfCreate(minTimestamps, maxTimestamps, sizes),
270      new long[] { 0, 50, 51, 40, 41, 42, 33, 30, 31, 2, 1 },
271      new long[] { Long.MIN_VALUE, -144, -120, -96, -72, -48, -24, 0, 6, 12 }, true, true);
272  }
273}