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.thrift2;
019
020import static org.apache.hadoop.hbase.HConstants.DEFAULT_HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD;
021import static org.apache.hadoop.hbase.HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD;
022import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_READONLY_ENABLED;
023import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_READONLY_ENABLED_DEFAULT;
024import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.appendFromThrift;
025import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.columnFamilyDescriptorFromThrift;
026import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.compareOpFromThrift;
027import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deleteFromThrift;
028import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.deletesFromThrift;
029import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getFromThrift;
030import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.getsFromThrift;
031import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.incrementFromThrift;
032import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.namespaceDescriptorFromHBase;
033import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.namespaceDescriptorFromThrift;
034import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.namespaceDescriptorsFromHBase;
035import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putFromThrift;
036import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.putsFromThrift;
037import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.resultFromHBase;
038import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.resultsFromHBase;
039import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.rowMutationsFromThrift;
040import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.scanFromThrift;
041import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.splitKeyFromThrift;
042import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableDescriptorFromHBase;
043import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableDescriptorFromThrift;
044import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableDescriptorsFromHBase;
045import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableNameFromThrift;
046import static org.apache.hadoop.hbase.thrift2.ThriftUtilities.tableNamesFromHBase;
047import static org.apache.thrift.TBaseHelper.byteBufferToByteArray;
048
049import java.io.IOException;
050import java.nio.ByteBuffer;
051import java.util.ArrayList;
052import java.util.Collections;
053import java.util.List;
054import java.util.Set;
055import java.util.concurrent.TimeUnit;
056import java.util.concurrent.atomic.AtomicInteger;
057import java.util.regex.Pattern;
058import org.apache.hadoop.conf.Configuration;
059import org.apache.hadoop.hbase.DoNotRetryIOException;
060import org.apache.hadoop.hbase.HRegionLocation;
061import org.apache.hadoop.hbase.NamespaceDescriptor;
062import org.apache.hadoop.hbase.ServerName;
063import org.apache.hadoop.hbase.TableName;
064import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
065import org.apache.hadoop.hbase.client.LogQueryFilter;
066import org.apache.hadoop.hbase.client.OnlineLogRecord;
067import org.apache.hadoop.hbase.client.RegionLocator;
068import org.apache.hadoop.hbase.client.ResultScanner;
069import org.apache.hadoop.hbase.client.Table;
070import org.apache.hadoop.hbase.client.TableDescriptor;
071import org.apache.hadoop.hbase.security.UserProvider;
072import org.apache.hadoop.hbase.security.access.AccessControlClient;
073import org.apache.hadoop.hbase.security.access.Permission;
074import org.apache.hadoop.hbase.thrift.HBaseServiceHandler;
075import org.apache.hadoop.hbase.thrift2.generated.TAccessControlEntity;
076import org.apache.hadoop.hbase.thrift2.generated.TAppend;
077import org.apache.hadoop.hbase.thrift2.generated.TColumnFamilyDescriptor;
078import org.apache.hadoop.hbase.thrift2.generated.TCompareOperator;
079import org.apache.hadoop.hbase.thrift2.generated.TDelete;
080import org.apache.hadoop.hbase.thrift2.generated.TGet;
081import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
082import org.apache.hadoop.hbase.thrift2.generated.THRegionLocation;
083import org.apache.hadoop.hbase.thrift2.generated.TIOError;
084import org.apache.hadoop.hbase.thrift2.generated.TIllegalArgument;
085import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
086import org.apache.hadoop.hbase.thrift2.generated.TLogQueryFilter;
087import org.apache.hadoop.hbase.thrift2.generated.TNamespaceDescriptor;
088import org.apache.hadoop.hbase.thrift2.generated.TOnlineLogRecord;
089import org.apache.hadoop.hbase.thrift2.generated.TPermissionScope;
090import org.apache.hadoop.hbase.thrift2.generated.TPut;
091import org.apache.hadoop.hbase.thrift2.generated.TResult;
092import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
093import org.apache.hadoop.hbase.thrift2.generated.TScan;
094import org.apache.hadoop.hbase.thrift2.generated.TServerName;
095import org.apache.hadoop.hbase.thrift2.generated.TTableDescriptor;
096import org.apache.hadoop.hbase.thrift2.generated.TTableName;
097import org.apache.hadoop.hbase.thrift2.generated.TThriftServerType;
098import org.apache.hadoop.hbase.util.Bytes;
099import org.apache.thrift.TException;
100import org.apache.yetus.audience.InterfaceAudience;
101import org.slf4j.Logger;
102import org.slf4j.LoggerFactory;
103
104import org.apache.hbase.thirdparty.com.google.common.cache.Cache;
105import org.apache.hbase.thirdparty.com.google.common.cache.CacheBuilder;
106import org.apache.hbase.thirdparty.com.google.common.cache.RemovalListener;
107
108/**
109 * This class is a glue object that connects Thrift RPC calls to the HBase client API primarily
110 * defined in the Table interface.
111 */
112@InterfaceAudience.Private
113@SuppressWarnings("deprecation")
114public class ThriftHBaseServiceHandler extends HBaseServiceHandler implements THBaseService.Iface {
115
116  // TODO: Size of pool configuraple
117  private static final Logger LOG = LoggerFactory.getLogger(ThriftHBaseServiceHandler.class);
118
119  // nextScannerId and scannerMap are used to manage scanner state
120  private final AtomicInteger nextScannerId = new AtomicInteger(0);
121  private final Cache<Integer, ResultScanner> scannerMap;
122
123  private static final IOException ioe =
124    new DoNotRetryIOException("Thrift Server is in Read-only mode.");
125  private boolean isReadOnly;
126
127  private static class TIOErrorWithCause extends TIOError {
128    private Throwable cause;
129
130    public TIOErrorWithCause(Throwable cause) {
131      super();
132      this.cause = cause;
133    }
134
135    @Override
136    public synchronized Throwable getCause() {
137      return cause;
138    }
139
140    @Override
141    public boolean equals(Object other) {
142      if (super.equals(other) && other instanceof TIOErrorWithCause) {
143        Throwable otherCause = ((TIOErrorWithCause) other).getCause();
144        if (this.getCause() != null) {
145          return otherCause != null && this.getCause().equals(otherCause);
146        } else {
147          return otherCause == null;
148        }
149      }
150      return false;
151    }
152
153    @Override
154    public int hashCode() {
155      int result = super.hashCode();
156      result = 31 * result + (cause != null ? cause.hashCode() : 0);
157      return result;
158    }
159  }
160
161  public ThriftHBaseServiceHandler(final Configuration conf, final UserProvider userProvider)
162    throws IOException {
163    super(conf, userProvider);
164    long cacheTimeout = conf.getLong(HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD,
165      DEFAULT_HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD);
166    isReadOnly = conf.getBoolean(THRIFT_READONLY_ENABLED, THRIFT_READONLY_ENABLED_DEFAULT);
167    scannerMap = CacheBuilder.newBuilder().expireAfterAccess(cacheTimeout, TimeUnit.MILLISECONDS)
168      .removalListener((RemovalListener<Integer,
169        ResultScanner>) removalNotification -> removalNotification.getValue().close())
170      .build();
171  }
172
173  @Override
174  protected Table getTable(ByteBuffer tableName) {
175    try {
176      return connectionCache.getTable(Bytes.toString(byteBufferToByteArray(tableName)));
177    } catch (IOException ie) {
178      throw new RuntimeException(ie);
179    }
180  }
181
182  private RegionLocator getLocator(ByteBuffer tableName) {
183    try {
184      return connectionCache.getRegionLocator(byteBufferToByteArray(tableName));
185    } catch (IOException ie) {
186      throw new RuntimeException(ie);
187    }
188  }
189
190  private void closeTable(Table table) throws TIOError {
191    try {
192      table.close();
193    } catch (IOException e) {
194      throw getTIOError(e);
195    }
196  }
197
198  private TIOError getTIOError(IOException e) {
199    TIOError err = new TIOErrorWithCause(e);
200    err.setCanRetry(!(e instanceof DoNotRetryIOException));
201    err.setMessage(e.getMessage());
202    return err;
203  }
204
205  /**
206   * Assigns a unique ID to the scanner and adds the mapping to an internal HashMap.
207   * @param scanner to add
208   * @return Id for this Scanner
209   */
210  private int addScanner(ResultScanner scanner) {
211    int id = nextScannerId.getAndIncrement();
212    scannerMap.put(id, scanner);
213    return id;
214  }
215
216  /**
217   * Returns the Scanner associated with the specified Id.
218   * @param id of the Scanner to get
219   * @return a Scanner, or null if the Id is invalid
220   */
221  private ResultScanner getScanner(int id) {
222    return scannerMap.getIfPresent(id);
223  }
224
225  /**
226   * Removes the scanner associated with the specified ID from the internal HashMap.
227   * @param id of the Scanner to remove
228   */
229  protected void removeScanner(int id) {
230    scannerMap.invalidate(id);
231  }
232
233  @Override
234  public boolean exists(ByteBuffer table, TGet get) throws TIOError, TException {
235    Table htable = getTable(table);
236    try {
237      return htable.exists(getFromThrift(get));
238    } catch (IOException e) {
239      throw getTIOError(e);
240    } finally {
241      closeTable(htable);
242    }
243  }
244
245  @Override
246  public List<Boolean> existsAll(ByteBuffer table, List<TGet> gets) throws TIOError, TException {
247    Table htable = getTable(table);
248    try {
249      boolean[] exists = htable.exists(getsFromThrift(gets));
250      List<Boolean> result = new ArrayList<>(exists.length);
251      for (boolean exist : exists) {
252        result.add(exist);
253      }
254      return result;
255    } catch (IOException e) {
256      throw getTIOError(e);
257    } finally {
258      closeTable(htable);
259    }
260  }
261
262  @Override
263  public TResult get(ByteBuffer table, TGet get) throws TIOError, TException {
264    Table htable = getTable(table);
265    try {
266      return resultFromHBase(htable.get(getFromThrift(get)));
267    } catch (IOException e) {
268      throw getTIOError(e);
269    } finally {
270      closeTable(htable);
271    }
272  }
273
274  @Override
275  public List<TResult> getMultiple(ByteBuffer table, List<TGet> gets) throws TIOError, TException {
276    Table htable = getTable(table);
277    try {
278      return resultsFromHBase(htable.get(getsFromThrift(gets)));
279    } catch (IOException e) {
280      throw getTIOError(e);
281    } finally {
282      closeTable(htable);
283    }
284  }
285
286  @Override
287  public void put(ByteBuffer table, TPut put) throws TIOError, TException {
288    checkReadOnlyMode();
289    Table htable = getTable(table);
290    try {
291      htable.put(putFromThrift(put));
292    } catch (IOException e) {
293      throw getTIOError(e);
294    } finally {
295      closeTable(htable);
296    }
297  }
298
299  @Override
300  public boolean checkAndPut(ByteBuffer table, ByteBuffer row, ByteBuffer family,
301    ByteBuffer qualifier, ByteBuffer value, TPut put) throws TIOError, TException {
302    checkReadOnlyMode();
303    Table htable = getTable(table);
304    try {
305      Table.CheckAndMutateBuilder builder =
306        htable.checkAndMutate(byteBufferToByteArray(row), byteBufferToByteArray(family))
307          .qualifier(byteBufferToByteArray(qualifier));
308      if (value == null) {
309        return builder.ifNotExists().thenPut(putFromThrift(put));
310      } else {
311        return builder.ifEquals(byteBufferToByteArray(value)).thenPut(putFromThrift(put));
312      }
313    } catch (IOException e) {
314      throw getTIOError(e);
315    } finally {
316      closeTable(htable);
317    }
318  }
319
320  @Override
321  public void putMultiple(ByteBuffer table, List<TPut> puts) throws TIOError, TException {
322    checkReadOnlyMode();
323    Table htable = getTable(table);
324    try {
325      htable.put(putsFromThrift(puts));
326    } catch (IOException e) {
327      throw getTIOError(e);
328    } finally {
329      closeTable(htable);
330    }
331  }
332
333  @Override
334  public void deleteSingle(ByteBuffer table, TDelete deleteSingle) throws TIOError, TException {
335    checkReadOnlyMode();
336    Table htable = getTable(table);
337    try {
338      htable.delete(deleteFromThrift(deleteSingle));
339    } catch (IOException e) {
340      throw getTIOError(e);
341    } finally {
342      closeTable(htable);
343    }
344  }
345
346  @Override
347  public List<TDelete> deleteMultiple(ByteBuffer table, List<TDelete> deletes)
348    throws TIOError, TException {
349    checkReadOnlyMode();
350    Table htable = getTable(table);
351    try {
352      htable.delete(deletesFromThrift(deletes));
353    } catch (IOException e) {
354      throw getTIOError(e);
355    } finally {
356      closeTable(htable);
357    }
358    return Collections.emptyList();
359  }
360
361  @Override
362  public boolean checkAndMutate(ByteBuffer table, ByteBuffer row, ByteBuffer family,
363    ByteBuffer qualifier, TCompareOperator compareOp, ByteBuffer value, TRowMutations rowMutations)
364    throws TIOError, TException {
365    checkReadOnlyMode();
366    try (final Table htable = getTable(table)) {
367      return htable.checkAndMutate(byteBufferToByteArray(row), byteBufferToByteArray(family))
368        .qualifier(byteBufferToByteArray(qualifier))
369        .ifMatches(compareOpFromThrift(compareOp), byteBufferToByteArray(value))
370        .thenMutate(rowMutationsFromThrift(rowMutations));
371    } catch (IOException e) {
372      throw getTIOError(e);
373    }
374  }
375
376  @Override
377  public boolean checkAndDelete(ByteBuffer table, ByteBuffer row, ByteBuffer family,
378    ByteBuffer qualifier, ByteBuffer value, TDelete deleteSingle) throws TIOError, TException {
379    checkReadOnlyMode();
380    Table htable = getTable(table);
381    try {
382      Table.CheckAndMutateBuilder mutateBuilder =
383        htable.checkAndMutate(byteBufferToByteArray(row), byteBufferToByteArray(family))
384          .qualifier(byteBufferToByteArray(qualifier));
385      if (value == null) {
386        return mutateBuilder.ifNotExists().thenDelete(deleteFromThrift(deleteSingle));
387      } else {
388        return mutateBuilder.ifEquals(byteBufferToByteArray(value))
389          .thenDelete(deleteFromThrift(deleteSingle));
390      }
391    } catch (IOException e) {
392      throw getTIOError(e);
393    } finally {
394      closeTable(htable);
395    }
396  }
397
398  @Override
399  public TResult increment(ByteBuffer table, TIncrement increment) throws TIOError, TException {
400    checkReadOnlyMode();
401    Table htable = getTable(table);
402    try {
403      return resultFromHBase(htable.increment(incrementFromThrift(increment)));
404    } catch (IOException e) {
405      throw getTIOError(e);
406    } finally {
407      closeTable(htable);
408    }
409  }
410
411  @Override
412  public TResult append(ByteBuffer table, TAppend append) throws TIOError, TException {
413    checkReadOnlyMode();
414    Table htable = getTable(table);
415    try {
416      return resultFromHBase(htable.append(appendFromThrift(append)));
417    } catch (IOException e) {
418      throw getTIOError(e);
419    } finally {
420      closeTable(htable);
421    }
422  }
423
424  @Override
425  public int openScanner(ByteBuffer table, TScan scan) throws TIOError, TException {
426    Table htable = getTable(table);
427    ResultScanner resultScanner = null;
428    try {
429      resultScanner = htable.getScanner(scanFromThrift(scan));
430    } catch (IOException e) {
431      throw getTIOError(e);
432    } finally {
433      closeTable(htable);
434    }
435    return addScanner(resultScanner);
436  }
437
438  @Override
439  public List<TResult> getScannerRows(int scannerId, int numRows)
440    throws TIOError, TIllegalArgument, TException {
441    ResultScanner scanner = getScanner(scannerId);
442    if (scanner == null) {
443      TIllegalArgument ex = new TIllegalArgument();
444      ex.setMessage("Invalid scanner Id");
445      throw ex;
446    }
447    try {
448      connectionCache.updateConnectionAccessTime();
449      return resultsFromHBase(scanner.next(numRows));
450    } catch (IOException e) {
451      throw getTIOError(e);
452    }
453  }
454
455  @Override
456  public List<TResult> getScannerResults(ByteBuffer table, TScan scan, int numRows)
457    throws TIOError, TException {
458    Table htable = getTable(table);
459    List<TResult> results = null;
460    ResultScanner scanner = null;
461    try {
462      scanner = htable.getScanner(scanFromThrift(scan));
463      results = resultsFromHBase(scanner.next(numRows));
464    } catch (IOException e) {
465      throw getTIOError(e);
466    } finally {
467      if (scanner != null) {
468        scanner.close();
469      }
470      closeTable(htable);
471    }
472    return results;
473  }
474
475  @Override
476  public void closeScanner(int scannerId) throws TIOError, TIllegalArgument, TException {
477    LOG.debug("scannerClose: id=" + scannerId);
478    ResultScanner scanner = getScanner(scannerId);
479    if (scanner == null) {
480      LOG.warn("scanner ID: " + scannerId + "is invalid");
481      // While the scanner could be already expired,
482      // we should not throw exception here. Just log and return.
483      return;
484    }
485    scanner.close();
486    removeScanner(scannerId);
487  }
488
489  @Override
490  public void mutateRow(ByteBuffer table, TRowMutations rowMutations) throws TIOError, TException {
491    checkReadOnlyMode();
492    Table htable = getTable(table);
493    try {
494      htable.mutateRow(rowMutationsFromThrift(rowMutations));
495    } catch (IOException e) {
496      throw getTIOError(e);
497    } finally {
498      closeTable(htable);
499    }
500  }
501
502  @Override
503  public List<THRegionLocation> getAllRegionLocations(ByteBuffer table)
504    throws TIOError, TException {
505    RegionLocator locator = null;
506    try {
507      locator = getLocator(table);
508      return ThriftUtilities.regionLocationsFromHBase(locator.getAllRegionLocations());
509
510    } catch (IOException e) {
511      throw getTIOError(e);
512    } finally {
513      if (locator != null) {
514        try {
515          locator.close();
516        } catch (IOException e) {
517          LOG.warn("Couldn't close the locator.", e);
518        }
519      }
520    }
521  }
522
523  @Override
524  public THRegionLocation getRegionLocation(ByteBuffer table, ByteBuffer row, boolean reload)
525    throws TIOError, TException {
526
527    RegionLocator locator = null;
528    try {
529      locator = getLocator(table);
530      byte[] rowBytes = byteBufferToByteArray(row);
531      HRegionLocation hrl = locator.getRegionLocation(rowBytes, reload);
532      return ThriftUtilities.regionLocationFromHBase(hrl);
533
534    } catch (IOException e) {
535      throw getTIOError(e);
536    } finally {
537      if (locator != null) {
538        try {
539          locator.close();
540        } catch (IOException e) {
541          LOG.warn("Couldn't close the locator.", e);
542        }
543      }
544    }
545  }
546
547  private void checkReadOnlyMode() throws TIOError {
548    if (isReadOnly()) {
549      throw getTIOError(ioe);
550    }
551  }
552
553  private boolean isReadOnly() {
554    return isReadOnly;
555  }
556
557  @Override
558  public TTableDescriptor getTableDescriptor(TTableName table) throws TIOError, TException {
559    try {
560      TableName tableName = ThriftUtilities.tableNameFromThrift(table);
561      TableDescriptor tableDescriptor = connectionCache.getAdmin().getDescriptor(tableName);
562      return tableDescriptorFromHBase(tableDescriptor);
563    } catch (IOException e) {
564      throw getTIOError(e);
565    }
566  }
567
568  @Override
569  public List<TTableDescriptor> getTableDescriptors(List<TTableName> tables)
570    throws TIOError, TException {
571    try {
572      List<TableName> tableNames = ThriftUtilities.tableNamesFromThrift(tables);
573      List<TableDescriptor> tableDescriptors =
574        connectionCache.getAdmin().listTableDescriptors(tableNames);
575      return tableDescriptorsFromHBase(tableDescriptors);
576    } catch (IOException e) {
577      throw getTIOError(e);
578    }
579  }
580
581  @Override
582  public boolean tableExists(TTableName tTableName) throws TIOError, TException {
583    try {
584      TableName tableName = tableNameFromThrift(tTableName);
585      return connectionCache.getAdmin().tableExists(tableName);
586    } catch (IOException e) {
587      throw getTIOError(e);
588    }
589  }
590
591  @Override
592  public List<TTableDescriptor> getTableDescriptorsByPattern(String regex, boolean includeSysTables)
593    throws TIOError, TException {
594    try {
595      Pattern pattern = (regex == null ? null : Pattern.compile(regex));
596      List<TableDescriptor> tableDescriptors =
597        connectionCache.getAdmin().listTableDescriptors(pattern, includeSysTables);
598      return tableDescriptorsFromHBase(tableDescriptors);
599    } catch (IOException e) {
600      throw getTIOError(e);
601    }
602  }
603
604  @Override
605  public List<TTableDescriptor> getTableDescriptorsByNamespace(String name)
606    throws TIOError, TException {
607    try {
608      List<TableDescriptor> descriptors =
609        connectionCache.getAdmin().listTableDescriptorsByNamespace(Bytes.toBytes(name));
610      return tableDescriptorsFromHBase(descriptors);
611    } catch (IOException e) {
612      throw getTIOError(e);
613    }
614  }
615
616  @Override
617  public List<TTableName> getTableNamesByPattern(String regex, boolean includeSysTables)
618    throws TIOError, TException {
619    try {
620      Pattern pattern = (regex == null ? null : Pattern.compile(regex));
621      TableName[] tableNames = connectionCache.getAdmin().listTableNames(pattern, includeSysTables);
622      return tableNamesFromHBase(tableNames);
623    } catch (IOException e) {
624      throw getTIOError(e);
625    }
626  }
627
628  @Override
629  public List<TTableName> getTableNamesByNamespace(String name) throws TIOError, TException {
630    try {
631      TableName[] tableNames = connectionCache.getAdmin().listTableNamesByNamespace(name);
632      return tableNamesFromHBase(tableNames);
633    } catch (IOException e) {
634      throw getTIOError(e);
635    }
636  }
637
638  @Override
639  public void createTable(TTableDescriptor desc, List<ByteBuffer> splitKeys)
640    throws TIOError, TException {
641    try {
642      TableDescriptor descriptor = tableDescriptorFromThrift(desc);
643      byte[][] split = splitKeyFromThrift(splitKeys);
644      if (split != null) {
645        connectionCache.getAdmin().createTable(descriptor, split);
646      } else {
647        connectionCache.getAdmin().createTable(descriptor);
648      }
649    } catch (IOException e) {
650      throw getTIOError(e);
651    }
652  }
653
654  @Override
655  public void deleteTable(TTableName tableName) throws TIOError, TException {
656    try {
657      TableName table = tableNameFromThrift(tableName);
658      connectionCache.getAdmin().deleteTable(table);
659    } catch (IOException e) {
660      throw getTIOError(e);
661    }
662  }
663
664  @Override
665  public void truncateTable(TTableName tableName, boolean preserveSplits)
666    throws TIOError, TException {
667    try {
668      TableName table = tableNameFromThrift(tableName);
669      connectionCache.getAdmin().truncateTable(table, preserveSplits);
670    } catch (IOException e) {
671      throw getTIOError(e);
672    }
673  }
674
675  @Override
676  public void enableTable(TTableName tableName) throws TIOError, TException {
677    try {
678      TableName table = tableNameFromThrift(tableName);
679      connectionCache.getAdmin().enableTable(table);
680    } catch (IOException e) {
681      throw getTIOError(e);
682    }
683  }
684
685  @Override
686  public void disableTable(TTableName tableName) throws TIOError, TException {
687    try {
688      TableName table = tableNameFromThrift(tableName);
689      connectionCache.getAdmin().disableTable(table);
690    } catch (IOException e) {
691      throw getTIOError(e);
692    }
693  }
694
695  @Override
696  public boolean isTableEnabled(TTableName tableName) throws TIOError, TException {
697    try {
698      TableName table = tableNameFromThrift(tableName);
699      return connectionCache.getAdmin().isTableEnabled(table);
700    } catch (IOException e) {
701      throw getTIOError(e);
702    }
703  }
704
705  @Override
706  public boolean isTableDisabled(TTableName tableName) throws TIOError, TException {
707    try {
708      TableName table = tableNameFromThrift(tableName);
709      return connectionCache.getAdmin().isTableDisabled(table);
710    } catch (IOException e) {
711      throw getTIOError(e);
712    }
713  }
714
715  @Override
716  public boolean isTableAvailable(TTableName tableName) throws TIOError, TException {
717    try {
718      TableName table = tableNameFromThrift(tableName);
719      return connectionCache.getAdmin().isTableAvailable(table);
720    } catch (IOException e) {
721      throw getTIOError(e);
722    }
723  }
724
725  @Override
726  public void addColumnFamily(TTableName tableName, TColumnFamilyDescriptor column)
727    throws TIOError, TException {
728    try {
729      TableName table = tableNameFromThrift(tableName);
730      ColumnFamilyDescriptor columnFamilyDescriptor = columnFamilyDescriptorFromThrift(column);
731      connectionCache.getAdmin().addColumnFamily(table, columnFamilyDescriptor);
732    } catch (IOException e) {
733      throw getTIOError(e);
734    }
735  }
736
737  @Override
738  public void deleteColumnFamily(TTableName tableName, ByteBuffer column)
739    throws TIOError, TException {
740    try {
741      TableName table = tableNameFromThrift(tableName);
742      connectionCache.getAdmin().deleteColumnFamily(table, column.array());
743    } catch (IOException e) {
744      throw getTIOError(e);
745    }
746  }
747
748  @Override
749  public void modifyColumnFamily(TTableName tableName, TColumnFamilyDescriptor column)
750    throws TIOError, TException {
751    try {
752      TableName table = tableNameFromThrift(tableName);
753      ColumnFamilyDescriptor columnFamilyDescriptor = columnFamilyDescriptorFromThrift(column);
754      connectionCache.getAdmin().modifyColumnFamily(table, columnFamilyDescriptor);
755    } catch (IOException e) {
756      throw getTIOError(e);
757    }
758  }
759
760  @Override
761  public void modifyTable(TTableDescriptor desc) throws TIOError, TException {
762    try {
763      TableDescriptor descriptor = tableDescriptorFromThrift(desc);
764      connectionCache.getAdmin().modifyTable(descriptor);
765    } catch (IOException e) {
766      throw getTIOError(e);
767    }
768  }
769
770  @Override
771  public void createNamespace(TNamespaceDescriptor namespaceDesc) throws TIOError, TException {
772    try {
773      NamespaceDescriptor descriptor = namespaceDescriptorFromThrift(namespaceDesc);
774      connectionCache.getAdmin().createNamespace(descriptor);
775    } catch (IOException e) {
776      throw getTIOError(e);
777    }
778  }
779
780  @Override
781  public void modifyNamespace(TNamespaceDescriptor namespaceDesc) throws TIOError, TException {
782    try {
783      NamespaceDescriptor descriptor = namespaceDescriptorFromThrift(namespaceDesc);
784      connectionCache.getAdmin().modifyNamespace(descriptor);
785    } catch (IOException e) {
786      throw getTIOError(e);
787    }
788  }
789
790  @Override
791  public void deleteNamespace(String name) throws TIOError, TException {
792    try {
793      connectionCache.getAdmin().deleteNamespace(name);
794    } catch (IOException e) {
795      throw getTIOError(e);
796    }
797  }
798
799  @Override
800  public TNamespaceDescriptor getNamespaceDescriptor(String name) throws TIOError, TException {
801    try {
802      NamespaceDescriptor descriptor = connectionCache.getAdmin().getNamespaceDescriptor(name);
803      return namespaceDescriptorFromHBase(descriptor);
804    } catch (IOException e) {
805      throw getTIOError(e);
806    }
807  }
808
809  @Override
810  public List<String> listNamespaces() throws TIOError, TException {
811    try {
812      String[] namespaces = connectionCache.getAdmin().listNamespaces();
813      List<String> result = new ArrayList<>(namespaces.length);
814      for (String ns : namespaces) {
815        result.add(ns);
816      }
817      return result;
818    } catch (IOException e) {
819      throw getTIOError(e);
820    }
821  }
822
823  @Override
824  public TThriftServerType getThriftServerType() {
825    return TThriftServerType.TWO;
826  }
827
828  @Override
829  public String getClusterId() throws TException {
830    return connectionCache.getClusterId();
831  }
832
833  @Override
834  public List<TOnlineLogRecord> getSlowLogResponses(Set<TServerName> tServerNames,
835    TLogQueryFilter tLogQueryFilter) throws TIOError, TException {
836    try {
837      Set<ServerName> serverNames = ThriftUtilities.getServerNamesFromThrift(tServerNames);
838      LogQueryFilter logQueryFilter = ThriftUtilities.getSlowLogQueryFromThrift(tLogQueryFilter);
839      List<OnlineLogRecord> onlineLogRecords =
840        connectionCache.getAdmin().getSlowLogResponses(serverNames, logQueryFilter);
841      return ThriftUtilities.getSlowLogRecordsFromHBase(onlineLogRecords);
842    } catch (IOException e) {
843      throw getTIOError(e);
844    }
845  }
846
847  @Override
848  public List<Boolean> clearSlowLogResponses(Set<TServerName> tServerNames)
849    throws TIOError, TException {
850    Set<ServerName> serverNames = ThriftUtilities.getServerNamesFromThrift(tServerNames);
851    try {
852      return connectionCache.getAdmin().clearSlowLogResponses(serverNames);
853    } catch (IOException e) {
854      throw getTIOError(e);
855    }
856  }
857
858  @Override
859  public boolean grant(TAccessControlEntity info) throws TIOError, TException {
860    Permission.Action[] actions = ThriftUtilities.permissionActionsFromString(info.actions);
861    try {
862      if (info.scope == TPermissionScope.NAMESPACE) {
863        AccessControlClient.grant(connectionCache.getAdmin().getConnection(), info.getNsName(),
864          info.getUsername(), actions);
865      } else if (info.scope == TPermissionScope.TABLE) {
866        TableName tableName = TableName.valueOf(info.getTableName());
867        AccessControlClient.grant(connectionCache.getAdmin().getConnection(), tableName,
868          info.getUsername(), null, null, actions);
869      }
870    } catch (Throwable t) {
871      if (t instanceof IOException) {
872        throw getTIOError((IOException) t);
873      } else {
874        throw getTIOError(new DoNotRetryIOException(t.getMessage()));
875      }
876    }
877    return true;
878  }
879
880  @Override
881  public boolean revoke(TAccessControlEntity info) throws TIOError, TException {
882    Permission.Action[] actions = ThriftUtilities.permissionActionsFromString(info.actions);
883    try {
884      if (info.scope == TPermissionScope.NAMESPACE) {
885        AccessControlClient.revoke(connectionCache.getAdmin().getConnection(), info.getNsName(),
886          info.getUsername(), actions);
887      } else if (info.scope == TPermissionScope.TABLE) {
888        TableName tableName = TableName.valueOf(info.getTableName());
889        AccessControlClient.revoke(connectionCache.getAdmin().getConnection(), tableName,
890          info.getUsername(), null, null, actions);
891      }
892    } catch (Throwable t) {
893      if (t instanceof IOException) {
894        throw getTIOError((IOException) t);
895      } else {
896        throw getTIOError(new DoNotRetryIOException(t.getMessage()));
897      }
898    }
899    return true;
900  }
901
902  @Override
903  public List<TNamespaceDescriptor> listNamespaceDescriptors() throws TIOError, TException {
904    try {
905      NamespaceDescriptor[] descriptors = connectionCache.getAdmin().listNamespaceDescriptors();
906      return namespaceDescriptorsFromHBase(descriptors);
907    } catch (IOException e) {
908      throw getTIOError(e);
909    }
910  }
911}