HBASE-24033 Add ut for loading the corrupt recovered hfiles (#1322)
[hbase.git] / hbase-server / src / test / java / org / apache / hadoop / hbase / regionserver / TestCompactionLifeCycleTracker.java
blob6cd91a711408cbd4451b83b3067c33fc2cbd4d99
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org.apache.hadoop.hbase.regionserver;
20 import static org.hamcrest.CoreMatchers.containsString;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertThat;
24 import static org.junit.Assert.assertTrue;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Optional;
30 import org.apache.hadoop.hbase.Cell;
31 import org.apache.hadoop.hbase.Cell.Type;
32 import org.apache.hadoop.hbase.CellBuilderFactory;
33 import org.apache.hadoop.hbase.CellBuilderType;
34 import org.apache.hadoop.hbase.HBaseClassTestRule;
35 import org.apache.hadoop.hbase.HBaseTestingUtility;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.TableName;
38 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
39 import org.apache.hadoop.hbase.client.Put;
40 import org.apache.hadoop.hbase.client.Table;
41 import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
42 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
43 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
44 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
45 import org.apache.hadoop.hbase.coprocessor.RegionObserver;
46 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot;
47 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
48 import org.apache.hadoop.hbase.quotas.SpaceViolationPolicy;
49 import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
50 import org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTracker;
51 import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest;
52 import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
53 import org.apache.hadoop.hbase.testclassification.MediumTests;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.Pair;
56 import org.junit.After;
57 import org.junit.AfterClass;
58 import org.junit.Before;
59 import org.junit.BeforeClass;
60 import org.junit.ClassRule;
61 import org.junit.Ignore;
62 import org.junit.Test;
63 import org.junit.experimental.categories.Category;
65 /**
66 * Confirm that the function of CompactionLifeCycleTracker is OK as we do not use it in our own
67 * code.
69 @Category({ CoprocessorTests.class, MediumTests.class })
70 public class TestCompactionLifeCycleTracker {
72 @ClassRule
73 public static final HBaseClassTestRule CLASS_RULE =
74 HBaseClassTestRule.forClass(TestCompactionLifeCycleTracker.class);
76 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
78 private static final TableName NAME =
79 TableName.valueOf(TestCompactionLifeCycleTracker.class.getSimpleName());
81 private static final byte[] CF1 = Bytes.toBytes("CF1");
83 private static final byte[] CF2 = Bytes.toBytes("CF2");
85 private static final byte[] QUALIFIER = Bytes.toBytes("CQ");
87 private HRegion region;
89 private static CompactionLifeCycleTracker TRACKER = null;
91 // make sure that we pass the correct CompactionLifeCycleTracker to CP hooks.
92 public static final class CompactionObserver implements RegionObserver, RegionCoprocessor {
94 @Override
95 public Optional<RegionObserver> getRegionObserver() {
96 return Optional.of(this);
99 @Override
100 public void preCompactSelection(ObserverContext<RegionCoprocessorEnvironment> c, Store store,
101 List<? extends StoreFile> candidates, CompactionLifeCycleTracker tracker)
102 throws IOException {
103 if (TRACKER != null) {
104 assertSame(tracker, TRACKER);
108 @Override
109 public void postCompactSelection(ObserverContext<RegionCoprocessorEnvironment> c, Store store,
110 List<? extends StoreFile> selected, CompactionLifeCycleTracker tracker,
111 CompactionRequest request) {
112 if (TRACKER != null) {
113 assertSame(tracker, TRACKER);
117 @Override
118 public InternalScanner preCompact(ObserverContext<RegionCoprocessorEnvironment> c, Store store,
119 InternalScanner scanner, ScanType scanType, CompactionLifeCycleTracker tracker,
120 CompactionRequest request) throws IOException {
121 if (TRACKER != null) {
122 assertSame(tracker, TRACKER);
124 return scanner;
127 @Override
128 public void postCompact(ObserverContext<RegionCoprocessorEnvironment> c, Store store,
129 StoreFile resultFile, CompactionLifeCycleTracker tracker, CompactionRequest request)
130 throws IOException {
131 if (TRACKER != null) {
132 assertSame(tracker, TRACKER);
137 @BeforeClass
138 public static void setUpBeforeClass() throws Exception {
139 UTIL.getConfiguration().setInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY, 2);
140 UTIL.startMiniCluster(3);
143 @AfterClass
144 public static void tearDownAfterClass() throws Exception {
145 UTIL.shutdownMiniCluster();
148 @Before
149 public void setUp() throws IOException {
150 UTIL.getAdmin()
151 .createTable(TableDescriptorBuilder.newBuilder(NAME)
152 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(CF1))
153 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(CF2))
154 .setCoprocessor(CompactionObserver.class.getName()).build());
155 try (Table table = UTIL.getConnection().getTable(NAME)) {
156 for (int i = 0; i < 100; i++) {
157 byte[] row = Bytes.toBytes(i);
158 table.put(new Put(row)
159 .add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
160 .setRow(row)
161 .setFamily(CF1)
162 .setQualifier(QUALIFIER)
163 .setTimestamp(HConstants.LATEST_TIMESTAMP)
164 .setType(Cell.Type.Put)
165 .setValue(Bytes.toBytes(i))
166 .build()));
168 UTIL.getAdmin().flush(NAME);
169 for (int i = 100; i < 200; i++) {
170 byte[] row = Bytes.toBytes(i);
171 table.put(new Put(row)
172 .add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
173 .setRow(row)
174 .setFamily(CF1)
175 .setQualifier(QUALIFIER)
176 .setTimestamp(HConstants.LATEST_TIMESTAMP)
177 .setType(Type.Put)
178 .setValue(Bytes.toBytes(i))
179 .build()));
181 UTIL.getAdmin().flush(NAME);
183 region = UTIL.getHBaseCluster().getRegions(NAME).get(0);
184 assertEquals(2, region.getStore(CF1).getStorefilesCount());
185 assertEquals(0, region.getStore(CF2).getStorefilesCount());
188 @After
189 public void tearDown() throws IOException {
190 region = null;
191 TRACKER = null;
192 UTIL.deleteTable(NAME);
195 private static final class Tracker implements CompactionLifeCycleTracker {
197 final List<Pair<Store, String>> notExecutedStores = new ArrayList<>();
199 final List<Store> beforeExecuteStores = new ArrayList<>();
201 final List<Store> afterExecuteStores = new ArrayList<>();
203 private boolean completed = false;
205 @Override
206 public void notExecuted(Store store, String reason) {
207 notExecutedStores.add(Pair.newPair(store, reason));
210 @Override
211 public void beforeExecution(Store store) {
212 beforeExecuteStores.add(store);
215 @Override
216 public void afterExecution(Store store) {
217 afterExecuteStores.add(store);
220 @Override
221 public synchronized void completed() {
222 completed = true;
223 notifyAll();
226 public synchronized void await() throws InterruptedException {
227 while (!completed) {
228 wait();
233 @Test
234 public void testRequestOnRegion() throws IOException, InterruptedException {
235 Tracker tracker = new Tracker();
236 TRACKER = tracker;
237 region.requestCompaction("test", Store.PRIORITY_USER, false, tracker);
238 tracker.await();
239 assertEquals(1, tracker.notExecutedStores.size());
240 assertEquals(Bytes.toString(CF2),
241 tracker.notExecutedStores.get(0).getFirst().getColumnFamilyName());
242 assertThat(tracker.notExecutedStores.get(0).getSecond(),
243 containsString("compaction request was cancelled"));
245 assertEquals(1, tracker.beforeExecuteStores.size());
246 assertEquals(Bytes.toString(CF1), tracker.beforeExecuteStores.get(0).getColumnFamilyName());
248 assertEquals(1, tracker.afterExecuteStores.size());
249 assertEquals(Bytes.toString(CF1), tracker.afterExecuteStores.get(0).getColumnFamilyName());
252 @Test
253 public void testRequestOnStore() throws IOException, InterruptedException {
254 Tracker tracker = new Tracker();
255 TRACKER = tracker;
256 region.requestCompaction(CF1, "test", Store.PRIORITY_USER, false, tracker);
257 tracker.await();
258 assertTrue(tracker.notExecutedStores.isEmpty());
259 assertEquals(1, tracker.beforeExecuteStores.size());
260 assertEquals(Bytes.toString(CF1), tracker.beforeExecuteStores.get(0).getColumnFamilyName());
261 assertEquals(1, tracker.afterExecuteStores.size());
262 assertEquals(Bytes.toString(CF1), tracker.afterExecuteStores.get(0).getColumnFamilyName());
264 tracker = new Tracker();
265 TRACKER = tracker;
266 region.requestCompaction(CF2, "test", Store.PRIORITY_USER, false, tracker);
267 tracker.await();
268 assertEquals(1, tracker.notExecutedStores.size());
269 assertEquals(Bytes.toString(CF2),
270 tracker.notExecutedStores.get(0).getFirst().getColumnFamilyName());
271 assertThat(tracker.notExecutedStores.get(0).getSecond(),
272 containsString("compaction request was cancelled"));
273 assertTrue(tracker.beforeExecuteStores.isEmpty());
274 assertTrue(tracker.afterExecuteStores.isEmpty());
277 // This test assumes that compaction wouldn't happen with null user.
278 // But null user means system generated compaction so compaction should happen
279 // even if the space quota is violated. So this test should be removed/ignored.
280 @Ignore @Test
281 public void testSpaceQuotaViolation() throws IOException, InterruptedException {
282 region.getRegionServerServices().getRegionServerSpaceQuotaManager().enforceViolationPolicy(NAME,
283 new SpaceQuotaSnapshot(new SpaceQuotaStatus(SpaceViolationPolicy.NO_WRITES_COMPACTIONS), 10L,
284 100L));
285 Tracker tracker = new Tracker();
286 TRACKER = tracker;
287 region.requestCompaction("test", Store.PRIORITY_USER, false, tracker);
288 tracker.await();
289 assertEquals(2, tracker.notExecutedStores.size());
290 tracker.notExecutedStores.sort((p1, p2) -> p1.getFirst().getColumnFamilyName()
291 .compareTo(p2.getFirst().getColumnFamilyName()));
293 assertEquals(Bytes.toString(CF2),
294 tracker.notExecutedStores.get(1).getFirst().getColumnFamilyName());
295 assertThat(tracker.notExecutedStores.get(1).getSecond(),
296 containsString("space quota violation"));
298 assertTrue(tracker.beforeExecuteStores.isEmpty());
299 assertTrue(tracker.afterExecuteStores.isEmpty());