Skip to content

Commit 18b2e18

Browse files
authored
fix: dynamically load BigtableAdmin and BigtableAsyncAdmin (#3341)
* fix: load BigtableAdmin with ProxyFactory * update hbase2_x * fix connection class * reformat * use bytebuddy instead * refactor * fix constructor * update javadoc * update error handling * udpate
1 parent 0d1454a commit 18b2e18

File tree

12 files changed

+182
-1362
lines changed

12 files changed

+182
-1362
lines changed

bigtable-client-core-parent/bigtable-hbase/src/main/java/org/apache/hadoop/hbase/client/AbstractBigtableAdmin.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
import com.google.protobuf.ByteString;
4646
import io.grpc.Status;
4747
import java.io.IOException;
48+
import java.lang.reflect.InvocationHandler;
49+
import java.lang.reflect.Method;
4850
import java.util.ArrayList;
4951
import java.util.LinkedList;
5052
import java.util.List;
@@ -1337,4 +1339,12 @@ public int getMasterInfoPort() throws IOException {
13371339
public void rollWALWriter(ServerName serverName) throws IOException, FailedLogCloseException {
13381340
throw new UnsupportedOperationException("rollWALWriter"); // TODO
13391341
}
1342+
1343+
/** Handler for unsupported operations for generating Admin class at runtime. */
1344+
public static class UnsupportedOperationsHandler implements InvocationHandler {
1345+
@Override
1346+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
1347+
throw new UnsupportedOperationException(method.getName());
1348+
}
1349+
}
13401350
}

bigtable-hbase-1.x-parent/bigtable-hbase-1.x-shaded/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ limitations under the License.
159159
<exclude>META-INF/NOTICE</exclude>
160160
<exclude>META-INF/DEPENDENCIES</exclude>
161161
<exclude>META-INF/NOTICE.txt</exclude>
162+
<exclude>META-INF/versions/9/module-info.class</exclude>
162163
</excludes>
163164
</filter>
164165
</filters>
@@ -331,6 +332,10 @@ limitations under the License.
331332
<pattern>javax.annotation</pattern>
332333
<shadedPattern>com.google.bigtable.repackaged.javax.annotation</shadedPattern>
333334
</relocation>
335+
<relocation>
336+
<pattern>net.bytebuddy</pattern>
337+
<shadedPattern>com.google.bigtable.repackaged.net.bytebuddy</shadedPattern>
338+
</relocation>
334339
</relocations>
335340
</configuration>
336341
</execution>

bigtable-hbase-1.x-parent/bigtable-hbase-1.x/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ limitations under the License.
146146
<artifactId>grpc-google-cloud-bigtable-v2</artifactId>
147147
<scope>compile</scope>
148148
</dependency>
149+
<dependency>
150+
<groupId>net.bytebuddy</groupId>
151+
<artifactId>byte-buddy</artifactId>
152+
<version>1.12.2</version>
153+
</dependency>
154+
149155

150156
<!-- Test dependencies-->
151157
<dependency>

bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/main/java/com/google/cloud/bigtable/hbase1_x/BigtableAdmin.java

Lines changed: 45 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,31 @@
1616
package com.google.cloud.bigtable.hbase1_x;
1717

1818
import com.google.api.core.InternalApi;
19+
import com.google.common.base.Throwables;
1920
import com.google.common.collect.ImmutableList;
2021
import com.google.common.util.concurrent.Futures;
2122
import java.io.IOException;
23+
import java.lang.reflect.InvocationTargetException;
2224
import java.util.ArrayList;
2325
import java.util.Collection;
2426
import java.util.Collections;
2527
import java.util.List;
26-
import java.util.Map;
27-
import java.util.Set;
28-
import java.util.concurrent.Future;
2928
import java.util.concurrent.TimeUnit;
3029
import java.util.regex.Pattern;
30+
import net.bytebuddy.ByteBuddy;
31+
import net.bytebuddy.implementation.InvocationHandlerAdapter;
32+
import net.bytebuddy.matcher.ElementMatchers;
3133
import org.apache.hadoop.hbase.ClusterStatus;
32-
import org.apache.hadoop.hbase.ProcedureInfo;
3334
import org.apache.hadoop.hbase.ServerName;
3435
import org.apache.hadoop.hbase.TableExistsException;
3536
import org.apache.hadoop.hbase.TableName;
3637
import org.apache.hadoop.hbase.client.AbstractBigtableAdmin;
38+
import org.apache.hadoop.hbase.client.Admin;
3739
import org.apache.hadoop.hbase.client.CommonConnection;
38-
import org.apache.hadoop.hbase.client.LogEntry;
39-
import org.apache.hadoop.hbase.client.ServerType;
40-
import org.apache.hadoop.hbase.client.security.SecurityCapability;
41-
import org.apache.hadoop.hbase.protobuf.generated.AdminProtos;
4240
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
43-
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
4441
import org.apache.hadoop.hbase.protobuf.generated.MasterProtos;
45-
import org.apache.hadoop.hbase.quotas.QuotaFilter;
46-
import org.apache.hadoop.hbase.quotas.QuotaRetriever;
47-
import org.apache.hadoop.hbase.quotas.QuotaSettings;
48-
import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
4942
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
5043
import org.apache.hadoop.hbase.snapshot.SnapshotCreationException;
51-
import org.apache.hadoop.hbase.snapshot.UnknownSnapshotException;
5244

5345
/**
5446
* This is an hbase 1.x implementation of {@link AbstractBigtableAdmin}. Most methods in this class
@@ -58,7 +50,7 @@
5850
*/
5951
@InternalApi("For internal usage only")
6052
@SuppressWarnings("deprecation")
61-
public class BigtableAdmin extends AbstractBigtableAdmin {
53+
public abstract class BigtableAdmin extends AbstractBigtableAdmin {
6254

6355
public BigtableAdmin(CommonConnection connection) throws IOException {
6456
super(connection);
@@ -83,32 +75,12 @@ public void disableTableAsync(TableName tableName) throws IOException {
8375
disableTable(tableName);
8476
}
8577

86-
@Override
87-
public Map<ServerName, Boolean> compactionSwitch(boolean b, List<String> list)
88-
throws IOException {
89-
throw new UnsupportedOperationException("not implemented");
90-
}
91-
9278
/** {@inheritDoc} */
9379
@Override
9480
public void enableTableAsync(TableName tableName) throws IOException {
9581
enableTable(tableName);
9682
}
9783

98-
/** {@inheritDoc} */
99-
@Override
100-
public AdminProtos.GetRegionInfoResponse.CompactionState getCompactionState(TableName tableName)
101-
throws IOException {
102-
throw new UnsupportedOperationException("getCompactionState");
103-
}
104-
105-
/** {@inheritDoc} */
106-
@Override
107-
public AdminProtos.GetRegionInfoResponse.CompactionState getCompactionStateForRegion(byte[] bytes)
108-
throws IOException {
109-
throw new UnsupportedOperationException("getCompactionStateForRegion");
110-
}
111-
11284
/**
11385
* {@inheritDoc}
11486
*
@@ -123,33 +95,13 @@ public void snapshot(
12395
snapshot(snapshotId, tableName);
12496
}
12597

126-
@Override
127-
public void snapshot(
128-
String s, TableName tableName, SnapshotDescription.Type type, Map<String, Object> map)
129-
throws IOException, SnapshotCreationException, IllegalArgumentException {
130-
throw new UnsupportedOperationException("not implemented");
131-
}
132-
13398
/** {@inheritDoc} */
13499
@Override
135100
public void snapshot(HBaseProtos.SnapshotDescription snapshot)
136101
throws IOException, SnapshotCreationException, IllegalArgumentException {
137102
snapshot(snapshot.getName(), TableName.valueOf(snapshot.getTable()));
138103
}
139104

140-
/** {@inheritDoc} */
141-
@Override
142-
public boolean isSnapshotFinished(HBaseProtos.SnapshotDescription snapshot)
143-
throws IOException, HBaseSnapshotException, UnknownSnapshotException {
144-
throw new UnsupportedOperationException("isSnapshotFinished"); // TODO
145-
}
146-
147-
@Override
148-
public void restoreSnapshot(String s, boolean b, boolean b1)
149-
throws IOException, RestoreSnapshotException {
150-
throw new UnsupportedOperationException("restoreSnapshot"); // TODO
151-
}
152-
153105
@Override
154106
public void cloneSnapshot(String s, TableName tableName, boolean b)
155107
throws IOException, TableExistsException, RestoreSnapshotException {
@@ -196,152 +148,6 @@ public List<HBaseProtos.SnapshotDescription> listSnapshots(Pattern pattern) thro
196148
return response;
197149
}
198150

199-
@Override
200-
public List<SnapshotDescription> listTableSnapshots(
201-
String tableNameRegex, String snapshotNameRegex) throws IOException {
202-
throw new UnsupportedOperationException("Unsupported - please use listSnapshots");
203-
}
204-
205-
@Override
206-
public List<SnapshotDescription> listTableSnapshots(
207-
Pattern tableNamePattern, Pattern snapshotNamePattern) throws IOException {
208-
throw new UnsupportedOperationException("Unsupported - please use listSnapshots");
209-
}
210-
211-
@Override
212-
public boolean isBalancerEnabled() throws IOException {
213-
throw new UnsupportedOperationException("isBalancerEnabled"); // TODO
214-
}
215-
216-
@Override
217-
public long getLastMajorCompactionTimestamp(TableName tableName) throws IOException {
218-
throw new UnsupportedOperationException("getLastMajorCompactionTimestamp"); // TODO
219-
}
220-
221-
@Override
222-
public long getLastMajorCompactionTimestampForRegion(byte[] regionName) throws IOException {
223-
throw new UnsupportedOperationException("getLastMajorCompactionTimestampForRegion"); // TODO
224-
}
225-
226-
@Override
227-
public void setQuota(QuotaSettings quota) throws IOException {
228-
throw new UnsupportedOperationException("setQuota"); // TODO
229-
}
230-
231-
@Override
232-
public QuotaRetriever getQuotaRetriever(QuotaFilter filter) throws IOException {
233-
throw new UnsupportedOperationException("getQuotaRetriever"); // TODO
234-
}
235-
236-
@Override
237-
public ServerName getMaster() throws IOException {
238-
throw new UnsupportedOperationException("not implemented");
239-
}
240-
241-
@Override
242-
public boolean normalize() throws IOException {
243-
throw new UnsupportedOperationException("normalize"); // TODO
244-
}
245-
246-
@Override
247-
public boolean isNormalizerEnabled() throws IOException {
248-
throw new UnsupportedOperationException("isNormalizerEnabled"); // TODO
249-
}
250-
251-
@Override
252-
public boolean setNormalizerRunning(boolean on) throws IOException {
253-
throw new UnsupportedOperationException("setNormalizerRunning"); // TODO
254-
}
255-
256-
@Override
257-
public boolean setCleanerChoreRunning(boolean b) throws IOException {
258-
throw new UnsupportedOperationException("setCleanerChoreRunning"); // TODO
259-
}
260-
261-
@Override
262-
public boolean runCleanerChore() throws IOException {
263-
throw new UnsupportedOperationException("runCleanerChore"); // TODO
264-
}
265-
266-
@Override
267-
public boolean isCleanerChoreEnabled() throws IOException {
268-
throw new UnsupportedOperationException("isCleanerChoreEnabled"); // TODO
269-
}
270-
271-
@Override
272-
public boolean isMasterInMaintenanceMode() throws IOException {
273-
throw new UnsupportedOperationException("isMasterInMaintenanceMode"); // TODO
274-
}
275-
276-
@Override
277-
public boolean abortProcedure(long procId, boolean mayInterruptIfRunning) throws IOException {
278-
throw new UnsupportedOperationException("abortProcedure"); // TODO
279-
}
280-
281-
@Override
282-
public ProcedureInfo[] listProcedures() throws IOException {
283-
throw new UnsupportedOperationException("listProcedures"); // TODO
284-
}
285-
286-
@Override
287-
public Future<Boolean> abortProcedureAsync(long procId, boolean mayInterruptIfRunning)
288-
throws IOException {
289-
throw new UnsupportedOperationException("abortProcedureAsync"); // TODO
290-
}
291-
292-
@Override
293-
public List<SecurityCapability> getSecurityCapabilities() throws IOException {
294-
throw new UnsupportedOperationException("getSecurityCapabilities"); // TODO
295-
}
296-
297-
@Override
298-
public boolean balancer(boolean arg0) throws IOException {
299-
throw new UnsupportedOperationException("balancer"); // TODO
300-
}
301-
302-
@Override
303-
public boolean isSplitOrMergeEnabled(MasterSwitchType arg0) throws IOException {
304-
throw new UnsupportedOperationException("isSplitOrMergeEnabled"); // TODO
305-
}
306-
307-
@Override
308-
public List<ServerName> listDeadServers() throws IOException {
309-
throw new UnsupportedOperationException("listDeadServers"); // TODO
310-
}
311-
312-
@Override
313-
public List<ServerName> clearDeadServers(List<ServerName> list) throws IOException {
314-
throw new UnsupportedOperationException("clearDeadServers"); // TODO
315-
}
316-
317-
@Override
318-
public boolean snapshotCleanupSwitch(boolean b, boolean b1) throws IOException {
319-
throw new UnsupportedOperationException("not implemented");
320-
}
321-
322-
@Override
323-
public boolean isSnapshotCleanupEnabled() throws IOException {
324-
throw new UnsupportedOperationException("not implemented");
325-
}
326-
327-
@Override
328-
public List<Boolean> clearSlowLogResponses(Set<ServerName> set) throws IOException {
329-
throw new UnsupportedOperationException("not implemented");
330-
}
331-
332-
@Override
333-
public List<LogEntry> getLogEntries(
334-
Set<ServerName> set, String s, ServerType serverType, int i, Map<String, Object> map)
335-
throws IOException {
336-
throw new UnsupportedOperationException("not implemented");
337-
}
338-
339-
@Override
340-
public boolean[] setSplitOrMergeEnabled(boolean arg0, boolean arg1, MasterSwitchType... arg2)
341-
throws IOException {
342-
throw new UnsupportedOperationException("setSplitOrMergeEnabled"); // TODO
343-
}
344-
345151
@Override
346152
public ClusterStatus getClusterStatus() throws IOException {
347153
return new ClusterStatus() {
@@ -352,8 +158,43 @@ public Collection<ServerName> getServers() {
352158
};
353159
}
354160

355-
@Override
356-
public String[] listNamespaces() throws IOException {
357-
throw new UnsupportedOperationException("not implemented");
161+
private static Class<? extends BigtableAdmin> adminClass = null;
162+
163+
/**
164+
* This is a workaround for incompatible changes in hbase minor versions. Dynamically generates a
165+
* class that extends BigtableAdmin so incompatible methods won't be accessed unless the methods
166+
* are called. If a method is implemented by BigtableAdmin, the generated class will invoke the
167+
* implementation in BigtableAdmin. Otherwise it'll throw {@link UnsupportedOperationException}.
168+
*/
169+
private static synchronized Class<? extends BigtableAdmin> getSubclass() {
170+
if (adminClass == null) {
171+
adminClass =
172+
new ByteBuddy()
173+
.subclass(BigtableAdmin.class)
174+
.method(ElementMatchers.isAbstract())
175+
.intercept(
176+
InvocationHandlerAdapter.of(
177+
new AbstractBigtableAdmin.UnsupportedOperationsHandler()))
178+
.make()
179+
.load(BigtableAdmin.class.getClassLoader())
180+
.getLoaded();
181+
}
182+
return adminClass;
183+
}
184+
185+
public static Admin createInstance(CommonConnection connection) throws IOException {
186+
try {
187+
return getSubclass().getDeclaredConstructor(CommonConnection.class).newInstance(connection);
188+
} catch (InvocationTargetException e) {
189+
// Unwrap and throw IOException or RuntimeException as is, and convert all other exceptions to
190+
// IOException because
191+
// org.apache.hadoop.hbase.client.Connection#getAdmin() only throws
192+
// IOException
193+
Throwables.throwIfInstanceOf(e.getTargetException(), IOException.class);
194+
Throwables.throwIfInstanceOf(e.getTargetException(), RuntimeException.class);
195+
throw new IOException(e);
196+
} catch (Exception e) {
197+
throw new IOException(e);
198+
}
358199
}
359200
}

bigtable-hbase-1.x-parent/bigtable-hbase-1.x/src/main/java/com/google/cloud/bigtable/hbase1_x/BigtableConnection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public BigtableConnection(Configuration conf) throws IOException {
5858
/** {@inheritDoc} */
5959
@Override
6060
public Admin getAdmin() throws IOException {
61-
return new BigtableAdmin(this);
61+
return BigtableAdmin.createInstance(this);
6262
}
6363

6464
@Override

0 commit comments

Comments
 (0)