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