View Javadoc

1   /*
2    * Copyright (c) 2010.  The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.hbql.impl;
22  
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.HBaseConfiguration;
25  import org.apache.hadoop.hbase.HColumnDescriptor;
26  import org.apache.hadoop.hbase.HTableDescriptor;
27  import org.apache.hadoop.hbase.MasterNotRunningException;
28  import org.apache.hadoop.hbase.client.HBaseAdmin;
29  import org.apache.hadoop.hbase.client.HTablePool;
30  import org.apache.hadoop.hbase.client.tableindexed.IndexSpecification;
31  import org.apache.hadoop.hbase.client.tableindexed.IndexedTable;
32  import org.apache.hadoop.hbase.client.tableindexed.IndexedTableAdmin;
33  import org.apache.hadoop.hbase.client.tableindexed.IndexedTableDescriptor;
34  import org.apache.hadoop.hbase.hbql.client.AsyncExecutor;
35  import org.apache.hadoop.hbase.hbql.client.AsyncExecutorManager;
36  import org.apache.hadoop.hbase.hbql.client.ExecutionResults;
37  import org.apache.hadoop.hbase.hbql.client.HBatch;
38  import org.apache.hadoop.hbase.hbql.client.HBqlException;
39  import org.apache.hadoop.hbase.hbql.client.HConnection;
40  import org.apache.hadoop.hbase.hbql.client.HMapping;
41  import org.apache.hadoop.hbase.hbql.client.HPreparedStatement;
42  import org.apache.hadoop.hbase.hbql.client.HRecord;
43  import org.apache.hadoop.hbase.hbql.client.HResultSet;
44  import org.apache.hadoop.hbase.hbql.client.HStatement;
45  import org.apache.hadoop.hbase.hbql.client.QueryExecutorPool;
46  import org.apache.hadoop.hbase.hbql.client.QueryExecutorPoolManager;
47  import org.apache.hadoop.hbase.hbql.mapping.AnnotationResultAccessor;
48  import org.apache.hadoop.hbase.hbql.mapping.FamilyMapping;
49  import org.apache.hadoop.hbase.hbql.mapping.TableMapping;
50  import org.apache.hadoop.hbase.hbql.statement.args.KeyInfo;
51  import org.apache.hadoop.hbase.hbql.statement.args.WithArgs;
52  import org.apache.hadoop.hbase.hbql.util.AtomicReferences;
53  import org.apache.hadoop.hbase.hbql.util.Maps;
54  import org.apache.hadoop.hbase.hbql.util.PoolableElement;
55  import org.apache.hadoop.hbase.hbql.util.Sets;
56  import org.apache.hadoop.hbase.util.Bytes;
57  
58  import java.io.IOException;
59  import java.util.List;
60  import java.util.Map;
61  import java.util.Set;
62  import java.util.concurrent.atomic.AtomicBoolean;
63  import java.util.concurrent.atomic.AtomicReference;
64  
65  public class HConnectionImpl extends PoolableElement<HConnectionImpl> implements HConnection {
66  
67      public static final String MAXTABLEREFS = "maxtablerefs";
68      public static final String MASTER = "hbase.master";
69  
70      private final AtomicBoolean atomicClosed = new AtomicBoolean(false);
71      private final HBaseConfiguration hbaseConfiguration;
72      private final HTablePool tablePool;
73      private final int maxTablePoolReferencesPerTable;
74      private final MappingManager mappingManager;
75  
76      private final AtomicReference<Map<Class, AnnotationResultAccessor>> atomicAnnoMapping = AtomicReferences.newAtomicReference();
77      private final AtomicReference<HBaseAdmin> atomicHbaseAdmin = AtomicReferences.newAtomicReference();
78      private final AtomicReference<IndexedTableAdmin> atomicIndexTableAdmin = AtomicReferences.newAtomicReference();
79  
80      private String queryExecutorPoolName = null;
81      private String asyncExecutorName = null;
82  
83      public HConnectionImpl(final HBaseConfiguration hbaseConfiguration,
84                             final HConnectionPoolImpl connectionPool,
85                             final int maxTablePoolReferencesPerTable) throws HBqlException {
86          super(connectionPool);
87          this.hbaseConfiguration = (hbaseConfiguration == null) ? new HBaseConfiguration() : hbaseConfiguration;
88          this.maxTablePoolReferencesPerTable = maxTablePoolReferencesPerTable;
89          this.tablePool = new HTablePool(this.getHBaseConfiguration(), this.getMaxTablePoolReferencesPerTable());
90          this.mappingManager = new MappingManager(this);
91  
92          this.getMappingManager().validatePersistentMetadata();
93      }
94  
95      public static HBaseConfiguration getHBaseConfiguration(final String master) {
96          final Configuration configuration = new Configuration();
97          configuration.set(HConnectionImpl.MASTER, master);
98          return new HBaseConfiguration(configuration);
99      }
100 
101     private AtomicReference<Map<Class, AnnotationResultAccessor>> getAtomicAnnoMapping() {
102         return this.atomicAnnoMapping;
103     }
104 
105     public void resetElement() {
106 
107         try {
108             this.getAtomicClosed().set(false);
109             this.getMappingManager().clear();
110         }
111         catch (HBqlException e) {
112             e.printStackTrace();
113         }
114 
115         if (this.getAtomicAnnoMapping().get() != null)
116             this.getAtomicAnnoMapping().get().clear();
117 
118         this.setQueryExecutorPoolName(null);
119     }
120 
121     public boolean isPooled() {
122         return this.getElementPool() != null;
123     }
124 
125     public HBaseConfiguration getHBaseConfiguration() {
126         return this.hbaseConfiguration;
127     }
128 
129     private HTablePool getTablePool() {
130         return this.tablePool;
131     }
132 
133     private MappingManager getMappingManager() throws HBqlException {
134         this.checkIfClosed();
135         return this.mappingManager;
136     }
137 
138     public int getMaxTablePoolReferencesPerTable() {
139         return this.maxTablePoolReferencesPerTable;
140     }
141 
142     private Map<Class, AnnotationResultAccessor> getAnnotationMappingMap() {
143         if (this.getAtomicAnnoMapping().get() == null) {
144             synchronized (this) {
145                 if (this.getAtomicAnnoMapping().get() == null) {
146                     final Map<Class, AnnotationResultAccessor> newmap = Maps.newConcurrentHashMap();
147                     this.getAtomicAnnoMapping().set(newmap);
148                 }
149             }
150         }
151         return this.getAtomicAnnoMapping().get();
152     }
153 
154     public AnnotationResultAccessor getAnnotationMapping(final Object obj) throws HBqlException {
155         return this.getAnnotationMapping(obj.getClass());
156     }
157 
158     public synchronized AnnotationResultAccessor getAnnotationMapping(final Class<?> clazz) throws HBqlException {
159 
160         AnnotationResultAccessor accessor = getAnnotationMappingMap().get(clazz);
161 
162         if (accessor != null) {
163             return accessor;
164         }
165         else {
166             accessor = AnnotationResultAccessor.newAnnotationMapping(this, clazz);
167             getAnnotationMappingMap().put(clazz, accessor);
168             return accessor;
169         }
170     }
171 
172     private AtomicReference<HBaseAdmin> getAtomicHbaseAdmin() {
173         return this.atomicHbaseAdmin;
174     }
175 
176     public HBaseAdmin getHBaseAdmin() throws HBqlException {
177         this.checkIfClosed();
178         if (this.getAtomicHbaseAdmin().get() == null) {
179             synchronized (this) {
180                 if (this.getAtomicHbaseAdmin().get() == null) {
181                     try {
182                         this.getAtomicHbaseAdmin().set(new HBaseAdmin(this.getHBaseConfiguration()));
183                     }
184                     catch (MasterNotRunningException e) {
185                         throw new HBqlException(e);
186                     }
187                 }
188             }
189         }
190         return this.getAtomicHbaseAdmin().get();
191     }
192 
193     private AtomicReference<IndexedTableAdmin> getAtomicIndexTableAdmin() {
194         return this.atomicIndexTableAdmin;
195     }
196 
197     public IndexedTableAdmin getIndexTableAdmin() throws HBqlException {
198         this.checkIfClosed();
199         if (this.getAtomicIndexTableAdmin().get() == null) {
200             synchronized (this) {
201                 if (this.getAtomicIndexTableAdmin().get() == null) {
202                     try {
203                         this.getAtomicIndexTableAdmin().set(new IndexedTableAdmin(this.getHBaseConfiguration()));
204                     }
205                     catch (MasterNotRunningException e) {
206                         throw new HBqlException(e);
207                     }
208                 }
209             }
210         }
211         return this.getAtomicIndexTableAdmin().get();
212     }
213 
214     public Set<String> getFamilyNames(final String tableName) throws HBqlException {
215         this.checkIfClosed();
216         final HTableDescriptor table = this.getHTableDescriptor(tableName);
217         final Set<String> familySet = Sets.newHashSet();
218         for (final HColumnDescriptor descriptor : table.getColumnFamilies())
219             familySet.add(Bytes.toString(descriptor.getName()));
220         return familySet;
221     }
222 
223     public boolean familyExistsForTable(final String familyName, final String tableName) throws HBqlException {
224         final Set<String> names = this.getFamilyNames(tableName);
225         return names.contains(familyName);
226     }
227 
228     public boolean familyExistsForMapping(final String familyName, final String mappingName) throws HBqlException {
229         final TableMapping mapping = this.getMapping(mappingName);
230         return mapping.containsFamily(familyName);
231     }
232 
233     public IndexedTableDescriptor newIndexedTableDescriptor(final String tableName) throws HBqlException {
234         this.checkIfClosed();
235         try {
236             final HTableDescriptor tableDesc = this.getHTableDescriptor(tableName);
237             return new IndexedTableDescriptor(tableDesc);
238         }
239         catch (IOException e) {
240             throw new HBqlException(e);
241         }
242     }
243 
244     public boolean indexExistsForMapping(final String indexName, final String mappingName) throws HBqlException {
245         final TableMapping mapping = this.getMapping(mappingName);
246         return this.indexExistsForTable(indexName, mapping.getTableName());
247     }
248 
249     public IndexSpecification getIndexForTable(final String indexName, final String tableName) throws HBqlException {
250         final IndexedTableDescriptor indexDesc = this.newIndexedTableDescriptor(tableName);
251         return indexDesc.getIndex(indexName);
252     }
253 
254     public boolean indexExistsForTable(final String indexName, final String tableName) throws HBqlException {
255         this.checkIfClosed();
256         final IndexSpecification index = this.getIndexForTable(indexName, tableName);
257         return index != null;
258     }
259 
260     public void dropIndexForMapping(final String indexName, final String mappingName) throws HBqlException {
261         final TableMapping mapping = this.getMapping(mappingName);
262         this.dropIndexForTable(mapping.getTableName(), indexName);
263     }
264 
265     public void dropIndexForTable(final String tableName, final String indexName) throws HBqlException {
266         this.validateIndexExistsForTable(indexName, tableName);
267         try {
268             final IndexedTableAdmin ita = this.getIndexTableAdmin();
269             ita.removeIndex(tableName.getBytes(), indexName);
270         }
271         catch (IOException e) {
272             throw new HBqlException(e);
273         }
274     }
275 
276     public HStatement createStatement() throws HBqlException {
277         this.checkIfClosed();
278         return new HStatementImpl(this);
279     }
280 
281     public HPreparedStatement prepareStatement(final String sql) throws HBqlException {
282         this.checkIfClosed();
283         return new HPreparedStatementImpl(this, sql);
284     }
285 
286     public void releaseElement() {
287         this.getElementPool().release(this);
288     }
289 
290     private AtomicBoolean getAtomicClosed() {
291         return this.atomicClosed;
292     }
293 
294     public boolean isClosed() {
295         return this.getAtomicClosed().get();
296     }
297 
298     public synchronized void close() {
299         if (!this.isClosed()) {
300             this.getAtomicClosed().set(true);
301             // If it is a pool conection, just give it back to pool (reset() will be called on release)
302             if (this.isPooled())
303                 this.releaseElement();
304         }
305     }
306 
307     private void checkIfClosed() throws HBqlException {
308         if (this.isClosed())
309             throw new HBqlException("Connection is closed");
310     }
311 
312     public ExecutionResults execute(final String sql) throws HBqlException {
313         final HStatement stmt = this.createStatement();
314         return stmt.execute(sql);
315     }
316 
317     public HResultSet<HRecord> executeQuery(final String sql) throws HBqlException {
318         final HStatement stmt = this.createStatement();
319         return stmt.executeQuery(sql);
320     }
321 
322     public <T> HResultSet<T> executeQuery(final String sql, final Class clazz) throws HBqlException {
323         final HStatement stmt = this.createStatement();
324         return stmt.executeQuery(sql, clazz);
325     }
326 
327     public List<HRecord> executeQueryAndFetch(final String sql) throws HBqlException {
328         final HStatement stmt = this.createStatement();
329         return stmt.executeQueryAndFetch(sql);
330     }
331 
332     public <T> List<T> executeQueryAndFetch(final String sql, final Class clazz) throws HBqlException {
333         final HStatement stmt = this.createStatement();
334         return stmt.executeQueryAndFetch(sql, clazz);
335     }
336 
337     public ExecutionResults executeUpdate(final String sql) throws HBqlException {
338         final HStatement stmt = this.createStatement();
339         return stmt.executeUpdate(sql);
340     }
341 
342     // Mapping Routines
343     public boolean mappingExists(final String mappingName) throws HBqlException {
344         return this.getMappingManager().mappingExists(mappingName);
345     }
346 
347     public TableMapping getMapping(final String mappingName) throws HBqlException {
348         return this.getMappingManager().getMapping(mappingName);
349     }
350 
351     public boolean dropMapping(final String mappingName) throws HBqlException {
352         return this.getMappingManager().dropMapping(mappingName);
353     }
354 
355     public Set<HMapping> getAllMappings() throws HBqlException {
356         return this.getMappingManager().getAllMappings();
357     }
358 
359     public TableMapping createMapping(final boolean tempMapping,
360                                       final boolean systemMapping,
361                                       final String mappingName,
362                                       final String tableName,
363                                       final KeyInfo keyInfo,
364                                       final List<FamilyMapping> familyList) throws HBqlException {
365         return this.getMappingManager().createMapping(tempMapping,
366                                                       systemMapping,
367                                                       mappingName,
368                                                       tableName,
369                                                       keyInfo,
370                                                       familyList);
371     }
372 
373     // Table Routines
374     public void createTable(final HTableDescriptor tableDesc) throws HBqlException {
375         this.checkIfClosed();
376         final String tableName = tableDesc.getNameAsString();
377         if (this.tableExists(tableName))
378             throw new HBqlException("Table already exists: " + tableName);
379 
380         try {
381             this.getHBaseAdmin().createTable(tableDesc);
382         }
383         catch (IOException e) {
384             throw new HBqlException(e);
385         }
386     }
387 
388     public HTableWrapper newHTableWrapper(final WithArgs withArgs, final String tableName) throws HBqlException {
389 
390         this.checkIfClosed();
391 
392         try {
393             if (withArgs != null && withArgs.hasAnIndex())
394                 return new HTableWrapper(new IndexedTable(this.getHBaseConfiguration(), tableName.getBytes()), null);
395             else
396                 return new HTableWrapper(this.getTablePool().getTable(tableName), this.getTablePool());
397         }
398         catch (IOException e) {
399             throw new HBqlException(e);
400         }
401         catch (RuntimeException e) {
402             throw new HBqlException("Invalid table name: " + tableName);
403         }
404     }
405 
406     public boolean tableExists(final String tableName) throws HBqlException {
407         try {
408             return this.getHBaseAdmin().tableExists(tableName);
409         }
410         catch (MasterNotRunningException e) {
411             throw new HBqlException(e);
412         }
413     }
414 
415     public HTableDescriptor getHTableDescriptor(final String tableName) throws HBqlException {
416         this.validateTableName(tableName);
417         try {
418             return this.getHBaseAdmin().getTableDescriptor(tableName.getBytes());
419         }
420         catch (IOException e) {
421             throw new HBqlException(e);
422         }
423     }
424 
425     public boolean tableAvailable(final String tableName) throws HBqlException {
426         this.validateTableName(tableName);
427         try {
428             return this.getHBaseAdmin().isTableAvailable(tableName);
429         }
430         catch (IOException e) {
431             throw new HBqlException(e);
432         }
433     }
434 
435     public boolean tableEnabled(final String tableName) throws HBqlException {
436         this.validateTableName(tableName);
437         try {
438             return this.getHBaseAdmin().isTableEnabled(tableName);
439         }
440         catch (IOException e) {
441             throw new HBqlException(e);
442         }
443     }
444 
445     public void dropTable(final String tableName) throws HBqlException {
446         validateTableDisabled(tableName, "drop");
447         try {
448             final byte[] tableNameBytes = tableName.getBytes();
449             this.getHBaseAdmin().deleteTable(tableNameBytes);
450         }
451         catch (IOException e) {
452             throw new HBqlException(e);
453         }
454     }
455 
456     public void disableTable(final String tableName) throws HBqlException {
457         try {
458             if (!this.tableEnabled(tableName))
459                 throw new HBqlException("Cannot disable disabled table: " + tableName);
460             this.getHBaseAdmin().disableTable(tableName);
461         }
462         catch (IOException e) {
463             throw new HBqlException(e);
464         }
465     }
466 
467     public void enableTable(final String tableName) throws HBqlException {
468         validateTableDisabled(tableName, "enable");
469         try {
470             this.getHBaseAdmin().enableTable(tableName);
471         }
472         catch (IOException e) {
473             throw new HBqlException(e);
474         }
475     }
476 
477     public Set<String> getTableNames() throws HBqlException {
478         try {
479             final HBaseAdmin admin = this.getHBaseAdmin();
480             final Set<String> tableSet = Sets.newHashSet();
481             for (final HTableDescriptor table : admin.listTables())
482                 tableSet.add(table.getNameAsString());
483             return tableSet;
484         }
485         catch (IOException e) {
486             throw new HBqlException(e);
487         }
488     }
489 
490     // The value returned from this call must be eventually released.
491     public CompletionQueueExecutor getQueryExecutorForConnection() throws HBqlException {
492 
493         if (!Utils.isValidString(this.getQueryExecutorPoolName()))
494             throw new HBqlException("Connection not assigned a QueryExecutorPool name");
495 
496         this.validateQueryExecutorPoolNameExists(this.getQueryExecutorPoolName());
497 
498         final QueryExecutorPool pool = QueryExecutorPoolManager.getQueryExecutorPool(this.getQueryExecutorPoolName());
499         final CompletionQueueExecutor executorQueue = ((QueryExecutorPoolImpl)pool).take();
500 
501         // Reset it prior to handing it out
502         executorQueue.resetElement();
503         return executorQueue;
504     }
505 
506     // The value returned from this call must eventually be released.
507     public AsyncExecutorImpl getAsyncExecutorForConnection() throws HBqlException {
508 
509         if (!Utils.isValidString(this.getAsyncExecutorName()))
510             throw new HBqlException("Connection not assigned an AsyncExecutor name");
511 
512         this.validateAsyncExecutorNameExists(this.getAsyncExecutorName());
513 
514         final AsyncExecutor executor = AsyncExecutorManager.getAsyncExecutor(this.getAsyncExecutorName());
515 
516         return ((AsyncExecutorImpl)executor);
517     }
518 
519 
520     public boolean usesQueryExecutor() {
521         return Utils.isValidString(this.getQueryExecutorPoolName());
522     }
523 
524     public String getQueryExecutorPoolName() {
525         return this.queryExecutorPoolName;
526     }
527 
528     public void setQueryExecutorPoolName(final String poolName) {
529         this.queryExecutorPoolName = poolName;
530     }
531 
532     public String getAsyncExecutorName() {
533         return this.asyncExecutorName;
534     }
535 
536     public void setAsyncExecutorName(final String poolName) {
537         this.asyncExecutorName = poolName;
538     }
539 
540     public <T> HBatch<T> newHBatch() {
541         return new HBatch<T>(this);
542     }
543 
544     public void validateTableName(final String tableName) throws HBqlException {
545         if (!this.tableExists(tableName))
546             throw new HBqlException("Table not found: " + tableName);
547     }
548 
549     public void validateTableDisabled(final String tableName, final String action) throws HBqlException {
550         if (this.tableEnabled(tableName))
551             throw new HBqlException("Cannot " + action + " enabled table: " + tableName);
552     }
553 
554     public void validateFamilyExistsForTable(final String familyName, final String tableName) throws HBqlException {
555         if (!this.familyExistsForTable(familyName, tableName))
556             throw new HBqlException("Family " + familyName + " not defined for table " + tableName);
557     }
558 
559     public void validateIndexExistsForTable(final String indexName, final String tableName) throws HBqlException {
560         if (!this.indexExistsForTable(indexName, tableName))
561             throw new HBqlException("Index " + indexName + " not defined for table " + tableName);
562     }
563 
564     public void validateQueryExecutorPoolNameExists(final String poolName) throws HBqlException {
565         if (!QueryExecutorPoolManager.queryExecutorPoolExists(poolName))
566             throw new HBqlException("QueryExecutorPool " + poolName + " does not exist.");
567     }
568 
569     public void validateAsyncExecutorNameExists(final String name) throws HBqlException {
570         if (!AsyncExecutorManager.asyncExecutorExists(name))
571             throw new HBqlException("AsyncExecutor " + name + " does not exist.");
572     }
573 }