Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

Expand Down Expand Up @@ -702,15 +703,53 @@ int pruneEntriesOlderThan(long timeToPruneBefore) {
Iterator<Entry<RegionInfo,SizeSnapshotWithTimestamp>> iterator =
regionSizes.entrySet().iterator();
while (iterator.hasNext()) {
long currentEntryTime = iterator.next().getValue().getTime();
if (currentEntryTime < timeToPruneBefore) {
RegionInfo regionInfo = iterator.next().getKey();
long currentEntryTime = regionSizes.get(regionInfo).getTime();
boolean isInViolationAndPolicyDisable = isInViolationAndPolicyDisable(regionInfo.getTable());
// do not prune the entries if table is in violation and
// violation policy is disable.prune entries older than time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you buff out this comment with an explanation as to why we need to hold onto RegionSizes for tables in violation with a disable policy or include a reference to HBASE-22012, please?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (currentEntryTime < timeToPruneBefore && !isInViolationAndPolicyDisable) {
iterator.remove();
numEntriesRemoved++;
}
}
return numEntriesRemoved;
}

/**
* Method to check if a table is in violation and policy set on table is DISABLE.
*
* @param tableName tableName to check.
* @return returns true if table is in violation and policy is disable else false.
*/
private boolean isInViolationAndPolicyDisable(TableName tableName) {
boolean isInViolationAtTable = false;
boolean isInViolationAndPolicyDisable = false;
SpaceViolationPolicy policy = null;
try {
if (QuotaUtil.isQuotaEnabled(masterServices.getConfiguration())) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is unnecessary to re-check.

QuotaObserverChore would be calling pruneEntriesOlderThan(long) but that chore is only scheduled if quotas are enabled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

// Get Current Snapshot for the given table
SpaceQuotaSnapshot spaceQuotaSnapshot =
QuotaUtil.getCurrentSnapshotFromQuotaTable(masterServices.getConnection(), tableName);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use QuotaObserverChore#getTableQuotaSnapshot(TableName) instead? This is going to hit hbase:quota every time which might be costly.

Since we're inside the master already, we should be able to safely pull from the in-memory state in QuotaObserverChore instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using QuotaObserverChore#getTableQuotaSnapshot(TableName) now.

if (spaceQuotaSnapshot != null) {
// check if table in violation
isInViolationAtTable = spaceQuotaSnapshot.getQuotaStatus().isInViolation();
Optional<SpaceViolationPolicy> policyAtNamespace =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: just policy? AtNamespace doesn't seem to be appropriate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

spaceQuotaSnapshot.getQuotaStatus().getPolicy();
if (policyAtNamespace.isPresent()) {
policy = policyAtNamespace.get();
}
}
}
isInViolationAndPolicyDisable =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can just make this return policy == SpaceViolationPolicy.DISABLE && isInViolationAtTable;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you do this, then you can also remove the variable isInViolationAndPolicyDisable completely, lift the return isInViolationAndPolicyDisable into the catch block and make it return false instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

(policy == SpaceViolationPolicy.DISABLE) && isInViolationAtTable;

} catch (IOException e) {
LOG.info("Problem in getting connection to quota table: ", e);
}
return isInViolationAndPolicyDisable;
}

public void processFileArchivals(FileArchiveNotificationRequest request, Connection conn,
Configuration conf, FileSystem fs) throws IOException {
final HashMultimap<TableName,Entry<String,Long>> archivedFilesByTable = HashMultimap.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
*/
package org.apache.hadoop.hbase.quotas;

import static org.apache.hadoop.hbase.quotas.QuotaUtil.QUOTA_CONF_KEY;
import static org.apache.hadoop.hbase.util.Bytes.toBytes;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.master.MasterServices;
Expand Down Expand Up @@ -51,6 +55,10 @@ public void testOldEntriesRemoved() {
MasterServices masterServices = mock(MasterServices.class);
MasterQuotaManager manager = new MasterQuotaManager(masterServices);
manager.initializeRegionSizes();
HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
Configuration conf = TEST_UTIL.getConfiguration();
conf.set(QUOTA_CONF_KEY, "false");
when(masterServices.getConfiguration()).thenReturn(conf);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you disabling the quota feature here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

// Mock out some regions
TableName tableName = TableName.valueOf("foo");
HRegionInfo region1 = new HRegionInfo(tableName, null, toBytes("a"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.hadoop.conf.Configuration;
Expand All @@ -31,12 +32,15 @@
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.RegionInfo;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.master.HMaster;
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.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
Expand Down Expand Up @@ -221,4 +225,30 @@ public void testTableQuotaOverridesNamespaceQuota() throws Exception {
Bytes.toBytes("reject"));
helper.verifyViolation(policy, tn, p);
}

@Test
public void testDisablePolicyQuotaAndViolate() throws Exception {
TableName tableName = helper.createTable();
helper.setQuotaLimit(tableName, SpaceViolationPolicy.DISABLE, 2L);
helper.writeData(tableName, SpaceQuotaHelperForTests.ONE_MEGABYTE * 3L);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1MB should be enough to trigger the quota, no?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to 1MB.


HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
MasterQuotaManager quotaManager = master.getMasterQuotaManager();

// Sufficient time for all the chores to run.
Thread.sleep(5000);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the state you're actually expecting to happen? RegionSize reports to be sent in?

Same issue as one of your recent PRs. Can you please convert this into an wait+explicit check?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. added a wait predicate.


long timeToPrune = System.currentTimeMillis() + 11 * 60 * 1000;
quotaManager.pruneEntriesOlderThan(timeToPrune);

// Check if disabled table region report present in the map after retention period expired.
// It should be present after retention period expired.
for (Map.Entry<RegionInfo, Long> entry : quotaManager.snapshotRegionSizes().entrySet()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about making this whole for-loop:

quotaManager.snapshotRegionSize().keySet()
  .stream()
  .filter(k -> k.getTable().equals(tableName))
  .count() > 0`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (entry.getKey().getTable().equals(tableName)) {
assertTrue(true);
return;
}
}
Assert.fail("Testcase failed, disable entry removed");
}
}