1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.hadoop.hbase.quotas;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertTrue;
23
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.concurrent.atomic.AtomicLong;
27 import java.util.concurrent.atomic.AtomicReference;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.hbase.HBaseTestingUtility;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.Waiter;
36 import org.apache.hadoop.hbase.Waiter.Predicate;
37 import org.apache.hadoop.hbase.client.Connection;
38 import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
39 import org.apache.hadoop.hbase.master.HMaster;
40 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
41 import org.apache.hadoop.hbase.quotas.policies.MissingSnapshotViolationPolicyEnforcement;
42 import org.apache.hadoop.hbase.regionserver.HRegionServer;
43 import org.apache.hadoop.hbase.testclassification.MediumTests;
44 import org.junit.AfterClass;
45 import org.junit.Before;
46 import org.junit.BeforeClass;
47 import org.junit.Rule;
48 import org.junit.Test;
49 import org.junit.experimental.categories.Category;
50 import org.junit.rules.TestName;
51
52
53
54
55 @Category({MediumTests.class})
56 public class TestQuotaStatusRPCs {
57 private static final Log LOG = LogFactory.getLog(TestQuotaStatusRPCs.class);
58 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
59 private static final AtomicLong COUNTER = new AtomicLong(0);
60
61 @Rule
62 public TestName testName = new TestName();
63 private SpaceQuotaHelperForTests helper;
64
65 @BeforeClass
66 public static void setUp() throws Exception {
67 Configuration conf = TEST_UTIL.getConfiguration();
68
69 conf.setInt(FileSystemUtilizationChore.FS_UTILIZATION_CHORE_DELAY_KEY, 1000);
70 conf.setInt(FileSystemUtilizationChore.FS_UTILIZATION_CHORE_PERIOD_KEY, 1000);
71 conf.setInt(QuotaObserverChore.QUOTA_OBSERVER_CHORE_DELAY_KEY, 1000);
72 conf.setInt(QuotaObserverChore.QUOTA_OBSERVER_CHORE_PERIOD_KEY, 1000);
73 conf.setInt(SpaceQuotaRefresherChore.POLICY_REFRESHER_CHORE_DELAY_KEY, 1000);
74 conf.setInt(SpaceQuotaRefresherChore.POLICY_REFRESHER_CHORE_PERIOD_KEY, 1000);
75 conf.setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
76 TEST_UTIL.startMiniCluster(1);
77 }
78
79 @AfterClass
80 public static void tearDown() throws Exception {
81 TEST_UTIL.shutdownMiniCluster();
82 }
83
84 @Before
85 public void setupForTest() throws Exception {
86 helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, COUNTER);
87 }
88
89 @Test
90 public void testRegionSizesFromMaster() throws Exception {
91 final long tableSize = 1024L * 10L;
92 final int numRegions = 10;
93 final TableName tn = helper.createTableWithRegions(numRegions);
94
95 helper.writeData(tn, tableSize);
96
97 final HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
98 final MasterQuotaManager quotaManager = master.getMasterQuotaManager();
99
100 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
101 @Override
102 public boolean evaluate() throws Exception {
103 Map<HRegionInfo,Long> regionSizes = quotaManager.snapshotRegionSizes();
104 LOG.trace("Region sizes=" + regionSizes);
105 return numRegions == countRegionsForTable(tn, regionSizes) &&
106 tableSize <= getTableSize(tn, regionSizes);
107 }
108 });
109
110 Map<TableName,Long> sizes = QuotaTableUtil.getMasterReportedTableSizes(TEST_UTIL.getConnection());
111 Long size = sizes.get(tn);
112 assertNotNull("No reported size for " + tn, size);
113 assertTrue("Reported table size was " + size, size.longValue() >= tableSize);
114 }
115
116 @Test
117 public void testQuotaSnapshotsFromRS() throws Exception {
118 final long sizeLimit = 1024L * 1024L;
119 final long tableSize = 1024L * 10L;
120 final int numRegions = 10;
121 final TableName tn = helper.createTableWithRegions(numRegions);
122
123
124 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
125 tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
126 TEST_UTIL.getHBaseAdmin().setQuota(settings);
127
128
129 helper.writeData(tn, tableSize);
130
131 final HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
132 final RegionServerSpaceQuotaManager manager = rs.getRegionServerSpaceQuotaManager();
133 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
134 @Override
135 public boolean evaluate() throws Exception {
136 SpaceQuotaSnapshot snapshot = manager.copyQuotaSnapshots().get(tn);
137 if (snapshot == null) {
138 return false;
139 }
140 return snapshot.getUsage() >= tableSize;
141 }
142 });
143
144 Map<TableName, SpaceQuotaSnapshot> snapshots = QuotaTableUtil.getRegionServerQuotaSnapshots(
145 TEST_UTIL.getConnection(), rs.getServerName());
146 SpaceQuotaSnapshot snapshot = snapshots.get(tn);
147 assertNotNull("Did not find snapshot for " + tn, snapshot);
148 assertTrue(
149 "Observed table usage was " + snapshot.getUsage(),
150 snapshot.getUsage() >= tableSize);
151 assertEquals(snapshot.getLimit(), sizeLimit);
152 SpaceQuotaStatus pbStatus = snapshot.getQuotaStatus();
153 assertFalse(pbStatus.isInViolation());
154 }
155
156 @Test
157 public void testQuotaEnforcementsFromRS() throws Exception {
158 final long sizeLimit = 1024L * 8L;
159 final long tableSize = 1024L * 10L;
160 final int numRegions = 10;
161 final TableName tn = helper.createTableWithRegions(numRegions);
162
163
164 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
165 tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
166 TEST_UTIL.getHBaseAdmin().setQuota(settings);
167
168
169 try {
170 helper.writeData(tn, tableSize);
171 } catch (SpaceLimitingException e) {
172
173 }
174
175 final HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
176 final RegionServerSpaceQuotaManager manager = rs.getRegionServerSpaceQuotaManager();
177 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
178 @Override
179 public boolean evaluate() throws Exception {
180 ActivePolicyEnforcement enforcements = manager.getActiveEnforcements();
181 SpaceViolationPolicyEnforcement enforcement = enforcements.getPolicyEnforcement(tn);
182
183 if (enforcement instanceof MissingSnapshotViolationPolicyEnforcement) {
184 return false;
185 }
186 return enforcement.getQuotaSnapshot().getQuotaStatus().isInViolation();
187 }
188 });
189
190
191 Map<TableName,SpaceQuotaSnapshot> snapshots =
192 QuotaTableUtil.getRegionServerQuotaSnapshots(TEST_UTIL.getConnection(), rs.getServerName());
193 SpaceQuotaSnapshot snapshot = snapshots.get(tn);
194 assertNotNull("Did not find snapshot for " + tn, snapshot);
195 assertTrue(snapshot.getQuotaStatus().isInViolation());
196 assertEquals(SpaceViolationPolicy.NO_INSERTS, snapshot.getQuotaStatus().getPolicy());
197 }
198
199 @Test
200 public void testQuotaStatusFromMaster() throws Exception {
201 final long sizeLimit = 1024L * 10L;
202 final long tableSize = 1024L * 5;
203 final long nsLimit = Long.MAX_VALUE;
204 final int numRegions = 10;
205 final TableName tn = helper.createTableWithRegions(numRegions);
206
207
208 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
209 tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
210 TEST_UTIL.getHBaseAdmin().setQuota(settings);
211 QuotaSettings nsSettings = QuotaSettingsFactory.limitNamespaceSpace(
212 tn.getNamespaceAsString(), nsLimit, SpaceViolationPolicy.NO_INSERTS);
213 TEST_UTIL.getHBaseAdmin().setQuota(nsSettings);
214
215
216 helper.writeData(tn, tableSize);
217
218 final Connection conn = TEST_UTIL.getConnection();
219
220 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
221 @Override
222 public boolean evaluate() throws Exception {
223 SpaceQuotaSnapshot snapshot = QuotaTableUtil.getCurrentSnapshot(conn, tn);
224 LOG.info("Table snapshot after initial ingest: " + snapshot);
225 if (snapshot == null) {
226 return false;
227 }
228 return snapshot.getLimit() == sizeLimit && snapshot.getUsage() > 0L;
229 }
230 });
231 final AtomicReference<Long> nsUsage = new AtomicReference<>();
232
233 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000 * 1000, new Predicate<Exception>() {
234 @Override
235 public boolean evaluate() throws Exception {
236 SpaceQuotaSnapshot snapshot = QuotaTableUtil.getCurrentSnapshot(
237 conn, tn.getNamespaceAsString());
238 LOG.debug("Namespace snapshot after initial ingest: " + snapshot);
239 if (snapshot == null) {
240 return false;
241 }
242 nsUsage.set(snapshot.getUsage());
243 return snapshot.getLimit() == nsLimit && snapshot.getUsage() > 0;
244 }
245 });
246
247 try {
248 helper.writeData(tn, tableSize * 2L);
249 } catch (SpaceLimitingException e) {
250
251 } catch (RetriesExhaustedWithDetailsException e) {
252
253 String msg = e.getMessage();
254 assertTrue(
255 "Exception message did not contain expected text. " + msg,
256 msg.contains("Puts are disallowed due to a space quota"));
257 }
258
259
260 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
261 @Override
262 public boolean evaluate() throws Exception {
263 SpaceQuotaSnapshot snapshot = QuotaTableUtil.getCurrentSnapshot(conn, tn);
264 LOG.info("Table snapshot after second ingest: " + snapshot);
265 if (snapshot == null) {
266 return false;
267 }
268 return snapshot.getQuotaStatus().isInViolation();
269 }
270 });
271
272 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Predicate<Exception>() {
273 @Override
274 public boolean evaluate() throws Exception {
275 SpaceQuotaSnapshot snapshot = QuotaTableUtil.getCurrentSnapshot(
276 conn, tn.getNamespaceAsString());
277 LOG.debug("Namespace snapshot after second ingest: " + snapshot);
278 if (snapshot == null) {
279 return false;
280 }
281 return snapshot.getUsage() > nsUsage.get() && !snapshot.getQuotaStatus().isInViolation();
282 }
283 });
284 }
285
286 private int countRegionsForTable(TableName tn, Map<HRegionInfo,Long> regionSizes) {
287 int size = 0;
288 for (HRegionInfo regionInfo : regionSizes.keySet()) {
289 if (tn.equals(regionInfo.getTable())) {
290 size++;
291 }
292 }
293 return size;
294 }
295
296 private int getTableSize(TableName tn, Map<HRegionInfo,Long> regionSizes) {
297 int tableSize = 0;
298 for (Entry<HRegionInfo,Long> entry : regionSizes.entrySet()) {
299 HRegionInfo regionInfo = entry.getKey();
300 long regionSize = entry.getValue();
301 if (tn.equals(regionInfo.getTable())) {
302 tableSize += regionSize;
303 }
304 }
305 return tableSize;
306 }
307 }