001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.quotas;
019
020import static org.junit.jupiter.api.Assertions.assertTrue;
021import static org.junit.jupiter.api.Assertions.fail;
022
023import java.util.List;
024import java.util.Map;
025import java.util.concurrent.atomic.AtomicLong;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.HBaseTestingUtil;
028import org.apache.hadoop.hbase.MetaTableAccessor;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.Waiter;
031import org.apache.hadoop.hbase.client.Put;
032import org.apache.hadoop.hbase.client.RegionInfo;
033import org.apache.hadoop.hbase.master.HMaster;
034import org.apache.hadoop.hbase.testclassification.LargeTests;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.junit.jupiter.api.AfterAll;
037import org.junit.jupiter.api.BeforeAll;
038import org.junit.jupiter.api.BeforeEach;
039import org.junit.jupiter.api.Tag;
040import org.junit.jupiter.api.Test;
041import org.junit.jupiter.api.TestInfo;
042import org.slf4j.Logger;
043import org.slf4j.LoggerFactory;
044
045@Tag(LargeTests.TAG)
046public class TestSpaceQuotaDropTable {
047
048  private static final Logger LOG = LoggerFactory.getLogger(TestSpaceQuotaDropTable.class);
049  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
050
051  private SpaceQuotaHelperForTests helper;
052
053  @BeforeAll
054  public static void setUp() throws Exception {
055    Configuration conf = TEST_UTIL.getConfiguration();
056    SpaceQuotaHelperForTests.updateConfigForQuotas(conf);
057    TEST_UTIL.startMiniCluster(1);
058  }
059
060  @AfterAll
061  public static void tearDown() throws Exception {
062    TEST_UTIL.shutdownMiniCluster();
063  }
064
065  @BeforeEach
066  public void removeAllQuotas(TestInfo testInfo) throws Exception {
067    helper = new SpaceQuotaHelperForTests(TEST_UTIL, () -> testInfo.getTestMethod().get().getName(),
068      new AtomicLong(0));
069    helper.removeAllQuotas();
070  }
071
072  @Test
073  public void testSetQuotaAndThenDropTableWithNoInserts() throws Exception {
074    setQuotaAndThenDropTable(SpaceViolationPolicy.NO_INSERTS);
075  }
076
077  @Test
078  public void testSetQuotaAndThenDropTableWithNoWrite() throws Exception {
079    setQuotaAndThenDropTable(SpaceViolationPolicy.NO_WRITES);
080  }
081
082  @Test
083  public void testSetQuotaAndThenDropTableWithNoWritesCompactions() throws Exception {
084    setQuotaAndThenDropTable(SpaceViolationPolicy.NO_WRITES_COMPACTIONS);
085  }
086
087  @Test
088  public void testSetQuotaAndThenDropTableWithDisable() throws Exception {
089    setQuotaAndThenDropTable(SpaceViolationPolicy.DISABLE);
090  }
091
092  @Test
093  public void testSetQuotaAndThenDropTableWithRegionReport() throws Exception {
094    final TableName tn = helper.createTable();
095    helper.setQuotaLimit(tn, SpaceViolationPolicy.NO_INSERTS, 1L);
096    helper.writeData(tn, 2L);
097
098    final HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
099    final MasterQuotaManager quotaManager = master.getMasterQuotaManager();
100
101    // Make sure the master has report for the table.
102    Waiter.waitFor(TEST_UTIL.getConfiguration(), 30 * 1000, new Waiter.Predicate<Exception>() {
103      @Override
104      public boolean evaluate() throws Exception {
105        Map<RegionInfo, Long> regionSizes = quotaManager.snapshotRegionSizes();
106        List<RegionInfo> tableRegions =
107          MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), tn);
108        return regionSizes.containsKey(tableRegions.get(0));
109      }
110    });
111
112    boolean hasRegionSize = false;
113
114    // region report should be present before dropping the table.
115    for (Map.Entry<RegionInfo, Long> entry : quotaManager.snapshotRegionSizes().entrySet()) {
116      if (entry.getKey().getTable().equals(tn)) {
117        hasRegionSize = true;
118        break;
119      }
120    }
121
122    // regionSize report for the given table should be present before dropping the table.
123    assertTrue(hasRegionSize);
124
125    // drop the table
126    TEST_UTIL.getAdmin().disableTable(tn);
127    TEST_UTIL.getAdmin().deleteTable(tn);
128
129    // check if deleted table region report still present in the map.
130    for (Map.Entry<RegionInfo, Long> entry : quotaManager.snapshotRegionSizes().entrySet()) {
131      if (entry.getKey().getTable().equals(tn)) {
132        fail("Dropped table regionSizes were not deleted during the drop command");
133      }
134    }
135  }
136
137  private void setQuotaAndThenDropTable(SpaceViolationPolicy policy) throws Exception {
138    Put put = new Put(Bytes.toBytes("to_reject"));
139    put.addColumn(Bytes.toBytes(SpaceQuotaHelperForTests.F1), Bytes.toBytes("to"),
140      Bytes.toBytes("reject"));
141
142    // Do puts until we violate space policy
143    final TableName tn = helper.writeUntilViolationAndVerifyViolation(policy, put);
144
145    // Now, drop the table
146    TEST_UTIL.deleteTable(tn);
147    LOG.debug("Successfully deleted table ", tn);
148
149    // Now re-create the table
150    TEST_UTIL.createTable(tn, Bytes.toBytes(SpaceQuotaHelperForTests.F1));
151    LOG.debug("Successfully re-created table ", tn);
152
153    // Put some rows now: should not violate as table/quota was dropped
154    helper.verifyNoViolation(tn, put);
155  }
156}