001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to you under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.hadoop.hbase.quotas; 018 019import java.io.IOException; 020import java.util.Optional; 021 022import org.apache.hadoop.conf.Configuration; 023import org.apache.hadoop.hbase.CoprocessorEnvironment; 024import org.apache.hadoop.hbase.TableName; 025import org.apache.hadoop.hbase.client.Admin; 026import org.apache.hadoop.hbase.client.Connection; 027import org.apache.hadoop.hbase.coprocessor.CoprocessorException; 028import org.apache.hadoop.hbase.coprocessor.CoreCoprocessor; 029import org.apache.hadoop.hbase.coprocessor.HasMasterServices; 030import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor; 031import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; 032import org.apache.hadoop.hbase.coprocessor.MasterObserver; 033import org.apache.hadoop.hbase.coprocessor.ObserverContext; 034import org.apache.hadoop.hbase.master.MasterServices; 035import org.apache.yetus.audience.InterfaceAudience; 036import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas; 037 038/** 039 * An observer to automatically delete quotas when a table/namespace 040 * is deleted. 041 */ 042@CoreCoprocessor 043@InterfaceAudience.Private 044public class MasterQuotasObserver implements MasterCoprocessor, MasterObserver { 045 public static final String REMOVE_QUOTA_ON_TABLE_DELETE = "hbase.quota.remove.on.table.delete"; 046 public static final boolean REMOVE_QUOTA_ON_TABLE_DELETE_DEFAULT = true; 047 048 private CoprocessorEnvironment cpEnv; 049 private Configuration conf; 050 private boolean quotasEnabled = false; 051 private MasterServices masterServices; 052 053 @Override 054 public Optional<MasterObserver> getMasterObserver() { 055 return Optional.of(this); 056 } 057 058 @Override 059 public void start(CoprocessorEnvironment ctx) throws IOException { 060 this.conf = ctx.getConfiguration(); 061 this.quotasEnabled = QuotaUtil.isQuotaEnabled(conf); 062 063 if (!(ctx instanceof MasterCoprocessorEnvironment)) { 064 throw new CoprocessorException("Must be loaded on master."); 065 } 066 // if running on master 067 MasterCoprocessorEnvironment mEnv = (MasterCoprocessorEnvironment) ctx; 068 if (mEnv instanceof HasMasterServices) { 069 this.masterServices = ((HasMasterServices) mEnv).getMasterServices(); 070 } else { 071 throw new CoprocessorException("Must be loaded on a master having master services."); 072 } 073 } 074 075 @Override 076 public void postDeleteTable( 077 ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName) throws IOException { 078 // Do nothing if quotas aren't enabled 079 if (!quotasEnabled) { 080 return; 081 } 082 final Connection conn = ctx.getEnvironment().getConnection(); 083 Quotas tableQuotas = QuotaUtil.getTableQuota(conn, tableName); 084 Quotas namespaceQuotas = QuotaUtil.getNamespaceQuota(conn, tableName.getNamespaceAsString()); 085 if (tableQuotas != null || namespaceQuotas != null) { 086 // Remove regions of table from space quota map. 087 this.masterServices.getMasterQuotaManager().removeRegionSizesForTable(tableName); 088 if (tableQuotas != null) { 089 if (tableQuotas.hasSpace()) { 090 QuotaSettings settings = QuotaSettingsFactory.removeTableSpaceLimit(tableName); 091 try (Admin admin = conn.getAdmin()) { 092 admin.setQuota(settings); 093 } 094 } 095 if (tableQuotas.hasThrottle()) { 096 QuotaSettings settings = QuotaSettingsFactory.unthrottleTable(tableName); 097 try (Admin admin = conn.getAdmin()) { 098 admin.setQuota(settings); 099 } 100 } 101 } 102 } 103 } 104 105 @Override 106 public void postDeleteNamespace( 107 ObserverContext<MasterCoprocessorEnvironment> ctx, String namespace) throws IOException { 108 // Do nothing if quotas aren't enabled 109 if (!quotasEnabled) { 110 return; 111 } 112 final Connection conn = ctx.getEnvironment().getConnection(); 113 Quotas quotas = QuotaUtil.getNamespaceQuota(conn, namespace); 114 if (quotas != null) { 115 if (quotas.hasSpace()) { 116 QuotaSettings settings = QuotaSettingsFactory.removeNamespaceSpaceLimit(namespace); 117 try (Admin admin = conn.getAdmin()) { 118 admin.setQuota(settings); 119 } 120 } 121 if (quotas.hasThrottle()) { 122 QuotaSettings settings = QuotaSettingsFactory.unthrottleNamespace(namespace); 123 try (Admin admin = conn.getAdmin()) { 124 admin.setQuota(settings); 125 } 126 } 127 } 128 } 129}