HBASE-22895 Fix the flakey TestSpaceQuotas (#526)
Break down TestSpaceQuotas(TSQ) into TSQBasicFunctioning, TSQDropTable, TSQIncrease, TSQOnBulkLoad, TSQOnNonExistingTables, TSQRemoval & TSQSwitchPolicies Signed-off-by: Stack <stack@apache.org>
This commit is contained in:
parent
df0a40f61f
commit
fe689bf1d4
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.quotas;
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -29,21 +31,38 @@ import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
import org.apache.hadoop.hbase.HColumnDescriptor;
|
import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||||
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||||
import org.apache.hadoop.hbase.MiniHBaseCluster;
|
import org.apache.hadoop.hbase.MiniHBaseCluster;
|
||||||
import org.apache.hadoop.hbase.NamespaceDescriptor;
|
import org.apache.hadoop.hbase.NamespaceDescriptor;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.TableNotEnabledException;
|
||||||
import org.apache.hadoop.hbase.Waiter.Predicate;
|
import org.apache.hadoop.hbase.Waiter.Predicate;
|
||||||
import org.apache.hadoop.hbase.client.Admin;
|
import org.apache.hadoop.hbase.client.Admin;
|
||||||
|
import org.apache.hadoop.hbase.client.Append;
|
||||||
|
import org.apache.hadoop.hbase.client.ClientServiceCallable;
|
||||||
import org.apache.hadoop.hbase.client.Connection;
|
import org.apache.hadoop.hbase.client.Connection;
|
||||||
|
import org.apache.hadoop.hbase.client.Delete;
|
||||||
|
import org.apache.hadoop.hbase.client.Increment;
|
||||||
|
import org.apache.hadoop.hbase.client.Mutation;
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.client.Result;
|
||||||
|
import org.apache.hadoop.hbase.client.ResultScanner;
|
||||||
|
import org.apache.hadoop.hbase.client.Scan;
|
||||||
|
import org.apache.hadoop.hbase.client.SecureBulkLoadClient;
|
||||||
import org.apache.hadoop.hbase.client.Table;
|
import org.apache.hadoop.hbase.client.Table;
|
||||||
|
import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
import org.apache.hadoop.hbase.regionserver.HStore;
|
import org.apache.hadoop.hbase.regionserver.HStore;
|
||||||
import org.apache.hadoop.hbase.regionserver.HStoreFile;
|
import org.apache.hadoop.hbase.regionserver.HStoreFile;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.TestHRegionServerBulkLoad;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.apache.hadoop.hbase.util.Pair;
|
||||||
|
import org.apache.hadoop.util.StringUtils;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
import org.junit.rules.TestName;
|
import org.junit.rules.TestName;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -65,6 +84,7 @@ public class SpaceQuotaHelperForTests {
|
||||||
private final HBaseTestingUtility testUtil;
|
private final HBaseTestingUtility testUtil;
|
||||||
private final TestName testName;
|
private final TestName testName;
|
||||||
private final AtomicLong counter;
|
private final AtomicLong counter;
|
||||||
|
private static final int NUM_RETRIES = 10;
|
||||||
|
|
||||||
public SpaceQuotaHelperForTests(
|
public SpaceQuotaHelperForTests(
|
||||||
HBaseTestingUtility testUtil, TestName testName, AtomicLong counter) {
|
HBaseTestingUtility testUtil, TestName testName, AtomicLong counter) {
|
||||||
|
@ -110,16 +130,214 @@ public class SpaceQuotaHelperForTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given mutation into a table until it violates the given policy.
|
||||||
|
* Verifies that the policy has been violated & then returns the name of
|
||||||
|
* the table created & written into.
|
||||||
|
*/
|
||||||
|
TableName writeUntilViolationAndVerifyViolation(
|
||||||
|
SpaceViolationPolicy policyToViolate, Mutation m) throws Exception {
|
||||||
|
final TableName tn = writeUntilViolation(policyToViolate);
|
||||||
|
verifyViolation(policyToViolate, tn, m);
|
||||||
|
return tn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given mutation into a table until it violates the given policy.
|
||||||
|
* Returns the name of the table created & written into.
|
||||||
|
*/
|
||||||
|
TableName writeUntilViolation(SpaceViolationPolicy policyToViolate) throws Exception {
|
||||||
|
TableName tn = createTableWithRegions(10);
|
||||||
|
setQuotaLimit(tn, policyToViolate, 2L);
|
||||||
|
// Write more data than should be allowed and flush it to disk
|
||||||
|
writeData(tn, 3L * SpaceQuotaHelperForTests.ONE_MEGABYTE);
|
||||||
|
|
||||||
|
// This should be sufficient time for the chores to run and see the change.
|
||||||
|
Thread.sleep(5000);
|
||||||
|
|
||||||
|
return tn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that the given policy on the given table has been violated
|
||||||
|
*/
|
||||||
|
void verifyViolation(SpaceViolationPolicy policyToViolate, TableName tn, Mutation m)
|
||||||
|
throws Exception {
|
||||||
|
// But let's try a few times to get the exception before failing
|
||||||
|
boolean sawError = false;
|
||||||
|
String msg = "";
|
||||||
|
for (int i = 0; i < NUM_RETRIES && !sawError; i++) {
|
||||||
|
try (Table table = testUtil.getConnection().getTable(tn)) {
|
||||||
|
if (m instanceof Put) {
|
||||||
|
table.put((Put) m);
|
||||||
|
} else if (m instanceof Delete) {
|
||||||
|
table.delete((Delete) m);
|
||||||
|
} else if (m instanceof Append) {
|
||||||
|
table.append((Append) m);
|
||||||
|
} else if (m instanceof Increment) {
|
||||||
|
table.increment((Increment) m);
|
||||||
|
} else {
|
||||||
|
fail(
|
||||||
|
"Failed to apply " + m.getClass().getSimpleName() +
|
||||||
|
" to the table. Programming error");
|
||||||
|
}
|
||||||
|
LOG.info("Did not reject the " + m.getClass().getSimpleName() + ", will sleep and retry");
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
msg = StringUtils.stringifyException(e);
|
||||||
|
if ((policyToViolate.equals(SpaceViolationPolicy.DISABLE)
|
||||||
|
&& e instanceof TableNotEnabledException) || msg.contains(policyToViolate.name())) {
|
||||||
|
LOG.info("Got the expected exception={}", msg);
|
||||||
|
sawError = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
LOG.warn("Did not get the expected exception, will sleep and retry", e);
|
||||||
|
Thread.sleep(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sawError) {
|
||||||
|
try (Table quotaTable = testUtil.getConnection().getTable(QuotaUtil.QUOTA_TABLE_NAME)) {
|
||||||
|
ResultScanner scanner = quotaTable.getScanner(new Scan());
|
||||||
|
Result result = null;
|
||||||
|
LOG.info("Dumping contents of hbase:quota table");
|
||||||
|
while ((result = scanner.next()) != null) {
|
||||||
|
LOG.info(Bytes.toString(result.getRow()) + " => " + result.toString());
|
||||||
|
}
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (policyToViolate.equals(SpaceViolationPolicy.DISABLE)) {
|
||||||
|
assertTrue(
|
||||||
|
msg.contains("TableNotEnabledException") || msg.contains(policyToViolate.name()));
|
||||||
|
} else {
|
||||||
|
assertTrue("Expected exception message to contain the word '" + policyToViolate.name()
|
||||||
|
+ "', but was " + msg,
|
||||||
|
msg.contains(policyToViolate.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(
|
||||||
|
"Expected to see an exception writing data to a table exceeding its quota", sawError);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that no policy has been violated on the given table
|
||||||
|
*/
|
||||||
|
void verifyNoViolation(TableName tn, Mutation m) throws Exception {
|
||||||
|
// But let's try a few times to write data before failing
|
||||||
|
boolean sawSuccess = false;
|
||||||
|
for (int i = 0; i < NUM_RETRIES && !sawSuccess; i++) {
|
||||||
|
try (Table table = testUtil.getConnection().getTable(tn)) {
|
||||||
|
if (m instanceof Put) {
|
||||||
|
table.put((Put) m);
|
||||||
|
} else if (m instanceof Delete) {
|
||||||
|
table.delete((Delete) m);
|
||||||
|
} else if (m instanceof Append) {
|
||||||
|
table.append((Append) m);
|
||||||
|
} else if (m instanceof Increment) {
|
||||||
|
table.increment((Increment) m);
|
||||||
|
} else {
|
||||||
|
fail("Failed to apply " + m.getClass().getSimpleName() + " to the table."
|
||||||
|
+ " Programming error");
|
||||||
|
}
|
||||||
|
sawSuccess = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.info("Rejected the " + m.getClass().getSimpleName() + ", will sleep and retry");
|
||||||
|
Thread.sleep(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sawSuccess) {
|
||||||
|
try (Table quotaTable = testUtil.getConnection().getTable(QuotaUtil.QUOTA_TABLE_NAME)) {
|
||||||
|
ResultScanner scanner = quotaTable.getScanner(new Scan());
|
||||||
|
Result result = null;
|
||||||
|
LOG.info("Dumping contents of hbase:quota table");
|
||||||
|
while ((result = scanner.next()) != null) {
|
||||||
|
LOG.info(Bytes.toString(result.getRow()) + " => " + result.toString());
|
||||||
|
}
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue("Expected to succeed in writing data to a table not having quota ", sawSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the given quota (policy & limit) on the passed table.
|
||||||
|
*/
|
||||||
|
void setQuotaLimit(final TableName tn, SpaceViolationPolicy policy, long sizeInMBs)
|
||||||
|
throws Exception {
|
||||||
|
final long sizeLimit = sizeInMBs * SpaceQuotaHelperForTests.ONE_MEGABYTE;
|
||||||
|
QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(tn, sizeLimit, policy);
|
||||||
|
testUtil.getAdmin().setQuota(settings);
|
||||||
|
LOG.debug("Quota limit set for table = {}, limit = {}", tn, sizeLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the space quota from the given table
|
||||||
|
*/
|
||||||
|
void removeQuotaFromtable(final TableName tn) throws Exception {
|
||||||
|
QuotaSettings removeQuota = QuotaSettingsFactory.removeTableSpaceLimit(tn);
|
||||||
|
testUtil.getAdmin().setQuota(removeQuota);
|
||||||
|
LOG.debug("Space quota settings removed from the table ", tn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param tn the tablename
|
||||||
|
* @param numFiles number of files
|
||||||
|
* @param numRowsPerFile number of rows per file
|
||||||
|
* @return a clientServiceCallable which can be used with the Caller factory for bulk load
|
||||||
|
* @throws Exception when failed to get connection, table or preparation of the bulk load
|
||||||
|
*/
|
||||||
|
ClientServiceCallable<Void> generateFileToLoad(TableName tn, int numFiles, int numRowsPerFile)
|
||||||
|
throws Exception {
|
||||||
|
Connection conn = testUtil.getConnection();
|
||||||
|
FileSystem fs = testUtil.getTestFileSystem();
|
||||||
|
Configuration conf = testUtil.getConfiguration();
|
||||||
|
Path baseDir = new Path(fs.getHomeDirectory(), testName.getMethodName() + "_files");
|
||||||
|
fs.mkdirs(baseDir);
|
||||||
|
final List<Pair<byte[], String>> famPaths = new ArrayList<Pair<byte[], String>>();
|
||||||
|
for (int i = 1; i <= numFiles; i++) {
|
||||||
|
Path hfile = new Path(baseDir, "file" + i);
|
||||||
|
TestHRegionServerBulkLoad
|
||||||
|
.createHFile(fs, hfile, Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"), numRowsPerFile);
|
||||||
|
famPaths.add(new Pair<>(Bytes.toBytes(SpaceQuotaHelperForTests.F1), hfile.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// bulk load HFiles
|
||||||
|
Table table = conn.getTable(tn);
|
||||||
|
final String bulkToken = new SecureBulkLoadClient(conf, table).prepareBulkLoad(conn);
|
||||||
|
return new ClientServiceCallable<Void>(conn, tn, Bytes.toBytes("row"),
|
||||||
|
new RpcControllerFactory(conf).newController(), HConstants.PRIORITY_UNSET) {
|
||||||
|
@Override
|
||||||
|
public Void rpcCall() throws Exception {
|
||||||
|
SecureBulkLoadClient secureClient = null;
|
||||||
|
byte[] regionName = getLocation().getRegionInfo().getRegionName();
|
||||||
|
try (Table table = conn.getTable(getTableName())) {
|
||||||
|
secureClient = new SecureBulkLoadClient(conf, table);
|
||||||
|
secureClient.secureBulkLoadHFiles(getStub(), famPaths, regionName, true, null, bulkToken);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all quotas defined in the HBase quota table.
|
* Removes all quotas defined in the HBase quota table.
|
||||||
*/
|
*/
|
||||||
void removeAllQuotas(Connection conn) throws IOException, InterruptedException {
|
void removeAllQuotas() throws Exception {
|
||||||
|
final Connection conn = testUtil.getConnection();
|
||||||
|
removeAllQuotas(conn);
|
||||||
|
assertEquals(0, listNumDefinedQuotas(conn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all quotas defined in the HBase quota table.
|
||||||
|
*/
|
||||||
|
void removeAllQuotas(Connection conn) throws IOException {
|
||||||
// Wait for the quota table to be created
|
// Wait for the quota table to be created
|
||||||
if (!conn.getAdmin().tableExists(QuotaUtil.QUOTA_TABLE_NAME)) {
|
if (!conn.getAdmin().tableExists(QuotaUtil.QUOTA_TABLE_NAME)) {
|
||||||
do {
|
waitForQuotaTable(conn);
|
||||||
LOG.debug("Quota table does not yet exist");
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} while (!conn.getAdmin().tableExists(QuotaUtil.QUOTA_TABLE_NAME));
|
|
||||||
} else {
|
} else {
|
||||||
// Or, clean up any quotas from previous test runs.
|
// Or, clean up any quotas from previous test runs.
|
||||||
QuotaRetriever scanner = QuotaRetriever.open(conn.getConfiguration());
|
QuotaRetriever scanner = QuotaRetriever.open(conn.getConfiguration());
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Admin;
|
||||||
|
import org.apache.hadoop.hbase.client.Append;
|
||||||
|
import org.apache.hadoop.hbase.client.Delete;
|
||||||
|
import org.apache.hadoop.hbase.client.Increment;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.client.Table;
|
||||||
|
import org.apache.hadoop.hbase.security.AccessDeniedException;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.apache.hadoop.util.StringUtils;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@Category(LargeTests.class)
|
||||||
|
public class TestSpaceQuotaBasicFunctioning {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaBasicFunctioning.class);
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TestSpaceQuotaBasicFunctioning.class);
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
private static final int NUM_RETRIES = 10;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoInsertsWithPut() throws Exception {
|
||||||
|
Put p = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
p.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_INSERTS, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoInsertsWithAppend() throws Exception {
|
||||||
|
Append a = new Append(Bytes.toBytes("to_reject"));
|
||||||
|
a.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_INSERTS, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoInsertsWithIncrement() throws Exception {
|
||||||
|
Increment i = new Increment(Bytes.toBytes("to_reject"));
|
||||||
|
i.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("count"), 0);
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_INSERTS, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletesAfterNoInserts() throws Exception {
|
||||||
|
final TableName tn = helper.writeUntilViolation(SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
// Try a couple of times to verify that the quota never gets enforced, same as we
|
||||||
|
// do when we're trying to catch the failure.
|
||||||
|
Delete d = new Delete(Bytes.toBytes("should_not_be_rejected"));
|
||||||
|
for (int i = 0; i < NUM_RETRIES; i++) {
|
||||||
|
try (Table t = TEST_UTIL.getConnection().getTable(tn)) {
|
||||||
|
t.delete(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoWritesWithPut() throws Exception {
|
||||||
|
Put p = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
p.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoWritesWithAppend() throws Exception {
|
||||||
|
Append a = new Append(Bytes.toBytes("to_reject"));
|
||||||
|
a.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoWritesWithIncrement() throws Exception {
|
||||||
|
Increment i = new Increment(Bytes.toBytes("to_reject"));
|
||||||
|
i.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("count"), 0);
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoWritesWithDelete() throws Exception {
|
||||||
|
Delete d = new Delete(Bytes.toBytes("to_reject"));
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCompactions() throws Exception {
|
||||||
|
Put p = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
p.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
final TableName tn =
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES_COMPACTIONS, p);
|
||||||
|
// We know the policy is active at this point
|
||||||
|
|
||||||
|
// Major compactions should be rejected
|
||||||
|
try {
|
||||||
|
TEST_UTIL.getAdmin().majorCompact(tn);
|
||||||
|
fail("Expected that invoking the compaction should throw an Exception");
|
||||||
|
} catch (DoNotRetryIOException e) {
|
||||||
|
// Expected!
|
||||||
|
}
|
||||||
|
// Minor compactions should also be rejected.
|
||||||
|
try {
|
||||||
|
TEST_UTIL.getAdmin().compact(tn);
|
||||||
|
fail("Expected that invoking the compaction should throw an Exception");
|
||||||
|
} catch (DoNotRetryIOException e) {
|
||||||
|
// Expected!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoEnableAfterDisablePolicy() throws Exception {
|
||||||
|
Put p = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
p.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
final TableName tn = helper.writeUntilViolation(SpaceViolationPolicy.DISABLE);
|
||||||
|
final Admin admin = TEST_UTIL.getAdmin();
|
||||||
|
// Disabling a table relies on some external action (over the other policies), so wait a bit
|
||||||
|
// more than the other tests.
|
||||||
|
for (int i = 0; i < NUM_RETRIES * 2; i++) {
|
||||||
|
if (admin.isTableEnabled(tn)) {
|
||||||
|
LOG.info(tn + " is still enabled, expecting it to be disabled. Will wait and re-check.");
|
||||||
|
Thread.sleep(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertFalse(tn + " is still enabled but it should be disabled", admin.isTableEnabled(tn));
|
||||||
|
try {
|
||||||
|
admin.enableTable(tn);
|
||||||
|
} catch (AccessDeniedException e) {
|
||||||
|
String exceptionContents = StringUtils.stringifyException(e);
|
||||||
|
final String expectedText = "violated space quota";
|
||||||
|
assertTrue(
|
||||||
|
"Expected the exception to contain " + expectedText + ", but was: " + exceptionContents,
|
||||||
|
exceptionContents.contains(expectedText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTableQuotaOverridesNamespaceQuota() throws Exception {
|
||||||
|
final SpaceViolationPolicy policy = SpaceViolationPolicy.NO_INSERTS;
|
||||||
|
final TableName tn = helper.createTableWithRegions(10);
|
||||||
|
|
||||||
|
// 2MB limit on the table, 1GB limit on the namespace
|
||||||
|
final long tableLimit = 2L * SpaceQuotaHelperForTests.ONE_MEGABYTE;
|
||||||
|
final long namespaceLimit = 1024L * SpaceQuotaHelperForTests.ONE_MEGABYTE;
|
||||||
|
TEST_UTIL.getAdmin().setQuota(QuotaSettingsFactory.limitTableSpace(tn, tableLimit, policy));
|
||||||
|
TEST_UTIL.getAdmin().setQuota(QuotaSettingsFactory
|
||||||
|
.limitNamespaceSpace(tn.getNamespaceAsString(), namespaceLimit, policy));
|
||||||
|
|
||||||
|
// Write more data than should be allowed and flush it to disk
|
||||||
|
helper.writeData(tn, 3L * SpaceQuotaHelperForTests.ONE_MEGABYTE);
|
||||||
|
|
||||||
|
// This should be sufficient time for the chores to run and see the change.
|
||||||
|
Thread.sleep(5000);
|
||||||
|
|
||||||
|
// The write should be rejected because the table quota takes priority over the namespace
|
||||||
|
Put p = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
p.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
helper.verifyViolation(policy, tn, p);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@Category(LargeTests.class)
|
||||||
|
public class TestSpaceQuotaDropTable {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaDropTable.class);
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TestSpaceQuotaDropTable.class);
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDropTableWithNoInserts() throws Exception {
|
||||||
|
setQuotaAndThenDropTable(SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDropTableWithNoWrite() throws Exception {
|
||||||
|
setQuotaAndThenDropTable(SpaceViolationPolicy.NO_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDropTableWithNoWritesCompactions() throws Exception {
|
||||||
|
setQuotaAndThenDropTable(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDropTableWithDisable() throws Exception {
|
||||||
|
setQuotaAndThenDropTable(SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuotaAndThenDropTable(SpaceViolationPolicy policy) throws Exception {
|
||||||
|
Put put = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
|
||||||
|
// Do puts until we violate space policy
|
||||||
|
final TableName tn = helper.writeUntilViolationAndVerifyViolation(policy, put);
|
||||||
|
|
||||||
|
// Now, drop the table
|
||||||
|
TEST_UTIL.deleteTable(tn);
|
||||||
|
LOG.debug("Successfully deleted table ", tn);
|
||||||
|
|
||||||
|
// Now re-create the table
|
||||||
|
TEST_UTIL.createTable(tn, Bytes.toBytes(SpaceQuotaHelperForTests.F1));
|
||||||
|
LOG.debug("Successfully re-created table ", tn);
|
||||||
|
|
||||||
|
// Put some rows now: should not violate as table/quota was dropped
|
||||||
|
helper.verifyNoViolation(tn, put);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
|
@Category(LargeTests.class)
|
||||||
|
public class TestSpaceQuotaIncrease {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaIncrease.class);
|
||||||
|
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenIncreaseQuotaWithNoInserts() throws Exception {
|
||||||
|
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenIncreaseQuotaWithNoWrite() throws Exception {
|
||||||
|
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.NO_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenIncreaseQuotaWithNoWritesCompactions() throws Exception {
|
||||||
|
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenIncreaseQuotaWithDisable() throws Exception {
|
||||||
|
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuotaAndThenIncreaseQuota(SpaceViolationPolicy policy) throws Exception {
|
||||||
|
Put put = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
|
||||||
|
// Do puts until we violate space policy
|
||||||
|
final TableName tn = helper.writeUntilViolationAndVerifyViolation(policy, put);
|
||||||
|
|
||||||
|
// Now, increase limit and perform put
|
||||||
|
helper.setQuotaLimit(tn, policy, 4L);
|
||||||
|
|
||||||
|
// Put some row now: should not violate as quota limit increased
|
||||||
|
helper.verifyNoViolation(tn, put);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FileStatus;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.ClientServiceCallable;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.client.RegionInfo;
|
||||||
|
import org.apache.hadoop.hbase.client.ResultScanner;
|
||||||
|
import org.apache.hadoop.hbase.client.RpcRetryingCaller;
|
||||||
|
import org.apache.hadoop.hbase.client.RpcRetryingCallerFactory;
|
||||||
|
import org.apache.hadoop.hbase.client.Scan;
|
||||||
|
import org.apache.hadoop.hbase.client.Table;
|
||||||
|
import org.apache.hadoop.hbase.master.HMaster;
|
||||||
|
import org.apache.hadoop.hbase.quotas.policies.DefaultViolationPolicyEnforcement;
|
||||||
|
import org.apache.hadoop.hbase.regionserver.HRegionServer;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.MediumTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@Category(MediumTests.class)
|
||||||
|
public class TestSpaceQuotaOnBulkLoad {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaOnBulkLoad.class);
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TestSpaceQuotaOnBulkLoad.class);
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoBulkLoadsWithNoWrites() throws Exception {
|
||||||
|
Put p = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
p.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
TableName tableName =
|
||||||
|
helper.writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, p);
|
||||||
|
|
||||||
|
// The table is now in violation. Try to do a bulk load
|
||||||
|
ClientServiceCallable<Void> callable = helper.generateFileToLoad(tableName, 1, 50);
|
||||||
|
RpcRetryingCallerFactory factory = new RpcRetryingCallerFactory(TEST_UTIL.getConfiguration());
|
||||||
|
RpcRetryingCaller<Void> caller = factory.<Void> newCaller();
|
||||||
|
try {
|
||||||
|
caller.callWithRetries(callable, Integer.MAX_VALUE);
|
||||||
|
fail("Expected the bulk load call to fail!");
|
||||||
|
} catch (SpaceLimitingException e) {
|
||||||
|
// Pass
|
||||||
|
LOG.trace("Caught expected exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAtomicBulkLoadUnderQuota() throws Exception {
|
||||||
|
// Need to verify that if the batch of hfiles cannot be loaded, none are loaded.
|
||||||
|
TableName tn = helper.createTableWithRegions(10);
|
||||||
|
|
||||||
|
final long sizeLimit = 50L * SpaceQuotaHelperForTests.ONE_KILOBYTE;
|
||||||
|
QuotaSettings settings =
|
||||||
|
QuotaSettingsFactory.limitTableSpace(tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
TEST_UTIL.getAdmin().setQuota(settings);
|
||||||
|
|
||||||
|
HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
|
||||||
|
RegionServerSpaceQuotaManager spaceQuotaManager = rs.getRegionServerSpaceQuotaManager();
|
||||||
|
Map<TableName, SpaceQuotaSnapshot> snapshots = spaceQuotaManager.copyQuotaSnapshots();
|
||||||
|
Map<RegionInfo, Long> regionSizes = getReportedSizesForTable(tn);
|
||||||
|
while (true) {
|
||||||
|
SpaceQuotaSnapshot snapshot = snapshots.get(tn);
|
||||||
|
if (snapshot != null && snapshot.getLimit() > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LOG.debug("Snapshot does not yet realize quota limit: " + snapshots + ", regionsizes: "
|
||||||
|
+ regionSizes);
|
||||||
|
Thread.sleep(3000);
|
||||||
|
snapshots = spaceQuotaManager.copyQuotaSnapshots();
|
||||||
|
regionSizes = getReportedSizesForTable(tn);
|
||||||
|
}
|
||||||
|
// Our quota limit should be reflected in the latest snapshot
|
||||||
|
SpaceQuotaSnapshot snapshot = snapshots.get(tn);
|
||||||
|
assertEquals(0L, snapshot.getUsage());
|
||||||
|
assertEquals(sizeLimit, snapshot.getLimit());
|
||||||
|
|
||||||
|
// We would also not have a "real" policy in violation
|
||||||
|
ActivePolicyEnforcement activePolicies = spaceQuotaManager.getActiveEnforcements();
|
||||||
|
SpaceViolationPolicyEnforcement enforcement = activePolicies.getPolicyEnforcement(tn);
|
||||||
|
assertTrue("Expected to find Noop policy, but got " + enforcement.getClass().getSimpleName(),
|
||||||
|
enforcement instanceof DefaultViolationPolicyEnforcement);
|
||||||
|
|
||||||
|
// Should generate two files, each of which is over 25KB each
|
||||||
|
ClientServiceCallable<Void> callable = helper.generateFileToLoad(tn, 2, 500);
|
||||||
|
FileSystem fs = TEST_UTIL.getTestFileSystem();
|
||||||
|
FileStatus[] files =
|
||||||
|
fs.listStatus(new Path(fs.getHomeDirectory(), testName.getMethodName() + "_files"));
|
||||||
|
for (FileStatus file : files) {
|
||||||
|
assertTrue(
|
||||||
|
"Expected the file, " + file.getPath() + ", length to be larger than 25KB, but was "
|
||||||
|
+ file.getLen(), file.getLen() > 25 * SpaceQuotaHelperForTests.ONE_KILOBYTE);
|
||||||
|
LOG.debug(file.getPath() + " -> " + file.getLen() + "B");
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcRetryingCallerFactory factory = new RpcRetryingCallerFactory(TEST_UTIL.getConfiguration());
|
||||||
|
RpcRetryingCaller<Void> caller = factory.<Void>newCaller();
|
||||||
|
try {
|
||||||
|
caller.callWithRetries(callable, Integer.MAX_VALUE);
|
||||||
|
fail("Expected the bulk load call to fail!");
|
||||||
|
} catch (SpaceLimitingException e) {
|
||||||
|
// Pass
|
||||||
|
LOG.trace("Caught expected exception", e);
|
||||||
|
}
|
||||||
|
// Verify that we have no data in the table because neither file should have been
|
||||||
|
// loaded even though one of the files could have.
|
||||||
|
Table table = TEST_UTIL.getConnection().getTable(tn);
|
||||||
|
ResultScanner scanner = table.getScanner(new Scan());
|
||||||
|
try {
|
||||||
|
assertNull("Expected no results", scanner.next());
|
||||||
|
} finally {
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<RegionInfo, Long> getReportedSizesForTable(TableName tn) {
|
||||||
|
HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
|
||||||
|
MasterQuotaManager quotaManager = master.getMasterQuotaManager();
|
||||||
|
Map<RegionInfo, Long> filteredRegionSizes = new HashMap<>();
|
||||||
|
for (Map.Entry<RegionInfo, Long> entry : quotaManager.snapshotRegionSizes().entrySet()) {
|
||||||
|
if (entry.getKey().getTable().equals(tn)) {
|
||||||
|
filteredRegionSizes.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredRegionSizes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.SmallTests;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
|
@Category(SmallTests.class)
|
||||||
|
public class TestSpaceQuotaOnNonExistingTables {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaOnNonExistingTables.class);
|
||||||
|
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
private final TableName NON_EXISTENT_TABLE = TableName.valueOf("NON_EXISTENT_TABLE");
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaOnNonExistingTableWithNoInserts() throws Exception {
|
||||||
|
helper.setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.NO_INSERTS, 2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaOnNonExistingTableWithNoWrites() throws Exception {
|
||||||
|
helper.setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.NO_WRITES, 2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaOnNonExistingTableWithNoWritesCompaction() throws Exception {
|
||||||
|
helper.setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.NO_WRITES_COMPACTIONS, 2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaOnNonExistingTableWithDisable() throws Exception {
|
||||||
|
helper.setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.DISABLE, 2L);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
|
@Category(LargeTests.class)
|
||||||
|
public class TestSpaceQuotaRemoval {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaRemoval.class);
|
||||||
|
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveInOneWithNoInserts() throws Exception {
|
||||||
|
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveInOneWithNoWrite() throws Exception {
|
||||||
|
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.NO_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveInOneWithNoWritesCompaction() throws Exception {
|
||||||
|
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveInOneWithDisable() throws Exception {
|
||||||
|
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveWithNoInserts() throws Exception {
|
||||||
|
setQuotaAndThenRemove(SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveWithNoWrite() throws Exception {
|
||||||
|
setQuotaAndThenRemove(SpaceViolationPolicy.NO_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveWithNoWritesCompactions() throws Exception {
|
||||||
|
setQuotaAndThenRemove(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenRemoveWithDisable() throws Exception {
|
||||||
|
setQuotaAndThenRemove(SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDisableIncrEnableWithNoInserts() throws Exception {
|
||||||
|
setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDisableIncrEnableWithNoWrite() throws Exception {
|
||||||
|
setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy.NO_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDisableIncrEnableWithNoWritesCompaction() throws Exception {
|
||||||
|
setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaAndThenDisableIncrEnableWithDisable() throws Exception {
|
||||||
|
setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuotaAndThenRemove(SpaceViolationPolicy policy) throws Exception {
|
||||||
|
Put put = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
|
||||||
|
// Do puts until we violate space policy
|
||||||
|
final TableName tn = helper.writeUntilViolationAndVerifyViolation(policy, put);
|
||||||
|
|
||||||
|
// Now, remove the quota
|
||||||
|
helper.removeQuotaFromtable(tn);
|
||||||
|
|
||||||
|
// Put some rows now: should not violate as quota settings removed
|
||||||
|
helper.verifyNoViolation(tn, put);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy policy)
|
||||||
|
throws Exception {
|
||||||
|
Put put = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
|
||||||
|
// Do puts until we violate space policy on table tn1
|
||||||
|
final TableName tn1 = helper.writeUntilViolationAndVerifyViolation(policy, put);
|
||||||
|
|
||||||
|
// Do puts until we violate space policy on table tn2
|
||||||
|
final TableName tn2 = helper.writeUntilViolationAndVerifyViolation(policy, put);
|
||||||
|
|
||||||
|
// Now, remove the quota from table tn1
|
||||||
|
helper.removeQuotaFromtable(tn1);
|
||||||
|
|
||||||
|
// Put a new row now on tn1: should not violate as quota settings removed
|
||||||
|
helper.verifyNoViolation(tn1, put);
|
||||||
|
// Put a new row now on tn2: should violate as quota settings exists
|
||||||
|
helper.verifyViolation(policy, tn2, put);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy policy)
|
||||||
|
throws Exception {
|
||||||
|
Put put = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
|
||||||
|
// Do puts until we violate space policy
|
||||||
|
final TableName tn = helper.writeUntilViolationAndVerifyViolation(policy, put);
|
||||||
|
|
||||||
|
// Disable the table; in case of SpaceViolationPolicy.DISABLE already disabled
|
||||||
|
if (!policy.equals(SpaceViolationPolicy.DISABLE)) {
|
||||||
|
TEST_UTIL.getAdmin().disableTable(tn);
|
||||||
|
TEST_UTIL.waitTableDisabled(tn, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, increase limit and perform put
|
||||||
|
helper.setQuotaLimit(tn, policy, 4L);
|
||||||
|
|
||||||
|
// in case of disable policy quota manager will enable it
|
||||||
|
if (!policy.equals(SpaceViolationPolicy.DISABLE)) {
|
||||||
|
TEST_UTIL.getAdmin().enableTable(tn);
|
||||||
|
}
|
||||||
|
TEST_UTIL.waitTableEnabled(tn, 10000);
|
||||||
|
|
||||||
|
// Put some row now: should not violate as quota limit increased
|
||||||
|
helper.verifyNoViolation(tn, put);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.quotas;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
||||||
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
|
@Category(LargeTests.class)
|
||||||
|
public class TestSpaceQuotaSwitchPolicies {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestSpaceQuotaSwitchPolicies.class);
|
||||||
|
|
||||||
|
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName testName = new TestName();
|
||||||
|
private SpaceQuotaHelperForTests helper;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
Configuration conf = TEST_UTIL.getConfiguration();
|
||||||
|
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
||||||
|
TEST_UTIL.startMiniCluster(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void removeAllQuotas() throws Exception {
|
||||||
|
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong(0));
|
||||||
|
helper.removeAllQuotas();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaFirstWithDisableNextNoWrites() throws Exception {
|
||||||
|
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
||||||
|
SpaceViolationPolicy.NO_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaFirstWithDisableNextAgainDisable() throws Exception {
|
||||||
|
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
||||||
|
SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaFirstWithDisableNextNoInserts() throws Exception {
|
||||||
|
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
||||||
|
SpaceViolationPolicy.NO_INSERTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaFirstWithDisableNextNoWritesCompaction() throws Exception {
|
||||||
|
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
||||||
|
SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetQuotaFirstWithNoWritesNextWithDisable() throws Exception {
|
||||||
|
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.NO_WRITES,
|
||||||
|
SpaceViolationPolicy.DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy policy1,
|
||||||
|
SpaceViolationPolicy policy2) throws Exception {
|
||||||
|
Put put = new Put(Bytes.toBytes("to_reject"));
|
||||||
|
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
||||||
|
Bytes.toBytes("reject"));
|
||||||
|
|
||||||
|
// Do puts until we violate space violation policy1
|
||||||
|
final TableName tn = helper.writeUntilViolationAndVerifyViolation(policy1, put);
|
||||||
|
|
||||||
|
// Now, change violation policy to policy2
|
||||||
|
helper.setQuotaLimit(tn, policy2, 2L);
|
||||||
|
|
||||||
|
// The table should be in enabled state on changing violation policy
|
||||||
|
if (policy1.equals(SpaceViolationPolicy.DISABLE) && !policy1.equals(policy2)) {
|
||||||
|
TEST_UTIL.waitTableEnabled(tn, 20000);
|
||||||
|
}
|
||||||
|
// Put some row now: should still violate as quota limit still violated
|
||||||
|
helper.verifyViolation(policy2, tn, put);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,790 +0,0 @@
|
||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.hadoop.hbase.quotas;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
|
||||||
import org.apache.hadoop.fs.FileStatus;
|
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
|
||||||
import org.apache.hadoop.fs.Path;
|
|
||||||
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
|
||||||
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
|
||||||
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
|
||||||
import org.apache.hadoop.hbase.TableName;
|
|
||||||
import org.apache.hadoop.hbase.TableNotEnabledException;
|
|
||||||
import org.apache.hadoop.hbase.client.Admin;
|
|
||||||
import org.apache.hadoop.hbase.client.Append;
|
|
||||||
import org.apache.hadoop.hbase.client.ClientServiceCallable;
|
|
||||||
import org.apache.hadoop.hbase.client.Connection;
|
|
||||||
import org.apache.hadoop.hbase.client.Delete;
|
|
||||||
import org.apache.hadoop.hbase.client.Increment;
|
|
||||||
import org.apache.hadoop.hbase.client.Mutation;
|
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
|
||||||
import org.apache.hadoop.hbase.client.RegionInfo;
|
|
||||||
import org.apache.hadoop.hbase.client.Result;
|
|
||||||
import org.apache.hadoop.hbase.client.ResultScanner;
|
|
||||||
import org.apache.hadoop.hbase.client.RpcRetryingCaller;
|
|
||||||
import org.apache.hadoop.hbase.client.RpcRetryingCallerFactory;
|
|
||||||
import org.apache.hadoop.hbase.client.Scan;
|
|
||||||
import org.apache.hadoop.hbase.client.SecureBulkLoadClient;
|
|
||||||
import org.apache.hadoop.hbase.client.Table;
|
|
||||||
import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
|
|
||||||
import org.apache.hadoop.hbase.master.HMaster;
|
|
||||||
import org.apache.hadoop.hbase.quotas.policies.DefaultViolationPolicyEnforcement;
|
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegionServer;
|
|
||||||
import org.apache.hadoop.hbase.regionserver.TestHRegionServerBulkLoad;
|
|
||||||
import org.apache.hadoop.hbase.security.AccessDeniedException;
|
|
||||||
import org.apache.hadoop.hbase.testclassification.LargeTests;
|
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
|
||||||
import org.apache.hadoop.hbase.util.Pair;
|
|
||||||
import org.apache.hadoop.util.StringUtils;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.experimental.categories.Category;
|
|
||||||
import org.junit.rules.TestName;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End-to-end test class for filesystem space quotas.
|
|
||||||
*/
|
|
||||||
@Category(LargeTests.class)
|
|
||||||
public class TestSpaceQuotas {
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static final HBaseClassTestRule CLASS_RULE =
|
|
||||||
HBaseClassTestRule.forClass(TestSpaceQuotas.class);
|
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TestSpaceQuotas.class);
|
|
||||||
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
|
|
||||||
// Global for all tests in the class
|
|
||||||
private static final AtomicLong COUNTER = new AtomicLong(0);
|
|
||||||
private static final int NUM_RETRIES = 10;
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public TestName testName = new TestName();
|
|
||||||
private SpaceQuotaHelperForTests helper;
|
|
||||||
private final TableName NON_EXISTENT_TABLE = TableName.valueOf("NON_EXISTENT_TABLE");
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void setUp() throws Exception {
|
|
||||||
Configuration conf = TEST_UTIL.getConfiguration();
|
|
||||||
SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
|
|
||||||
TEST_UTIL.startMiniCluster(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void tearDown() throws Exception {
|
|
||||||
TEST_UTIL.shutdownMiniCluster();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void removeAllQuotas() throws Exception {
|
|
||||||
final Connection conn = TEST_UTIL.getConnection();
|
|
||||||
if (helper == null) {
|
|
||||||
helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, COUNTER);
|
|
||||||
}
|
|
||||||
// Wait for the quota table to be created
|
|
||||||
if (!conn.getAdmin().tableExists(QuotaUtil.QUOTA_TABLE_NAME)) {
|
|
||||||
helper.waitForQuotaTable(conn);
|
|
||||||
} else {
|
|
||||||
// Or, clean up any quotas from previous test runs.
|
|
||||||
helper.removeAllQuotas(conn);
|
|
||||||
assertEquals(0, helper.listNumDefinedQuotas(conn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoInsertsWithPut() throws Exception {
|
|
||||||
Put p = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
p.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_INSERTS, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoInsertsWithAppend() throws Exception {
|
|
||||||
Append a = new Append(Bytes.toBytes("to_reject"));
|
|
||||||
a.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_INSERTS, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoInsertsWithIncrement() throws Exception {
|
|
||||||
Increment i = new Increment(Bytes.toBytes("to_reject"));
|
|
||||||
i.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("count"), 0);
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_INSERTS, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDeletesAfterNoInserts() throws Exception {
|
|
||||||
final TableName tn = writeUntilViolation(SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
// Try a couple of times to verify that the quota never gets enforced, same as we
|
|
||||||
// do when we're trying to catch the failure.
|
|
||||||
Delete d = new Delete(Bytes.toBytes("should_not_be_rejected"));
|
|
||||||
for (int i = 0; i < NUM_RETRIES; i++) {
|
|
||||||
try (Table t = TEST_UTIL.getConnection().getTable(tn)) {
|
|
||||||
t.delete(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoWritesWithPut() throws Exception {
|
|
||||||
Put p = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
p.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoWritesWithAppend() throws Exception {
|
|
||||||
Append a = new Append(Bytes.toBytes("to_reject"));
|
|
||||||
a.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoWritesWithIncrement() throws Exception {
|
|
||||||
Increment i = new Increment(Bytes.toBytes("to_reject"));
|
|
||||||
i.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("count"), 0);
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoWritesWithDelete() throws Exception {
|
|
||||||
Delete d = new Delete(Bytes.toBytes("to_reject"));
|
|
||||||
writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoCompactions() throws Exception {
|
|
||||||
Put p = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
p.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
final TableName tn = writeUntilViolationAndVerifyViolation(
|
|
||||||
SpaceViolationPolicy.NO_WRITES_COMPACTIONS, p);
|
|
||||||
// We know the policy is active at this point
|
|
||||||
|
|
||||||
// Major compactions should be rejected
|
|
||||||
try {
|
|
||||||
TEST_UTIL.getAdmin().majorCompact(tn);
|
|
||||||
fail("Expected that invoking the compaction should throw an Exception");
|
|
||||||
} catch (DoNotRetryIOException e) {
|
|
||||||
// Expected!
|
|
||||||
}
|
|
||||||
// Minor compactions should also be rejected.
|
|
||||||
try {
|
|
||||||
TEST_UTIL.getAdmin().compact(tn);
|
|
||||||
fail("Expected that invoking the compaction should throw an Exception");
|
|
||||||
} catch (DoNotRetryIOException e) {
|
|
||||||
// Expected!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoEnableAfterDisablePolicy() throws Exception {
|
|
||||||
Put p = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
p.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
final TableName tn = writeUntilViolation(SpaceViolationPolicy.DISABLE);
|
|
||||||
final Admin admin = TEST_UTIL.getAdmin();
|
|
||||||
// Disabling a table relies on some external action (over the other policies), so wait a bit
|
|
||||||
// more than the other tests.
|
|
||||||
for (int i = 0; i < NUM_RETRIES * 2; i++) {
|
|
||||||
if (admin.isTableEnabled(tn)) {
|
|
||||||
LOG.info(tn + " is still enabled, expecting it to be disabled. Will wait and re-check.");
|
|
||||||
Thread.sleep(2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertFalse(tn + " is still enabled but it should be disabled", admin.isTableEnabled(tn));
|
|
||||||
try {
|
|
||||||
admin.enableTable(tn);
|
|
||||||
} catch (AccessDeniedException e) {
|
|
||||||
String exceptionContents = StringUtils.stringifyException(e);
|
|
||||||
final String expectedText = "violated space quota";
|
|
||||||
assertTrue("Expected the exception to contain " + expectedText + ", but was: "
|
|
||||||
+ exceptionContents, exceptionContents.contains(expectedText));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoBulkLoadsWithNoWrites() throws Exception {
|
|
||||||
Put p = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
p.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
TableName tableName = writeUntilViolationAndVerifyViolation(SpaceViolationPolicy.NO_WRITES, p);
|
|
||||||
|
|
||||||
// The table is now in violation. Try to do a bulk load
|
|
||||||
ClientServiceCallable<Void> callable = generateFileToLoad(tableName, 1, 50);
|
|
||||||
RpcRetryingCallerFactory factory = new RpcRetryingCallerFactory(TEST_UTIL.getConfiguration());
|
|
||||||
RpcRetryingCaller<Void> caller = factory.<Void> newCaller();
|
|
||||||
try {
|
|
||||||
caller.callWithRetries(callable, Integer.MAX_VALUE);
|
|
||||||
fail("Expected the bulk load call to fail!");
|
|
||||||
} catch (SpaceLimitingException e) {
|
|
||||||
// Pass
|
|
||||||
LOG.trace("Caught expected exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAtomicBulkLoadUnderQuota() throws Exception {
|
|
||||||
// Need to verify that if the batch of hfiles cannot be loaded, none are loaded.
|
|
||||||
TableName tn = helper.createTableWithRegions(10);
|
|
||||||
|
|
||||||
final long sizeLimit = 50L * SpaceQuotaHelperForTests.ONE_KILOBYTE;
|
|
||||||
QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(
|
|
||||||
tn, sizeLimit, SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
TEST_UTIL.getAdmin().setQuota(settings);
|
|
||||||
|
|
||||||
HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
|
|
||||||
RegionServerSpaceQuotaManager spaceQuotaManager = rs.getRegionServerSpaceQuotaManager();
|
|
||||||
Map<TableName,SpaceQuotaSnapshot> snapshots = spaceQuotaManager.copyQuotaSnapshots();
|
|
||||||
Map<RegionInfo,Long> regionSizes = getReportedSizesForTable(tn);
|
|
||||||
while (true) {
|
|
||||||
SpaceQuotaSnapshot snapshot = snapshots.get(tn);
|
|
||||||
if (snapshot != null && snapshot.getLimit() > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
LOG.debug(
|
|
||||||
"Snapshot does not yet realize quota limit: " + snapshots + ", regionsizes: " +
|
|
||||||
regionSizes);
|
|
||||||
Thread.sleep(3000);
|
|
||||||
snapshots = spaceQuotaManager.copyQuotaSnapshots();
|
|
||||||
regionSizes = getReportedSizesForTable(tn);
|
|
||||||
}
|
|
||||||
// Our quota limit should be reflected in the latest snapshot
|
|
||||||
SpaceQuotaSnapshot snapshot = snapshots.get(tn);
|
|
||||||
assertEquals(0L, snapshot.getUsage());
|
|
||||||
assertEquals(sizeLimit, snapshot.getLimit());
|
|
||||||
|
|
||||||
// We would also not have a "real" policy in violation
|
|
||||||
ActivePolicyEnforcement activePolicies = spaceQuotaManager.getActiveEnforcements();
|
|
||||||
SpaceViolationPolicyEnforcement enforcement = activePolicies.getPolicyEnforcement(tn);
|
|
||||||
assertTrue(
|
|
||||||
"Expected to find Noop policy, but got " + enforcement.getClass().getSimpleName(),
|
|
||||||
enforcement instanceof DefaultViolationPolicyEnforcement);
|
|
||||||
|
|
||||||
// Should generate two files, each of which is over 25KB each
|
|
||||||
ClientServiceCallable<Void> callable = generateFileToLoad(tn, 2, 500);
|
|
||||||
FileSystem fs = TEST_UTIL.getTestFileSystem();
|
|
||||||
FileStatus[] files = fs.listStatus(
|
|
||||||
new Path(fs.getHomeDirectory(), testName.getMethodName() + "_files"));
|
|
||||||
for (FileStatus file : files) {
|
|
||||||
assertTrue(
|
|
||||||
"Expected the file, " + file.getPath() + ", length to be larger than 25KB, but was "
|
|
||||||
+ file.getLen(),
|
|
||||||
file.getLen() > 25 * SpaceQuotaHelperForTests.ONE_KILOBYTE);
|
|
||||||
LOG.debug(file.getPath() + " -> " + file.getLen() +"B");
|
|
||||||
}
|
|
||||||
|
|
||||||
RpcRetryingCallerFactory factory = new RpcRetryingCallerFactory(TEST_UTIL.getConfiguration());
|
|
||||||
RpcRetryingCaller<Void> caller = factory.<Void> newCaller();
|
|
||||||
try {
|
|
||||||
caller.callWithRetries(callable, Integer.MAX_VALUE);
|
|
||||||
fail("Expected the bulk load call to fail!");
|
|
||||||
} catch (SpaceLimitingException e) {
|
|
||||||
// Pass
|
|
||||||
LOG.trace("Caught expected exception", e);
|
|
||||||
}
|
|
||||||
// Verify that we have no data in the table because neither file should have been
|
|
||||||
// loaded even though one of the files could have.
|
|
||||||
Table table = TEST_UTIL.getConnection().getTable(tn);
|
|
||||||
ResultScanner scanner = table.getScanner(new Scan());
|
|
||||||
try {
|
|
||||||
assertNull("Expected no results", scanner.next());
|
|
||||||
} finally{
|
|
||||||
scanner.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTableQuotaOverridesNamespaceQuota() throws Exception {
|
|
||||||
final SpaceViolationPolicy policy = SpaceViolationPolicy.NO_INSERTS;
|
|
||||||
final TableName tn = helper.createTableWithRegions(10);
|
|
||||||
|
|
||||||
// 2MB limit on the table, 1GB limit on the namespace
|
|
||||||
final long tableLimit = 2L * SpaceQuotaHelperForTests.ONE_MEGABYTE;
|
|
||||||
final long namespaceLimit = 1024L * SpaceQuotaHelperForTests.ONE_MEGABYTE;
|
|
||||||
TEST_UTIL.getAdmin().setQuota(QuotaSettingsFactory.limitTableSpace(tn, tableLimit, policy));
|
|
||||||
TEST_UTIL.getAdmin().setQuota(QuotaSettingsFactory.limitNamespaceSpace(
|
|
||||||
tn.getNamespaceAsString(), namespaceLimit, policy));
|
|
||||||
|
|
||||||
// Write more data than should be allowed and flush it to disk
|
|
||||||
helper.writeData(tn, 3L * SpaceQuotaHelperForTests.ONE_MEGABYTE);
|
|
||||||
|
|
||||||
// This should be sufficient time for the chores to run and see the change.
|
|
||||||
Thread.sleep(5000);
|
|
||||||
|
|
||||||
// The write should be rejected because the table quota takes priority over the namespace
|
|
||||||
Put p = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
p.addColumn(
|
|
||||||
Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"), Bytes.toBytes("reject"));
|
|
||||||
verifyViolation(policy, tn, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveWithNoInserts() throws Exception {
|
|
||||||
setQuotaAndThenRemove(SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveWithNoWrite() throws Exception {
|
|
||||||
setQuotaAndThenRemove(SpaceViolationPolicy.NO_WRITES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveWithNoWritesCompactions() throws Exception {
|
|
||||||
setQuotaAndThenRemove(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveWithDisable() throws Exception {
|
|
||||||
setQuotaAndThenRemove(SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenDropTableWithNoInserts() throws Exception {
|
|
||||||
setQuotaAndThenDropTable(SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenDropTableWithNoWrite() throws Exception {
|
|
||||||
setQuotaAndThenDropTable(SpaceViolationPolicy.NO_WRITES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenDropTableWithNoWritesCompactions() throws Exception {
|
|
||||||
setQuotaAndThenDropTable(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenDropTableWithDisable() throws Exception {
|
|
||||||
setQuotaAndThenDropTable(SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenIncreaseQuotaWithNoInserts() throws Exception {
|
|
||||||
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenIncreaseQuotaWithNoWrite() throws Exception {
|
|
||||||
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.NO_WRITES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenIncreaseQuotaWithNoWritesCompactions() throws Exception {
|
|
||||||
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenIncreaseQuotaWithDisable() throws Exception {
|
|
||||||
setQuotaAndThenIncreaseQuota(SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenDisableIncrEnableWithDisable() throws Exception {
|
|
||||||
setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveInOneWithNoInserts() throws Exception {
|
|
||||||
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveInOneWithNoWrite() throws Exception {
|
|
||||||
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.NO_WRITES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveInOneWithNoWritesCompaction() throws Exception {
|
|
||||||
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaAndThenRemoveInOneWithDisable() throws Exception {
|
|
||||||
setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaFirstWithDisableNextNoWrites() throws Exception {
|
|
||||||
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
|
||||||
SpaceViolationPolicy.NO_WRITES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaFirstWithDisableNextAgainDisable() throws Exception {
|
|
||||||
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
|
||||||
SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaFirstWithDisableNextNoInserts() throws Exception {
|
|
||||||
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
|
||||||
SpaceViolationPolicy.NO_INSERTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaFirstWithDisableNextNoWritesCompaction() throws Exception {
|
|
||||||
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.DISABLE,
|
|
||||||
SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaFirstWithNoWritesNextWithDisable() throws Exception {
|
|
||||||
setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy.NO_WRITES,
|
|
||||||
SpaceViolationPolicy.DISABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaOnNonExistingTableWithNoInserts() throws Exception {
|
|
||||||
setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.NO_INSERTS, 2L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaOnNonExistingTableWithNoWrites() throws Exception {
|
|
||||||
setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.NO_WRITES, 2L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaOnNonExistingTableWithNoWritesCompaction() throws Exception {
|
|
||||||
setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.NO_WRITES_COMPACTIONS, 2L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetQuotaOnNonExistingTableWithDisable() throws Exception {
|
|
||||||
setQuotaLimit(NON_EXISTENT_TABLE, SpaceViolationPolicy.DISABLE, 2L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQuotaAndViolateNextSwitchPoliciesAndValidate(SpaceViolationPolicy policy1,
|
|
||||||
SpaceViolationPolicy policy2) throws Exception {
|
|
||||||
Put put = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"));
|
|
||||||
|
|
||||||
// Do puts until we violate space violation policy1
|
|
||||||
final TableName tn = writeUntilViolationAndVerifyViolation(policy1, put);
|
|
||||||
|
|
||||||
// Now, change violation policy to policy2
|
|
||||||
setQuotaLimit(tn, policy2, 2L);
|
|
||||||
|
|
||||||
// The table should be in enabled state on changing violation policy
|
|
||||||
if (policy1.equals(SpaceViolationPolicy.DISABLE) && !policy1.equals(policy2)) {
|
|
||||||
TEST_UTIL.waitTableEnabled(tn, 20000);
|
|
||||||
}
|
|
||||||
// Put some row now: should still violate as quota limit still violated
|
|
||||||
verifyViolation(policy2, tn, put);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setQuotaAndThenRemove(SpaceViolationPolicy policy) throws Exception {
|
|
||||||
Put put = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"));
|
|
||||||
|
|
||||||
// Do puts until we violate space policy
|
|
||||||
final TableName tn = writeUntilViolationAndVerifyViolation(policy, put);
|
|
||||||
|
|
||||||
// Now, remove the quota
|
|
||||||
removeQuotaFromtable(tn);
|
|
||||||
|
|
||||||
// Put some rows now: should not violate as quota settings removed
|
|
||||||
verifyNoViolation(policy, tn, put);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setQuotaAndThenDropTable(SpaceViolationPolicy policy) throws Exception {
|
|
||||||
Put put = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"));
|
|
||||||
|
|
||||||
// Do puts until we violate space policy
|
|
||||||
final TableName tn = writeUntilViolationAndVerifyViolation(policy, put);
|
|
||||||
|
|
||||||
// Now, drop the table
|
|
||||||
TEST_UTIL.deleteTable(tn);
|
|
||||||
LOG.debug("Successfully deleted table ", tn);
|
|
||||||
|
|
||||||
// Now re-create the table
|
|
||||||
TEST_UTIL.createTable(tn, Bytes.toBytes(SpaceQuotaHelperForTests.F1));
|
|
||||||
LOG.debug("Successfully re-created table ", tn);
|
|
||||||
|
|
||||||
// Put some rows now: should not violate as table/quota was dropped
|
|
||||||
verifyNoViolation(policy, tn, put);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setQuotaAndThenIncreaseQuota(SpaceViolationPolicy policy) throws Exception {
|
|
||||||
Put put = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"));
|
|
||||||
|
|
||||||
// Do puts until we violate space policy
|
|
||||||
final TableName tn = writeUntilViolationAndVerifyViolation(policy, put);
|
|
||||||
|
|
||||||
// Now, increase limit and perform put
|
|
||||||
setQuotaLimit(tn, policy, 4L);
|
|
||||||
|
|
||||||
// Put some row now: should not violate as quota limit increased
|
|
||||||
verifyNoViolation(policy, tn, put);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setQuotaNextDisableThenIncreaseFinallyEnable(SpaceViolationPolicy policy)
|
|
||||||
throws Exception {
|
|
||||||
Put put = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"));
|
|
||||||
|
|
||||||
// Do puts until we violate space policy
|
|
||||||
final TableName tn = writeUntilViolationAndVerifyViolation(policy, put);
|
|
||||||
|
|
||||||
// Disable the table; in case of SpaceViolationPolicy.DISABLE already disabled
|
|
||||||
if (!policy.equals(SpaceViolationPolicy.DISABLE)) {
|
|
||||||
TEST_UTIL.getAdmin().disableTable(tn);
|
|
||||||
TEST_UTIL.waitTableDisabled(tn, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, increase limit and perform put
|
|
||||||
setQuotaLimit(tn, policy, 4L);
|
|
||||||
|
|
||||||
// in case of disable policy quota manager will enable it
|
|
||||||
if (!policy.equals(SpaceViolationPolicy.DISABLE)) {
|
|
||||||
TEST_UTIL.getAdmin().enableTable(tn);
|
|
||||||
}
|
|
||||||
TEST_UTIL.waitTableEnabled(tn, 10000);
|
|
||||||
|
|
||||||
// Put some row now: should not violate as quota limit increased
|
|
||||||
verifyNoViolation(policy, tn, put);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQuotaAndThenRemoveInOneAmongTwoTables(SpaceViolationPolicy policy)
|
|
||||||
throws Exception {
|
|
||||||
Put put = new Put(Bytes.toBytes("to_reject"));
|
|
||||||
put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"));
|
|
||||||
|
|
||||||
// Do puts until we violate space policy on table tn1
|
|
||||||
final TableName tn1 = writeUntilViolationAndVerifyViolation(policy, put);
|
|
||||||
|
|
||||||
// Do puts until we violate space policy on table tn2
|
|
||||||
final TableName tn2 = writeUntilViolationAndVerifyViolation(policy, put);
|
|
||||||
|
|
||||||
// Now, remove the quota from table tn1
|
|
||||||
removeQuotaFromtable(tn1);
|
|
||||||
|
|
||||||
// Put a new row now on tn1: should not violate as quota settings removed
|
|
||||||
verifyNoViolation(policy, tn1, put);
|
|
||||||
// Put a new row now on tn2: should violate as quota settings exists
|
|
||||||
verifyViolation(policy, tn2, put);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeQuotaFromtable(final TableName tn) throws Exception {
|
|
||||||
QuotaSettings removeQuota = QuotaSettingsFactory.removeTableSpaceLimit(tn);
|
|
||||||
TEST_UTIL.getAdmin().setQuota(removeQuota);
|
|
||||||
LOG.debug("Space quota settings removed from the table ", tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setQuotaLimit(final TableName tn, SpaceViolationPolicy policy, long sizeInMBs)
|
|
||||||
throws Exception {
|
|
||||||
final long sizeLimit = sizeInMBs * SpaceQuotaHelperForTests.ONE_MEGABYTE;
|
|
||||||
QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(tn, sizeLimit, policy);
|
|
||||||
TEST_UTIL.getAdmin().setQuota(settings);
|
|
||||||
LOG.debug("Quota limit set for table = {}, limit = {}", tn, sizeLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<RegionInfo,Long> getReportedSizesForTable(TableName tn) {
|
|
||||||
HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
|
|
||||||
MasterQuotaManager quotaManager = master.getMasterQuotaManager();
|
|
||||||
Map<RegionInfo,Long> filteredRegionSizes = new HashMap<>();
|
|
||||||
for (Entry<RegionInfo,Long> entry : quotaManager.snapshotRegionSizes().entrySet()) {
|
|
||||||
if (entry.getKey().getTable().equals(tn)) {
|
|
||||||
filteredRegionSizes.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filteredRegionSizes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TableName writeUntilViolation(SpaceViolationPolicy policyToViolate) throws Exception {
|
|
||||||
TableName tn = helper.createTableWithRegions(10);
|
|
||||||
setQuotaLimit(tn, policyToViolate, 2L);
|
|
||||||
// Write more data than should be allowed and flush it to disk
|
|
||||||
helper.writeData(tn, 3L * SpaceQuotaHelperForTests.ONE_MEGABYTE);
|
|
||||||
|
|
||||||
// This should be sufficient time for the chores to run and see the change.
|
|
||||||
Thread.sleep(5000);
|
|
||||||
|
|
||||||
return tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TableName writeUntilViolationAndVerifyViolation(
|
|
||||||
SpaceViolationPolicy policyToViolate, Mutation m) throws Exception {
|
|
||||||
final TableName tn = writeUntilViolation(policyToViolate);
|
|
||||||
verifyViolation(policyToViolate, tn, m);
|
|
||||||
return tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyViolation(
|
|
||||||
SpaceViolationPolicy policyToViolate, TableName tn, Mutation m) throws Exception {
|
|
||||||
// But let's try a few times to get the exception before failing
|
|
||||||
boolean sawError = false;
|
|
||||||
String msg = "";
|
|
||||||
for (int i = 0; i < NUM_RETRIES && !sawError; i++) {
|
|
||||||
try (Table table = TEST_UTIL.getConnection().getTable(tn)) {
|
|
||||||
if (m instanceof Put) {
|
|
||||||
table.put((Put) m);
|
|
||||||
} else if (m instanceof Delete) {
|
|
||||||
table.delete((Delete) m);
|
|
||||||
} else if (m instanceof Append) {
|
|
||||||
table.append((Append) m);
|
|
||||||
} else if (m instanceof Increment) {
|
|
||||||
table.increment((Increment) m);
|
|
||||||
} else {
|
|
||||||
fail(
|
|
||||||
"Failed to apply " + m.getClass().getSimpleName() +
|
|
||||||
" to the table. Programming error");
|
|
||||||
}
|
|
||||||
LOG.info("Did not reject the " + m.getClass().getSimpleName() + ", will sleep and retry");
|
|
||||||
Thread.sleep(2000);
|
|
||||||
} catch (Exception e) {
|
|
||||||
msg = StringUtils.stringifyException(e);
|
|
||||||
if ((policyToViolate.equals(SpaceViolationPolicy.DISABLE)
|
|
||||||
&& e instanceof TableNotEnabledException) || msg.contains(policyToViolate.name())) {
|
|
||||||
LOG.info("Got the expected exception={}", msg);
|
|
||||||
sawError = true;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
LOG.warn("Did not get the expected exception, will sleep and retry", e);
|
|
||||||
Thread.sleep(2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sawError) {
|
|
||||||
try (Table quotaTable = TEST_UTIL.getConnection().getTable(QuotaUtil.QUOTA_TABLE_NAME)) {
|
|
||||||
ResultScanner scanner = quotaTable.getScanner(new Scan());
|
|
||||||
Result result = null;
|
|
||||||
LOG.info("Dumping contents of hbase:quota table");
|
|
||||||
while ((result = scanner.next()) != null) {
|
|
||||||
LOG.info(Bytes.toString(result.getRow()) + " => " + result.toString());
|
|
||||||
}
|
|
||||||
scanner.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (policyToViolate.equals(SpaceViolationPolicy.DISABLE)) {
|
|
||||||
assertTrue(
|
|
||||||
msg.contains("TableNotEnabledException") || msg.contains(policyToViolate.name()));
|
|
||||||
} else {
|
|
||||||
assertTrue("Expected exception message to contain the word '" + policyToViolate.name()
|
|
||||||
+ "', but was " + msg,
|
|
||||||
msg.contains(policyToViolate.name()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertTrue(
|
|
||||||
"Expected to see an exception writing data to a table exceeding its quota", sawError);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClientServiceCallable<Void> generateFileToLoad(
|
|
||||||
TableName tn, int numFiles, int numRowsPerFile) throws Exception {
|
|
||||||
Connection conn = TEST_UTIL.getConnection();
|
|
||||||
FileSystem fs = TEST_UTIL.getTestFileSystem();
|
|
||||||
Configuration conf = TEST_UTIL.getConfiguration();
|
|
||||||
Path baseDir = new Path(fs.getHomeDirectory(), testName.getMethodName() + "_files");
|
|
||||||
fs.mkdirs(baseDir);
|
|
||||||
final List<Pair<byte[], String>> famPaths = new ArrayList<Pair<byte[], String>>();
|
|
||||||
for (int i = 1; i <= numFiles; i++) {
|
|
||||||
Path hfile = new Path(baseDir, "file" + i);
|
|
||||||
TestHRegionServerBulkLoad.createHFile(
|
|
||||||
fs, hfile, Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
|
|
||||||
Bytes.toBytes("reject"), numRowsPerFile);
|
|
||||||
famPaths.add(new Pair<>(Bytes.toBytes(SpaceQuotaHelperForTests.F1), hfile.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// bulk load HFiles
|
|
||||||
Table table = conn.getTable(tn);
|
|
||||||
final String bulkToken = new SecureBulkLoadClient(conf, table).prepareBulkLoad(conn);
|
|
||||||
return new ClientServiceCallable<Void>(conn,
|
|
||||||
tn, Bytes.toBytes("row"), new RpcControllerFactory(conf).newController(), HConstants.PRIORITY_UNSET) {
|
|
||||||
@Override
|
|
||||||
public Void rpcCall() throws Exception {
|
|
||||||
SecureBulkLoadClient secureClient = null;
|
|
||||||
byte[] regionName = getLocation().getRegionInfo().getRegionName();
|
|
||||||
try (Table table = conn.getTable(getTableName())) {
|
|
||||||
secureClient = new SecureBulkLoadClient(conf, table);
|
|
||||||
secureClient.secureBulkLoadHFiles(getStub(), famPaths, regionName,
|
|
||||||
true, null, bulkToken);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyNoViolation(SpaceViolationPolicy policyToViolate, TableName tn, Mutation m)
|
|
||||||
throws Exception {
|
|
||||||
// But let's try a few times to write data before failing
|
|
||||||
boolean sawSuccess = false;
|
|
||||||
for (int i = 0; i < NUM_RETRIES && !sawSuccess; i++) {
|
|
||||||
try (Table table = TEST_UTIL.getConnection().getTable(tn)) {
|
|
||||||
if (m instanceof Put) {
|
|
||||||
table.put((Put) m);
|
|
||||||
} else if (m instanceof Delete) {
|
|
||||||
table.delete((Delete) m);
|
|
||||||
} else if (m instanceof Append) {
|
|
||||||
table.append((Append) m);
|
|
||||||
} else if (m instanceof Increment) {
|
|
||||||
table.increment((Increment) m);
|
|
||||||
} else {
|
|
||||||
fail(
|
|
||||||
"Failed to apply " + m.getClass().getSimpleName() + " to the table. Programming error");
|
|
||||||
}
|
|
||||||
sawSuccess = true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.info("Rejected the " + m.getClass().getSimpleName() + ", will sleep and retry");
|
|
||||||
Thread.sleep(2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sawSuccess) {
|
|
||||||
try (Table quotaTable = TEST_UTIL.getConnection().getTable(QuotaUtil.QUOTA_TABLE_NAME)) {
|
|
||||||
ResultScanner scanner = quotaTable.getScanner(new Scan());
|
|
||||||
Result result = null;
|
|
||||||
LOG.info("Dumping contents of hbase:quota table");
|
|
||||||
while ((result = scanner.next()) != null) {
|
|
||||||
LOG.info(Bytes.toString(result.getRow()) + " => " + result.toString());
|
|
||||||
}
|
|
||||||
scanner.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertTrue("Expected to succeed in writing data to a table not having quota ", sawSuccess);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue