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