|
25 | 25 | import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
|
26 | 26 | import com.google.cloud.bigtable.admin.v2.models.RestoreTableRequest;
|
27 | 27 | import com.google.cloud.bigtable.admin.v2.models.Table;
|
| 28 | +import com.google.cloud.bigtable.data.v2.models.KeyOffset; |
28 | 29 | import com.google.cloud.bigtable.hbase.BigtableOptionsFactory;
|
29 | 30 | import com.google.cloud.bigtable.hbase.util.Logger;
|
30 | 31 | import com.google.cloud.bigtable.hbase.util.ModifyTableBuilder;
|
|
35 | 36 | import com.google.common.base.Strings;
|
36 | 37 | import com.google.common.base.Throwables;
|
37 | 38 | import com.google.common.collect.ImmutableList;
|
| 39 | +import com.google.protobuf.ByteString; |
38 | 40 | import io.grpc.Status;
|
39 | 41 | import java.io.IOException;
|
| 42 | +import java.lang.reflect.InvocationHandler; |
40 | 43 | import java.lang.reflect.InvocationTargetException;
|
| 44 | +import java.lang.reflect.Method; |
| 45 | +import java.util.ArrayList; |
41 | 46 | import java.util.Collection;
|
42 | 47 | import java.util.Collections;
|
43 | 48 | import java.util.List;
|
|
55 | 60 | import net.bytebuddy.matcher.ElementMatchers;
|
56 | 61 | import org.apache.hadoop.conf.Configuration;
|
57 | 62 | import org.apache.hadoop.hbase.HTableDescriptor;
|
| 63 | +import org.apache.hadoop.hbase.RegionMetrics; |
| 64 | +import org.apache.hadoop.hbase.ServerName; |
| 65 | +import org.apache.hadoop.hbase.Size; |
| 66 | +import org.apache.hadoop.hbase.Size.Unit; |
58 | 67 | import org.apache.hadoop.hbase.TableName;
|
59 | 68 | import org.apache.hadoop.hbase.TableNotDisabledException;
|
60 | 69 | import org.apache.hadoop.hbase.TableNotEnabledException;
|
@@ -555,6 +564,36 @@ public CompletableFuture<List<RegionInfo>> getRegions(TableName tableName) {
|
555 | 564 | });
|
556 | 565 | }
|
557 | 566 |
|
| 567 | + @Override |
| 568 | + public CompletableFuture<List<RegionMetrics>> getRegionMetrics( |
| 569 | + ServerName ignored, TableName tableName) { |
| 570 | + // TODO: implement caching |
| 571 | + CompletableFuture<List<KeyOffset>> keyOffsetsFuture = |
| 572 | + toCompletableFuture( |
| 573 | + asyncConnection |
| 574 | + .getBigtableApi() |
| 575 | + .getDataClient() |
| 576 | + .sampleRowKeysAsync(tableName.getNameAsString())); |
| 577 | + |
| 578 | + return keyOffsetsFuture.thenApply( |
| 579 | + keyOffsets -> { |
| 580 | + long now = System.currentTimeMillis(); |
| 581 | + List<RegionMetrics> metrics = new ArrayList<>(); |
| 582 | + ByteString lastKey = ByteString.EMPTY; |
| 583 | + long lastOffset = 0; |
| 584 | + for (KeyOffset keyOffset : keyOffsets) { |
| 585 | + byte[] regionName = |
| 586 | + RegionInfo.createRegionName( |
| 587 | + tableName, lastKey.toByteArray(), Bytes.toBytes(now), false); |
| 588 | + metrics.add( |
| 589 | + BasicRegionMetrics.create(regionName, keyOffset.getOffsetBytes() - lastOffset)); |
| 590 | + lastKey = keyOffset.getKey(); |
| 591 | + lastOffset = keyOffset.getOffsetBytes(); |
| 592 | + } |
| 593 | + return metrics; |
| 594 | + }); |
| 595 | + } |
| 596 | + |
558 | 597 | @Override
|
559 | 598 | public CompletableFuture<Void> snapshot(SnapshotDescription snapshot) {
|
560 | 599 | Objects.requireNonNull(snapshot);
|
@@ -601,4 +640,67 @@ public static BigtableAsyncAdmin createInstance(CommonConnection connection) thr
|
601 | 640 | throw new IOException(e);
|
602 | 641 | }
|
603 | 642 | }
|
| 643 | + |
| 644 | + private static Class<? extends RegionMetrics> regionMetricsClass = null; |
| 645 | + |
| 646 | + private static synchronized Class<? extends RegionMetrics> getRegionMetricsSubclass() |
| 647 | + throws NoSuchMethodException { |
| 648 | + if (regionMetricsClass == null) { |
| 649 | + regionMetricsClass = |
| 650 | + new ByteBuddy() |
| 651 | + .subclass(BasicRegionMetrics.class) |
| 652 | + .name(BasicRegionMetrics.class.getName() + "Impl") |
| 653 | + .method(ElementMatchers.isAbstract()) |
| 654 | + .intercept(InvocationHandlerAdapter.of(new UnsupportedOperationsHandler())) |
| 655 | + .make() |
| 656 | + .load(BigtableAsyncAdmin.class.getClassLoader()) |
| 657 | + .getLoaded(); |
| 658 | + } |
| 659 | + return regionMetricsClass; |
| 660 | + } |
| 661 | + |
| 662 | + public abstract static class BasicRegionMetrics implements RegionMetrics { |
| 663 | + private final byte[] regionName; |
| 664 | + private final long size; |
| 665 | + |
| 666 | + static RegionMetrics create(byte[] regionName, long size) { |
| 667 | + try { |
| 668 | + return getRegionMetricsSubclass() |
| 669 | + .getConstructor(byte[].class, long.class) |
| 670 | + .newInstance(regionName, size); |
| 671 | + } catch (NoSuchMethodException |
| 672 | + | InstantiationException |
| 673 | + | IllegalAccessException |
| 674 | + | InvocationTargetException e) { |
| 675 | + throw new IllegalStateException("Failed to instantiate RegionMetrics subclass", e); |
| 676 | + } |
| 677 | + } |
| 678 | + |
| 679 | + public BasicRegionMetrics(byte[] regionName, long size) { |
| 680 | + this.regionName = regionName; |
| 681 | + this.size = size; |
| 682 | + } |
| 683 | + |
| 684 | + @Override |
| 685 | + public byte[] getRegionName() { |
| 686 | + return regionName; |
| 687 | + } |
| 688 | + |
| 689 | + @Override |
| 690 | + public int getStoreFileCount() { |
| 691 | + return 1; |
| 692 | + } |
| 693 | + |
| 694 | + @Override |
| 695 | + public Size getStoreFileSize() { |
| 696 | + return new Size(size, Unit.BYTE); |
| 697 | + } |
| 698 | + } |
| 699 | + /** Handler for unsupported operations for generating Admin class at runtime. */ |
| 700 | + public static class UnsupportedOperationsHandler implements InvocationHandler { |
| 701 | + @Override |
| 702 | + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
| 703 | + throw new UnsupportedOperationException(method.getName()); |
| 704 | + } |
| 705 | + } |
604 | 706 | }
|
0 commit comments