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
;
66 * Confirm that the function of CompactionLifeCycleTracker is OK as we do not use it in our own
69 @Category({ CoprocessorTests
.class, MediumTests
.class })
70 public class TestCompactionLifeCycleTracker
{
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
{
95 public Optional
<RegionObserver
> getRegionObserver() {
96 return Optional
.of(this);
100 public void preCompactSelection(ObserverContext
<RegionCoprocessorEnvironment
> c
, Store store
,
101 List
<?
extends StoreFile
> candidates
, CompactionLifeCycleTracker tracker
)
103 if (TRACKER
!= null) {
104 assertSame(tracker
, TRACKER
);
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
);
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
);
128 public void postCompact(ObserverContext
<RegionCoprocessorEnvironment
> c
, Store store
,
129 StoreFile resultFile
, CompactionLifeCycleTracker tracker
, CompactionRequest request
)
131 if (TRACKER
!= null) {
132 assertSame(tracker
, TRACKER
);
138 public static void setUpBeforeClass() throws Exception
{
139 UTIL
.getConfiguration().setInt(CompactionConfiguration
.HBASE_HSTORE_COMPACTION_MIN_KEY
, 2);
140 UTIL
.startMiniCluster(3);
144 public static void tearDownAfterClass() throws Exception
{
145 UTIL
.shutdownMiniCluster();
149 public void setUp() throws IOException
{
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
)
162 .setQualifier(QUALIFIER
)
163 .setTimestamp(HConstants
.LATEST_TIMESTAMP
)
164 .setType(Cell
.Type
.Put
)
165 .setValue(Bytes
.toBytes(i
))
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
)
175 .setQualifier(QUALIFIER
)
176 .setTimestamp(HConstants
.LATEST_TIMESTAMP
)
178 .setValue(Bytes
.toBytes(i
))
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());
189 public void tearDown() throws IOException
{
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;
206 public void notExecuted(Store store
, String reason
) {
207 notExecutedStores
.add(Pair
.newPair(store
, reason
));
211 public void beforeExecution(Store store
) {
212 beforeExecuteStores
.add(store
);
216 public void afterExecution(Store store
) {
217 afterExecuteStores
.add(store
);
221 public synchronized void completed() {
226 public synchronized void await() throws InterruptedException
{
234 public void testRequestOnRegion() throws IOException
, InterruptedException
{
235 Tracker tracker
= new Tracker();
237 region
.requestCompaction("test", Store
.PRIORITY_USER
, false, tracker
);
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());
253 public void testRequestOnStore() throws IOException
, InterruptedException
{
254 Tracker tracker
= new Tracker();
256 region
.requestCompaction(CF1
, "test", Store
.PRIORITY_USER
, false, tracker
);
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();
266 region
.requestCompaction(CF2
, "test", Store
.PRIORITY_USER
, false, tracker
);
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.
281 public void testSpaceQuotaViolation() throws IOException
, InterruptedException
{
282 region
.getRegionServerServices().getRegionServerSpaceQuotaManager().enforceViolationPolicy(NAME
,
283 new SpaceQuotaSnapshot(new SpaceQuotaStatus(SpaceViolationPolicy
.NO_WRITES_COMPACTIONS
), 10L,
285 Tracker tracker
= new Tracker();
287 region
.requestCompaction("test", Store
.PRIORITY_USER
, false, tracker
);
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());