HBASE-24033 Add ut for loading the corrupt recovered hfiles (#1322)
[hbase.git] / hbase-server / src / test / java / org / apache / hadoop / hbase / quotas / TestQuotaStatusRPCs.java
blobb8b5eb96d177d187c3a303bf9a659ee4417be653
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.quotas;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertTrue;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.concurrent.atomic.AtomicLong;
28 import java.util.concurrent.atomic.AtomicReference;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.HBaseClassTestRule;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.TableName;
33 import org.apache.hadoop.hbase.Waiter;
34 import org.apache.hadoop.hbase.Waiter.Predicate;
35 import org.apache.hadoop.hbase.client.Connection;
36 import org.apache.hadoop.hbase.client.RegionInfo;
37 import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
38 import org.apache.hadoop.hbase.master.HMaster;
39 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
40 import org.apache.hadoop.hbase.quotas.policies.MissingSnapshotViolationPolicyEnforcement;
41 import org.apache.hadoop.hbase.regionserver.HRegionServer;
42 import org.apache.hadoop.hbase.testclassification.MediumTests;
43 import org.junit.AfterClass;
44 import org.junit.Before;
45 import org.junit.BeforeClass;
46 import org.junit.ClassRule;
47 import org.junit.Rule;
48 import org.junit.Test;
49 import org.junit.experimental.categories.Category;
50 import org.junit.rules.TestName;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
54 /**
55 * Test class for the quota status RPCs in the master and regionserver.
57 @Category({MediumTests.class})
58 public class TestQuotaStatusRPCs {
60 @ClassRule
61 public static final HBaseClassTestRule CLASS_RULE =
62 HBaseClassTestRule.forClass(TestQuotaStatusRPCs.class);
64 private static final Logger LOG = LoggerFactory.getLogger(TestQuotaStatusRPCs.class);
65 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
66 private static final AtomicLong COUNTER = new AtomicLong(0);
68 @Rule
69 public TestName testName = new TestName();
70 private SpaceQuotaHelperForTests helper;
72 @BeforeClass
73 public static void setUp() throws Exception {
74 Configuration conf = TEST_UTIL.getConfiguration();
75 // Increase the frequency of some of the chores for responsiveness of the test
76 SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
77 TEST_UTIL.startMiniCluster(1);
80 @AfterClass
81 public static void tearDown() throws Exception {
82 TEST_UTIL.shutdownMiniCluster();
85 @Before
86 public void setupForTest() throws Exception {
87 helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, COUNTER);
90 @Test
91 public void testRegionSizesFromMaster() throws Exception {
92 final long tableSize = 1024L * 10L; // 10KB
93 final int numRegions = 10;
94 final TableName tn = helper.createTableWithRegions(numRegions);
95 // Will write at least `tableSize` data
96 helper.writeData(tn, tableSize);
98 final HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
99 final MasterQuotaManager quotaManager = master.getMasterQuotaManager();
100 // Make sure the master has all of the reports
101 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
102 @Override
103 public boolean evaluate() throws Exception {
104 Map<RegionInfo,Long> regionSizes = quotaManager.snapshotRegionSizes();
105 LOG.trace("Region sizes=" + regionSizes);
106 return numRegions == countRegionsForTable(tn, regionSizes) &&
107 tableSize <= getTableSize(tn, regionSizes);
111 Map<TableName, Long> sizes = TEST_UTIL.getAdmin().getSpaceQuotaTableSizes();
112 Long size = sizes.get(tn);
113 assertNotNull("No reported size for " + tn, size);
114 assertTrue("Reported table size was " + size, size.longValue() >= tableSize);
117 @Test
118 public void testQuotaSnapshotsFromRS() throws Exception {
119 final long sizeLimit = 1024L * 1024L; // 1MB
120 final long tableSize = 1024L * 10L; // 10KB
121 final int numRegions = 10;
122 final TableName tn = helper.createTableWithRegions(numRegions);
124 // Define the quota
125 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
126 tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
127 TEST_UTIL.getAdmin().setQuota(settings);
129 // Write at least `tableSize` data
130 helper.writeData(tn, tableSize);
132 final HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
133 final RegionServerSpaceQuotaManager manager = rs.getRegionServerSpaceQuotaManager();
134 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
135 @Override
136 public boolean evaluate() throws Exception {
137 SpaceQuotaSnapshot snapshot = manager.copyQuotaSnapshots().get(tn);
138 if (snapshot == null) {
139 return false;
141 return snapshot.getUsage() >= tableSize;
145 @SuppressWarnings("unchecked")
146 Map<TableName, SpaceQuotaSnapshot> snapshots = (Map<TableName, SpaceQuotaSnapshot>) TEST_UTIL
147 .getAdmin().getRegionServerSpaceQuotaSnapshots(rs.getServerName());
148 SpaceQuotaSnapshot snapshot = snapshots.get(tn);
149 assertNotNull("Did not find snapshot for " + tn, snapshot);
150 assertTrue(
151 "Observed table usage was " + snapshot.getUsage(),
152 snapshot.getUsage() >= tableSize);
153 assertEquals(sizeLimit, snapshot.getLimit());
154 SpaceQuotaStatus pbStatus = snapshot.getQuotaStatus();
155 assertFalse(pbStatus.isInViolation());
158 @Test
159 public void testQuotaEnforcementsFromRS() throws Exception {
160 final long sizeLimit = 1024L * 8L; // 8KB
161 final long tableSize = 1024L * 10L; // 10KB
162 final int numRegions = 10;
163 final TableName tn = helper.createTableWithRegions(numRegions);
165 // Define the quota
166 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
167 tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
168 TEST_UTIL.getAdmin().setQuota(settings);
170 // Write at least `tableSize` data
171 try {
172 helper.writeData(tn, tableSize);
173 } catch (RetriesExhaustedWithDetailsException | SpaceLimitingException e) {
174 // Pass
177 final HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
178 final RegionServerSpaceQuotaManager manager = rs.getRegionServerSpaceQuotaManager();
179 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
180 @Override
181 public boolean evaluate() throws Exception {
182 ActivePolicyEnforcement enforcements = manager.getActiveEnforcements();
183 SpaceViolationPolicyEnforcement enforcement = enforcements.getPolicyEnforcement(tn);
184 // Signifies that we're waiting on the quota snapshot to be fetched
185 if (enforcement instanceof MissingSnapshotViolationPolicyEnforcement) {
186 return false;
188 return enforcement.getQuotaSnapshot().getQuotaStatus().isInViolation();
192 // We obtain the violations for a RegionServer by observing the snapshots
193 @SuppressWarnings("unchecked")
194 Map<TableName, SpaceQuotaSnapshot> snapshots = (Map<TableName, SpaceQuotaSnapshot>) TEST_UTIL
195 .getAdmin().getRegionServerSpaceQuotaSnapshots(rs.getServerName());
196 SpaceQuotaSnapshot snapshot = snapshots.get(tn);
197 assertNotNull("Did not find snapshot for " + tn, snapshot);
198 assertTrue(snapshot.getQuotaStatus().isInViolation());
199 assertEquals(SpaceViolationPolicy.NO_INSERTS, snapshot.getQuotaStatus().getPolicy().get());
202 @Test
203 public void testQuotaStatusFromMaster() throws Exception {
204 final long sizeLimit = 1024L * 25L; // 25KB
205 // As of 2.0.0-beta-2, this 1KB of "Cells" actually results in about 15KB on disk (HFiles)
206 // This is skewed a bit since we're writing such little data, so the test needs to keep
207 // this in mind; else, the quota will be in violation before the test expects it to be.
208 final long tableSize = 1024L * 1; // 1KB
209 final long nsLimit = Long.MAX_VALUE;
210 final int numRegions = 10;
211 final TableName tn = helper.createTableWithRegions(numRegions);
213 // Define the quota
214 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
215 tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
216 TEST_UTIL.getAdmin().setQuota(settings);
217 QuotaSettings nsSettings = QuotaSettingsFactory.limitNamespaceSpace(
218 tn.getNamespaceAsString(), nsLimit, SpaceViolationPolicy.NO_INSERTS);
219 TEST_UTIL.getAdmin().setQuota(nsSettings);
221 // Write at least `tableSize` data
222 helper.writeData(tn, tableSize);
224 final Connection conn = TEST_UTIL.getConnection();
225 // Make sure the master has a snapshot for our table
226 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
227 @Override
228 public boolean evaluate() throws Exception {
229 SpaceQuotaSnapshot snapshot =
230 (SpaceQuotaSnapshot) conn.getAdmin().getCurrentSpaceQuotaSnapshot(tn);
231 LOG.info("Table snapshot after initial ingest: " + snapshot);
232 if (snapshot == null) {
233 return false;
235 return snapshot.getLimit() == sizeLimit && snapshot.getUsage() > 0L;
238 final AtomicReference<Long> nsUsage = new AtomicReference<>();
239 // If we saw the table snapshot, we should also see the namespace snapshot
240 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000 * 1000, new Predicate<Exception>() {
241 @Override
242 public boolean evaluate() throws Exception {
243 SpaceQuotaSnapshot snapshot = (SpaceQuotaSnapshot) conn.getAdmin()
244 .getCurrentSpaceQuotaSnapshot(tn.getNamespaceAsString());
245 LOG.debug("Namespace snapshot after initial ingest: " + snapshot);
246 if (snapshot == null) {
247 return false;
249 nsUsage.set(snapshot.getUsage());
250 return snapshot.getLimit() == nsLimit && snapshot.getUsage() > 0;
254 // Sanity check: the below assertions will fail if we somehow write too much data
255 // and force the table to move into violation before we write the second bit of data.
256 SpaceQuotaSnapshot snapshot =
257 (SpaceQuotaSnapshot) conn.getAdmin().getCurrentSpaceQuotaSnapshot(tn);
258 assertTrue("QuotaSnapshot for " + tn + " should be non-null and not in violation",
259 snapshot != null && !snapshot.getQuotaStatus().isInViolation());
261 try {
262 helper.writeData(tn, tableSize * 2L);
263 } catch (RetriesExhaustedWithDetailsException | SpaceLimitingException e) {
264 // Pass
267 // Wait for the status to move to violation
268 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
269 @Override
270 public boolean evaluate() throws Exception {
271 SpaceQuotaSnapshot snapshot =
272 (SpaceQuotaSnapshot) conn.getAdmin().getCurrentSpaceQuotaSnapshot(tn);
273 LOG.info("Table snapshot after second ingest: " + snapshot);
274 if (snapshot == null) {
275 return false;
277 return snapshot.getQuotaStatus().isInViolation();
280 // The namespace should still not be in violation, but have a larger usage than previously
281 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
282 @Override
283 public boolean evaluate() throws Exception {
284 SpaceQuotaSnapshot snapshot = (SpaceQuotaSnapshot) conn.getAdmin()
285 .getCurrentSpaceQuotaSnapshot(tn.getNamespaceAsString());
286 LOG.debug("Namespace snapshot after second ingest: " + snapshot);
287 if (snapshot == null) {
288 return false;
290 return snapshot.getUsage() > nsUsage.get() && !snapshot.getQuotaStatus().isInViolation();
295 private int countRegionsForTable(TableName tn, Map<RegionInfo,Long> regionSizes) {
296 int size = 0;
297 for (RegionInfo regionInfo : regionSizes.keySet()) {
298 if (tn.equals(regionInfo.getTable())) {
299 size++;
302 return size;
305 private int getTableSize(TableName tn, Map<RegionInfo,Long> regionSizes) {
306 int tableSize = 0;
307 for (Entry<RegionInfo,Long> entry : regionSizes.entrySet()) {
308 RegionInfo regionInfo = entry.getKey();
309 long regionSize = entry.getValue();
310 if (tn.equals(regionInfo.getTable())) {
311 tableSize += regionSize;
314 return tableSize;