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 java.io.Closeable; 021import java.io.IOException; 022import java.util.ArrayDeque; 023import java.util.Iterator; 024import java.util.Objects; 025import java.util.Queue; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.client.Connection; 028import org.apache.hadoop.hbase.client.ConnectionFactory; 029import org.apache.hadoop.hbase.client.Result; 030import org.apache.hadoop.hbase.client.ResultScanner; 031import org.apache.hadoop.hbase.client.Scan; 032import org.apache.hadoop.hbase.client.Table; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.util.StringUtils; 035import org.apache.yetus.audience.InterfaceAudience; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039/** 040 * Scanner to iterate over the quota settings. 041 */ 042@InterfaceAudience.Public 043public class QuotaRetriever implements Closeable, Iterable<QuotaSettings> { 044 private static final Logger LOG = LoggerFactory.getLogger(QuotaRetriever.class); 045 046 private final Queue<QuotaSettings> cache = new ArrayDeque<>(); 047 private ResultScanner scanner; 048 /** 049 * Connection to use. Could pass one in and have this class use it but this class wants to be 050 * standalone. 051 */ 052 private Connection connection; 053 private Table table; 054 055 /** 056 * Should QutoaRetriever manage the state of the connection, or leave it be. 057 */ 058 private final boolean isManagedConnection; 059 060 public QuotaRetriever(final Connection conn) throws IOException { 061 this(conn, (QuotaFilter) null); 062 } 063 064 public QuotaRetriever(final Connection conn, final QuotaFilter filter) throws IOException { 065 this(conn, QuotaTableUtil.makeScan(filter)); 066 } 067 068 public QuotaRetriever(final Connection conn, final Scan scan) throws IOException { 069 isManagedConnection = false; 070 init(conn, scan); 071 } 072 073 QuotaRetriever(final Configuration conf, final Scan scan) throws IOException { 074 // Set this before creating the connection and passing it down to make sure 075 // it's cleaned up if we fail to construct the Scanner. 076 isManagedConnection = true; 077 init(ConnectionFactory.createConnection(conf), scan); 078 } 079 080 private void init(final Connection conn, final Scan scan) throws IOException { 081 this.connection = Objects.requireNonNull(conn); 082 this.table = this.connection.getTable(QuotaTableUtil.QUOTA_TABLE_NAME); 083 try { 084 scanner = table.getScanner(scan); 085 } catch (IOException e) { 086 try { 087 close(); 088 } catch (IOException ioe) { 089 LOG.warn("Failed getting scanner and then failed close on cleanup", e); 090 } 091 throw e; 092 } 093 } 094 095 @Override 096 public void close() throws IOException { 097 if (this.table != null) { 098 this.table.close(); 099 this.table = null; 100 } 101 // Null out the connection on close() even if we didn't explicitly close it 102 // to maintain typical semantics. 103 if (isManagedConnection) { 104 if (this.connection != null) { 105 this.connection.close(); 106 } 107 } 108 this.connection = null; 109 } 110 111 public QuotaSettings next() throws IOException { 112 if (cache.isEmpty()) { 113 Result result = scanner.next(); 114 // Skip exceedThrottleQuota row key because this is not a QuotaSettings 115 if ( 116 result != null 117 && Bytes.equals(result.getRow(), QuotaTableUtil.getExceedThrottleQuotaRowKey()) 118 ) { 119 result = scanner.next(); 120 } 121 if (result == null) { 122 return null; 123 } 124 QuotaTableUtil.parseResultToCollection(result, cache); 125 } 126 return cache.poll(); 127 } 128 129 @Override 130 public Iterator<QuotaSettings> iterator() { 131 return new Iter(); 132 } 133 134 private class Iter implements Iterator<QuotaSettings> { 135 QuotaSettings cache; 136 137 public Iter() { 138 try { 139 cache = QuotaRetriever.this.next(); 140 } catch (IOException e) { 141 LOG.warn(StringUtils.stringifyException(e)); 142 } 143 } 144 145 @Override 146 public boolean hasNext() { 147 return cache != null; 148 } 149 150 @Override 151 public QuotaSettings next() { 152 QuotaSettings result = cache; 153 try { 154 cache = QuotaRetriever.this.next(); 155 } catch (IOException e) { 156 LOG.warn(StringUtils.stringifyException(e)); 157 } 158 return result; 159 } 160 161 @Override 162 public void remove() { 163 throw new RuntimeException("remove() not supported"); 164 } 165 } 166 167 /** 168 * Open a QuotaRetriever with no filter, all the quota settings will be returned. 169 * @param conf Configuration object to use. 170 * @return the QuotaRetriever 171 * @throws IOException if a remote or network exception occurs 172 * @deprecated Since 3.0.0, will be removed in 4.0.0. Use 173 * {@link #QuotaRetriever(Configuration, Scan)} instead. 174 */ 175 @Deprecated 176 public static QuotaRetriever open(final Configuration conf) throws IOException { 177 return open(conf, null); 178 } 179 180 /** 181 * Open a QuotaRetriever with the specified filter. 182 * @param conf Configuration object to use. 183 * @param filter the QuotaFilter 184 * @return the QuotaRetriever 185 * @throws IOException if a remote or network exception occurs 186 * @deprecated Since 3.0.0, will be removed in 4.0.0. Use 187 * {@link #QuotaRetriever(Configuration, Scan)} instead. 188 */ 189 @Deprecated 190 public static QuotaRetriever open(final Configuration conf, final QuotaFilter filter) 191 throws IOException { 192 Scan scan = QuotaTableUtil.makeScan(filter); 193 return new QuotaRetriever(conf, scan); 194 } 195 196}