View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional information regarding
4    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
8    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
9    * for the specific language governing permissions and limitations under the License.
10   */
11  
12  package org.apache.hadoop.hbase.quotas;
13  
14  import java.io.Closeable;
15  import java.io.IOException;
16  import java.util.Iterator;
17  import java.util.LinkedList;
18  import java.util.Objects;
19  import java.util.Queue;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.TableName;
25  import org.apache.hadoop.hbase.classification.InterfaceAudience;
26  import org.apache.hadoop.hbase.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.client.Connection;
28  import org.apache.hadoop.hbase.client.ConnectionFactory;
29  import org.apache.hadoop.hbase.client.Result;
30  import org.apache.hadoop.hbase.client.ResultScanner;
31  import org.apache.hadoop.hbase.client.Scan;
32  import org.apache.hadoop.hbase.client.Table;
33  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
34  import org.apache.hadoop.util.StringUtils;
35  
36  /**
37   * Scanner to iterate over the quota settings.
38   */
39  @InterfaceAudience.Public
40  @InterfaceStability.Evolving
41  public final class QuotaRetriever implements Closeable, Iterable<QuotaSettings> {
42    private static final Log LOG = LogFactory.getLog(QuotaRetriever.class);
43  
44    private final Queue<QuotaSettings> cache = new LinkedList<QuotaSettings>();
45    private ResultScanner scanner;
46    /**
47     * Connection to use. Could pass one in and have this class use it but this class wants to be
48     * standalone.
49     */
50    private Connection connection;
51    private Table table;
52  
53    /**
54     * Should QutoaRetrieve manage the state of the connection, or leave it be.
55     */
56    private boolean isManagedConnection = false;
57  
58    QuotaRetriever() {
59    }
60  
61    void init(final Configuration conf, final Scan scan) throws IOException {
62      // Set this before creating the connection and passing it down to make sure
63      // it's cleaned up if we fail to construct the Scanner.
64      this.isManagedConnection = true;
65      init(ConnectionFactory.createConnection(conf), scan);
66    }
67  
68    void init(final Connection conn, final Scan scan) throws IOException {
69      this.connection = Objects.requireNonNull(conn);
70      this.table = this.connection.getTable(QuotaTableUtil.QUOTA_TABLE_NAME);
71      try {
72        scanner = table.getScanner(scan);
73      } catch (IOException e) {
74        try {
75          close();
76        } catch (IOException ioe) {
77          LOG.warn("Failed getting scanner and then failed close on cleanup", e);
78        }
79        throw e;
80      }
81    }
82  
83    public void close() throws IOException {
84      if (this.table != null) {
85        this.table.close();
86        this.table = null;
87      }
88      // Null out the connection on close() even if we didn't explicitly close it
89      // to maintain typical semantics.
90      if (isManagedConnection) {
91        if (this.connection != null) {
92          this.connection.close();
93        }
94      }
95      this.connection = null;
96    }
97  
98    public QuotaSettings next() throws IOException {
99      if (cache.isEmpty()) {
100       Result result = scanner.next();
101       if (result == null) return null;
102 
103       QuotaTableUtil.parseResult(result, new QuotaTableUtil.QuotasVisitor() {
104         @Override
105         public void visitUserQuotas(String userName, Quotas quotas) {
106           cache.addAll(QuotaSettingsFactory.fromUserQuotas(userName, quotas));
107         }
108 
109         @Override
110         public void visitUserQuotas(String userName, TableName table, Quotas quotas) {
111           cache.addAll(QuotaSettingsFactory.fromUserQuotas(userName, table, quotas));
112         }
113 
114         @Override
115         public void visitUserQuotas(String userName, String namespace, Quotas quotas) {
116           cache.addAll(QuotaSettingsFactory.fromUserQuotas(userName, namespace, quotas));
117         }
118 
119         @Override
120         public void visitTableQuotas(TableName tableName, Quotas quotas) {
121           cache.addAll(QuotaSettingsFactory.fromTableQuotas(tableName, quotas));
122         }
123 
124         @Override
125         public void visitNamespaceQuotas(String namespace, Quotas quotas) {
126           cache.addAll(QuotaSettingsFactory.fromNamespaceQuotas(namespace, quotas));
127         }
128       });
129     }
130     return cache.poll();
131   }
132 
133   @Override
134   public Iterator<QuotaSettings> iterator() {
135     return new Iter();
136   }
137 
138   private class Iter implements Iterator<QuotaSettings> {
139     private QuotaSettings cache;
140 
141     public Iter() {
142       try {
143         cache = QuotaRetriever.this.next();
144       } catch (IOException e) {
145         LOG.warn(StringUtils.stringifyException(e));
146       }
147     }
148 
149     @Override
150     public boolean hasNext() {
151       return cache != null;
152     }
153 
154     @Override
155     public QuotaSettings next() {
156       QuotaSettings result = cache;
157       try {
158         cache = QuotaRetriever.this.next();
159       } catch (IOException e) {
160         LOG.warn(StringUtils.stringifyException(e));
161       }
162       return result;
163     }
164 
165     @Override
166     public void remove() {
167       throw new RuntimeException("remove() not supported");
168     }
169   }
170 
171   /**
172    * Open a QuotaRetriever with no filter, all the quota settings will be returned.
173    * @param conf Configuration object to use.
174    * @return the QuotaRetriever
175    * @throws IOException if a remote or network exception occurs
176    */
177   public static QuotaRetriever open(final Configuration conf) throws IOException {
178     return open(conf, null);
179   }
180 
181   /**
182    * Open a QuotaRetriever with the specified filter.
183    * @param conf Configuration object to use.
184    * @param filter the QuotaFilter
185    * @return the QuotaRetriever
186    * @throws IOException if a remote or network exception occurs
187    */
188   public static QuotaRetriever open(final Configuration conf, final QuotaFilter filter)
189       throws IOException {
190     Scan scan = QuotaTableUtil.makeScan(filter);
191     QuotaRetriever scanner = new QuotaRetriever();
192     scanner.init(conf, scan);
193     return scanner;
194   }
195 }