View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.client;
20  
21  import java.io.Closeable;
22  import java.io.IOException;
23  import java.util.Collection;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HBaseConfiguration;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.client.coprocessor.Batch;
33  import org.apache.hadoop.hbase.client.coprocessor.Batch.Callback;
34  import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
35  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.hadoop.hbase.util.PoolMap;
38  import org.apache.hadoop.hbase.util.PoolMap.PoolType;
39  
40  import com.google.protobuf.Descriptors;
41  import com.google.protobuf.Message;
42  import com.google.protobuf.Service;
43  import com.google.protobuf.ServiceException;
44  
45  /**
46   * A simple pool of HTable instances.
47   *
48   * Each HTablePool acts as a pool for all tables. To use, instantiate an
49   * HTablePool and use {@link #getTable(String)} to get an HTable from the pool.
50   *
51     * This method is not needed anymore, clients should call
52     * HTableInterface.close() rather than returning the tables to the pool
53     *
54   * Once you are done with it, close your instance of {@link HTableInterface}
55   * by calling {@link HTableInterface#close()} rather than returning the tables
56   * to the pool with (deprecated) {@link #putTable(HTableInterface)}.
57   *
58   * <p>
59   * A pool can be created with a <i>maxSize</i> which defines the most HTable
60   * references that will ever be retained for each table. Otherwise the default
61   * is {@link Integer#MAX_VALUE}.
62   *
63   * <p>
64   * Pool will manage its own connections to the cluster. See
65   * {@link HConnectionManager}.
66   * @deprecated as of 0.98.1. See {@link HConnection#getTable(String)}.
67   */
68  @InterfaceAudience.Private
69  @Deprecated
70  public class HTablePool implements Closeable {
71    private final PoolMap<String, HTableInterface> tables;
72    private final int maxSize;
73    private final PoolType poolType;
74    private final Configuration config;
75    private final HTableInterfaceFactory tableFactory;
76  
77    /**
78     * Default Constructor. Default HBaseConfiguration and no limit on pool size.
79     */
80    public HTablePool() {
81      this(HBaseConfiguration.create(), Integer.MAX_VALUE);
82    }
83  
84    /**
85     * Constructor to set maximum versions and use the specified configuration.
86     *
87     * @param config
88     *          configuration
89     * @param maxSize
90     *          maximum number of references to keep for each table
91     */
92    public HTablePool(final Configuration config, final int maxSize) {
93      this(config, maxSize, null, null);
94    }
95  
96    /**
97     * Constructor to set maximum versions and use the specified configuration and
98     * table factory.
99     *
100    * @param config
101    *          configuration
102    * @param maxSize
103    *          maximum number of references to keep for each table
104    * @param tableFactory
105    *          table factory
106    */
107   public HTablePool(final Configuration config, final int maxSize,
108       final HTableInterfaceFactory tableFactory) {
109     this(config, maxSize, tableFactory, PoolType.Reusable);
110   }
111 
112   /**
113    * Constructor to set maximum versions and use the specified configuration and
114    * pool type.
115    *
116    * @param config
117    *          configuration
118    * @param maxSize
119    *          maximum number of references to keep for each table
120    * @param poolType
121    *          pool type which is one of {@link PoolType#Reusable} or
122    *          {@link PoolType#ThreadLocal}
123    */
124   public HTablePool(final Configuration config, final int maxSize,
125       final PoolType poolType) {
126     this(config, maxSize, null, poolType);
127   }
128 
129   /**
130    * Constructor to set maximum versions and use the specified configuration,
131    * table factory and pool type. The HTablePool supports the
132    * {@link PoolType#Reusable} and {@link PoolType#ThreadLocal}. If the pool
133    * type is null or not one of those two values, then it will default to
134    * {@link PoolType#Reusable}.
135    *
136    * @param config
137    *          configuration
138    * @param maxSize
139    *          maximum number of references to keep for each table
140    * @param tableFactory
141    *          table factory
142    * @param poolType
143    *          pool type which is one of {@link PoolType#Reusable} or
144    *          {@link PoolType#ThreadLocal}
145    */
146   public HTablePool(final Configuration config, final int maxSize,
147       final HTableInterfaceFactory tableFactory, PoolType poolType) {
148     // Make a new configuration instance so I can safely cleanup when
149     // done with the pool.
150     this.config = config == null ? HBaseConfiguration.create() : config;
151     this.maxSize = maxSize;
152     this.tableFactory = tableFactory == null ? new HTableFactory()
153         : tableFactory;
154     if (poolType == null) {
155       this.poolType = PoolType.Reusable;
156     } else {
157       switch (poolType) {
158       case Reusable:
159       case ThreadLocal:
160         this.poolType = poolType;
161         break;
162       default:
163         this.poolType = PoolType.Reusable;
164         break;
165       }
166     }
167     this.tables = new PoolMap<String, HTableInterface>(this.poolType,
168         this.maxSize);
169   }
170 
171   /**
172    * Get a reference to the specified table from the pool.
173    *
174    * @param tableName
175    *          table name
176    * @return a reference to the specified table
177    * @throws RuntimeException
178    *           if there is a problem instantiating the HTable
179    */
180   public HTableInterface getTable(String tableName) {
181     // call the old getTable implementation renamed to findOrCreateTable
182     HTableInterface table = findOrCreateTable(tableName);
183     // return a proxy table so when user closes the proxy, the actual table
184     // will be returned to the pool
185     return new PooledHTable(table);
186   }
187 
188   /**
189    * Get a reference to the specified table from the pool.
190    *
191    * Create a new one if one is not available.
192    *
193    * @param tableName
194    *          table name
195    * @return a reference to the specified table
196    * @throws RuntimeException
197    *           if there is a problem instantiating the HTable
198    */
199   private HTableInterface findOrCreateTable(String tableName) {
200     HTableInterface table = tables.get(tableName);
201     if (table == null) {
202       table = createHTable(tableName);
203     }
204     return table;
205   }
206 
207   /**
208    * Get a reference to the specified table from the pool.
209    * <p>
210    *
211    * Create a new one if one is not available.
212    *
213    * @param tableName
214    *          table name
215    * @return a reference to the specified table
216    * @throws RuntimeException
217    *           if there is a problem instantiating the HTable
218    */
219   public HTableInterface getTable(byte[] tableName) {
220     return getTable(Bytes.toString(tableName));
221   }
222 
223   /**
224    * This method is not needed anymore, clients should call
225    * HTableInterface.close() rather than returning the tables to the pool
226    *
227    * @param table
228    *          the proxy table user got from pool
229    * @deprecated
230    */
231   public void putTable(HTableInterface table) throws IOException {
232     // we need to be sure nobody puts a proxy implementation in the pool
233     // but if the client code is not updated
234     // and it will continue to call putTable() instead of calling close()
235     // then we need to return the wrapped table to the pool instead of the
236     // proxy
237     // table
238     if (table instanceof PooledHTable) {
239       returnTable(((PooledHTable) table).getWrappedTable());
240     } else {
241       // normally this should not happen if clients pass back the same
242       // table
243       // object they got from the pool
244       // but if it happens then it's better to reject it
245       throw new IllegalArgumentException("not a pooled table: " + table);
246     }
247   }
248 
249   /**
250    * Puts the specified HTable back into the pool.
251    * <p>
252    *
253    * If the pool already contains <i>maxSize</i> references to the table, then
254    * the table instance gets closed after flushing buffered edits.
255    *
256    * @param table
257    *          table
258    */
259   private void returnTable(HTableInterface table) throws IOException {
260     // this is the old putTable method renamed and made private
261     String tableName = Bytes.toString(table.getTableName());
262     if (tables.size(tableName) >= maxSize) {
263       // release table instance since we're not reusing it
264       this.tables.removeValue(tableName, table);
265       this.tableFactory.releaseHTableInterface(table);
266       return;
267     }
268     tables.put(tableName, table);
269   }
270 
271   protected HTableInterface createHTable(String tableName) {
272     return this.tableFactory.createHTableInterface(config,
273         Bytes.toBytes(tableName));
274   }
275 
276   /**
277    * Closes all the HTable instances , belonging to the given table, in the
278    * table pool.
279    * <p>
280    * Note: this is a 'shutdown' of the given table pool and different from
281    * {@link #putTable(HTableInterface)}, that is used to return the table
282    * instance to the pool for future re-use.
283    *
284    * @param tableName
285    */
286   public void closeTablePool(final String tableName) throws IOException {
287     Collection<HTableInterface> tables = this.tables.values(tableName);
288     if (tables != null) {
289       for (HTableInterface table : tables) {
290         this.tableFactory.releaseHTableInterface(table);
291       }
292     }
293     this.tables.remove(tableName);
294   }
295 
296   /**
297    * See {@link #closeTablePool(String)}.
298    *
299    * @param tableName
300    */
301   public void closeTablePool(final byte[] tableName) throws IOException {
302     closeTablePool(Bytes.toString(tableName));
303   }
304 
305   /**
306    * Closes all the HTable instances , belonging to all tables in the table
307    * pool.
308    * <p>
309    * Note: this is a 'shutdown' of all the table pools.
310    */
311   @Override
312   public void close() throws IOException {
313     for (String tableName : tables.keySet()) {
314       closeTablePool(tableName);
315     }
316     this.tables.clear();
317   }
318 
319   public int getCurrentPoolSize(String tableName) {
320     return tables.size(tableName);
321   }
322 
323   /**
324    * A proxy class that implements HTableInterface.close method to return the
325    * wrapped table back to the table pool
326    *
327    */
328   class PooledHTable implements HTableInterface {
329 
330     private boolean open = false;
331 
332     private HTableInterface table; // actual table implementation
333 
334     public PooledHTable(HTableInterface table) {
335       this.table = table;
336       this.open = true;
337     }
338 
339     @Override
340     public byte[] getTableName() {
341       checkState();
342       return table.getTableName();
343     }
344 
345     @Override
346     public TableName getName() {
347       return table.getName();
348     }
349 
350     @Override
351     public Configuration getConfiguration() {
352       checkState();
353       return table.getConfiguration();
354     }
355 
356     @Override
357     public HTableDescriptor getTableDescriptor() throws IOException {
358       checkState();
359       return table.getTableDescriptor();
360     }
361 
362     @Override
363     public boolean exists(Get get) throws IOException {
364       checkState();
365       return table.exists(get);
366     }
367 
368     @Override
369     public boolean[] existsAll(List<Get> gets) throws IOException {
370       checkState();
371       return table.existsAll(gets);
372     }
373 
374     @Override
375     public Boolean[] exists(List<Get> gets) throws IOException {
376       checkState();
377       return table.exists(gets);
378     }
379 
380     @Override
381     public void batch(List<? extends Row> actions, Object[] results) throws IOException,
382         InterruptedException {
383       checkState();
384       table.batch(actions, results);
385     }
386 
387     /**
388      * {@inheritDoc}
389      * @deprecated If any exception is thrown by one of the actions, there is no way to
390      * retrieve the partially executed results. Use {@link #batch(List, Object[])} instead.
391      */
392     @Override
393     public Object[] batch(List<? extends Row> actions) throws IOException,
394         InterruptedException {
395       checkState();
396       return table.batch(actions);
397     }
398 
399     @Override
400     public Result get(Get get) throws IOException {
401       checkState();
402       return table.get(get);
403     }
404 
405     @Override
406     public Result[] get(List<Get> gets) throws IOException {
407       checkState();
408       return table.get(gets);
409     }
410 
411     @Override
412     @SuppressWarnings("deprecation")
413     @Deprecated
414     public Result getRowOrBefore(byte[] row, byte[] family) throws IOException {
415       checkState();
416       return table.getRowOrBefore(row, family);
417     }
418 
419     @Override
420     public ResultScanner getScanner(Scan scan) throws IOException {
421       checkState();
422       return table.getScanner(scan);
423     }
424 
425     @Override
426     public ResultScanner getScanner(byte[] family) throws IOException {
427       checkState();
428       return table.getScanner(family);
429     }
430 
431     @Override
432     public ResultScanner getScanner(byte[] family, byte[] qualifier)
433         throws IOException {
434       checkState();
435       return table.getScanner(family, qualifier);
436     }
437 
438     @Override
439     public void put(Put put) throws IOException {
440       checkState();
441       table.put(put);
442     }
443 
444     @Override
445     public void put(List<Put> puts) throws IOException {
446       checkState();
447       table.put(puts);
448     }
449 
450     @Override
451     public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
452         byte[] value, Put put) throws IOException {
453       checkState();
454       return table.checkAndPut(row, family, qualifier, value, put);
455     }
456 
457     @Override
458     public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
459         CompareOp compareOp, byte[] value, Put put) throws IOException {
460       checkState();
461       return table.checkAndPut(row, family, qualifier, compareOp, value, put);
462     }
463 
464     @Override
465     public void delete(Delete delete) throws IOException {
466       checkState();
467       table.delete(delete);
468     }
469 
470     @Override
471     public void delete(List<Delete> deletes) throws IOException {
472       checkState();
473       table.delete(deletes);
474     }
475 
476     @Override
477     public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
478         byte[] value, Delete delete) throws IOException {
479       checkState();
480       return table.checkAndDelete(row, family, qualifier, value, delete);
481     }
482 
483     @Override
484     public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
485         CompareOp compareOp, byte[] value, Delete delete) throws IOException {
486       checkState();
487       return table.checkAndDelete(row, family, qualifier, compareOp, value, delete);
488     }
489 
490     @Override
491     public Result increment(Increment increment) throws IOException {
492       checkState();
493       return table.increment(increment);
494     }
495 
496     @Override
497     public long incrementColumnValue(byte[] row, byte[] family,
498         byte[] qualifier, long amount) throws IOException {
499       checkState();
500       return table.incrementColumnValue(row, family, qualifier, amount);
501     }
502 
503     @Override
504     public long incrementColumnValue(byte[] row, byte[] family,
505         byte[] qualifier, long amount, Durability durability) throws IOException {
506       checkState();
507       return table.incrementColumnValue(row, family, qualifier, amount,
508           durability);
509     }
510 
511     @Override
512     public boolean isAutoFlush() {
513       checkState();
514       return table.isAutoFlush();
515     }
516 
517     @Override
518     public void flushCommits() throws IOException {
519       checkState();
520       table.flushCommits();
521     }
522 
523     /**
524      * Returns the actual table back to the pool
525      *
526      * @throws IOException
527      */
528     @Override
529     public void close() throws IOException {
530       checkState();
531       open = false;
532       returnTable(table);
533     }
534 
535     @Override
536     public CoprocessorRpcChannel coprocessorService(byte[] row) {
537       checkState();
538       return table.coprocessorService(row);
539     }
540 
541     @Override
542     public <T extends Service, R> Map<byte[], R> coprocessorService(Class<T> service,
543         byte[] startKey, byte[] endKey, Batch.Call<T, R> callable)
544         throws ServiceException, Throwable {
545       checkState();
546       return table.coprocessorService(service, startKey, endKey, callable);
547     }
548 
549     @Override
550     public <T extends Service, R> void coprocessorService(Class<T> service,
551         byte[] startKey, byte[] endKey, Batch.Call<T, R> callable, Callback<R> callback)
552         throws ServiceException, Throwable {
553       checkState();
554       table.coprocessorService(service, startKey, endKey, callable, callback);
555     }
556 
557     @Override
558     public String toString() {
559       return "PooledHTable{" + ", table=" + table + '}';
560     }
561 
562     /**
563      * Expose the wrapped HTable to tests in the same package
564      *
565      * @return wrapped htable
566      */
567     HTableInterface getWrappedTable() {
568       return table;
569     }
570 
571     @Override
572     public <R> void batchCallback(List<? extends Row> actions,
573         Object[] results, Callback<R> callback) throws IOException,
574         InterruptedException {
575       checkState();
576       table.batchCallback(actions, results, callback);
577     }
578 
579     /**
580      * {@inheritDoc}
581      * @deprecated If any exception is thrown by one of the actions, there is no way to
582      * retrieve the partially executed results. Use
583      * {@link #batchCallback(List, Object[], org.apache.hadoop.hbase.client.coprocessor.Batch.Callback)}
584      * instead.
585      */
586     @Override
587     public <R> Object[] batchCallback(List<? extends Row> actions,
588         Callback<R> callback) throws IOException, InterruptedException {
589       checkState();
590       return table.batchCallback(actions,  callback);
591     }
592 
593     @Override
594     public void mutateRow(RowMutations rm) throws IOException {
595       checkState();
596       table.mutateRow(rm);
597     }
598 
599     @Override
600     public Result append(Append append) throws IOException {
601       checkState();
602       return table.append(append);
603     }
604 
605     @Override
606     public void setAutoFlush(boolean autoFlush) {
607       checkState();
608       table.setAutoFlush(autoFlush, autoFlush);
609     }
610 
611     @Override
612     public void setAutoFlush(boolean autoFlush, boolean clearBufferOnFail) {
613       checkState();
614       table.setAutoFlush(autoFlush, clearBufferOnFail);
615     }
616 
617     @Override
618     public void setAutoFlushTo(boolean autoFlush) {
619       table.setAutoFlushTo(autoFlush);
620     }
621 
622     @Override
623     public long getWriteBufferSize() {
624       checkState();
625       return table.getWriteBufferSize();
626     }
627 
628     @Override
629     public void setWriteBufferSize(long writeBufferSize) throws IOException {
630       checkState();
631       table.setWriteBufferSize(writeBufferSize);
632     }
633 
634     boolean isOpen() {
635       return open;
636     }
637 
638     private void checkState() {
639       if (!isOpen()) {
640         throw new IllegalStateException("Table=" + table.getName().getNameAsString()
641           + " already closed");
642       }
643     }
644 
645     @Override
646     public long incrementColumnValue(byte[] row, byte[] family,
647         byte[] qualifier, long amount, boolean writeToWAL) throws IOException {
648       return table.incrementColumnValue(row, family, qualifier, amount, writeToWAL);
649     }
650 
651     @Override
652     public <R extends Message> Map<byte[], R> batchCoprocessorService(
653         Descriptors.MethodDescriptor method, Message request,
654         byte[] startKey, byte[] endKey, R responsePrototype) throws ServiceException, Throwable {
655       checkState();
656       return table.batchCoprocessorService(method, request, startKey, endKey,
657           responsePrototype);
658     }
659 
660     @Override
661     public <R extends Message> void batchCoprocessorService(
662         Descriptors.MethodDescriptor method, Message request,
663         byte[] startKey, byte[] endKey, R responsePrototype, Callback<R> callback)
664         throws ServiceException, Throwable {
665       checkState();
666       table.batchCoprocessorService(method, request, startKey, endKey, responsePrototype, callback);
667     }
668 
669     @Override
670     public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier, CompareOp compareOp,
671         byte[] value, RowMutations mutation) throws IOException {
672       checkState();
673       return table.checkAndMutate(row, family, qualifier, compareOp, value, mutation);
674     }
675 
676     @Override public void setOperationTimeout(int operationTimeout) {
677       table.setOperationTimeout(operationTimeout);
678     }
679 
680     @Override public int getOperationTimeout() {
681       return table.getOperationTimeout();
682     }
683 
684     @Override
685     @Deprecated
686     public void setRpcTimeout(int rpcTimeout) {
687       table.setRpcTimeout(rpcTimeout);
688     }
689 
690     @Override
691     @Deprecated
692     public int getRpcTimeout() {
693       return table.getRpcTimeout();
694     }
695 
696     @Override
697     public int getReadRpcTimeout() {
698       return table.getReadRpcTimeout();
699     }
700 
701     @Override
702     public void setReadRpcTimeout(int readRpcTimeout) {
703       table.setReadRpcTimeout(readRpcTimeout);
704     }
705 
706     @Override
707     public int getWriteRpcTimeout() {
708       return table.getWriteRpcTimeout();
709     }
710 
711     @Override
712     public void setWriteRpcTimeout(int writeRpcTimeout) {
713       table.setWriteRpcTimeout(writeRpcTimeout);
714     }
715   }
716 }