1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.client.example;
21
22 import java.io.Closeable;
23 import java.io.IOException;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.conf.Configured;
28 import org.apache.hadoop.hbase.HBaseConfiguration;
29 import org.apache.hadoop.hbase.HConstants;
30 import org.apache.hadoop.hbase.TableName;
31 import org.apache.hadoop.hbase.client.Connection;
32 import org.apache.hadoop.hbase.client.ConnectionFactory;
33 import org.apache.hadoop.hbase.client.Table;
34 import org.apache.hadoop.hbase.client.coprocessor.Batch;
35 import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
36 import org.apache.hadoop.hbase.ipc.ServerRpcController;
37 import org.apache.hadoop.hbase.protobuf.generated.RefreshHFilesProtos;
38 import org.apache.hadoop.util.Tool;
39 import org.apache.hadoop.util.ToolRunner;
40
41
42
43
44
45 public class RefreshHFilesClient extends Configured implements Tool, Closeable {
46 private static final Log LOG = LogFactory.getLog(RefreshHFilesClient.class);
47 private final Connection connection;
48
49
50
51
52
53
54 public RefreshHFilesClient(Configuration cfg) {
55 try {
56 this.connection = ConnectionFactory.createConnection(cfg);
57 } catch (IOException e) {
58 throw new RuntimeException(e);
59 }
60 }
61
62 @Override
63 public void close() throws IOException {
64 if (this.connection != null && !this.connection.isClosed()) {
65 this.connection.close();
66 }
67 }
68
69 public void refreshHFiles(final TableName tableName) throws Throwable {
70 try (Table table = connection.getTable(tableName)) {
71 refreshHFiles(table);
72 }
73 }
74
75 public void refreshHFiles(final Table table) throws Throwable {
76 final RefreshHFilesProtos.RefreshHFilesRequest request = RefreshHFilesProtos.RefreshHFilesRequest
77 .getDefaultInstance();
78 table.coprocessorService(RefreshHFilesProtos.RefreshHFilesService.class, HConstants.EMPTY_START_ROW,
79 HConstants.EMPTY_END_ROW,
80 new Batch.Call<RefreshHFilesProtos.RefreshHFilesService,
81 RefreshHFilesProtos.RefreshHFilesResponse>() {
82 @Override
83 public RefreshHFilesProtos.RefreshHFilesResponse call(
84 RefreshHFilesProtos.RefreshHFilesService refreshHFilesService)
85 throws IOException {
86 ServerRpcController controller = new ServerRpcController();
87 BlockingRpcCallback<RefreshHFilesProtos.RefreshHFilesResponse> rpcCallback =
88 new BlockingRpcCallback<>();
89 refreshHFilesService.refreshHFiles(controller, request, rpcCallback);
90 if (controller.failedOnException()) {
91 throw controller.getFailedOn();
92 }
93 return rpcCallback.get();
94 }
95 });
96 LOG.debug("Done refreshing HFiles");
97 }
98
99 @Override
100 public int run(String[] args) throws Exception {
101 if (args.length != 1) {
102 String message = "When there are multiple HBase clusters sharing a common root directory, "
103 + "especially for read replica cluster (see detail in HBASE-18477), please consider to "
104 + "use this tool manually sync the flushed HFiles from the source cluster.";
105 message += "\nUsage: " + this.getClass().getName() + " tableName";
106 System.out.println(message);
107 return -1;
108 }
109 final TableName tableName = TableName.valueOf(args[0]);
110 try {
111 refreshHFiles(tableName);
112 } catch (Throwable t) {
113 LOG.error("Refresh HFiles from table " + tableName.getNameAsString() + " failed: ", t);
114 return -1;
115 }
116 return 0;
117 }
118
119 public static void main(String[] args) throws Exception {
120 ToolRunner.run(new RefreshHFilesClient(HBaseConfiguration.create()), args);
121 }
122 }