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.mapreduce.replication;
21
22 import java.io.IOException;
23
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.hbase.HBaseConfiguration;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.KeyValue;
30 import org.apache.hadoop.hbase.client.HConnection;
31 import org.apache.hadoop.hbase.client.HConnectionManager;
32 import org.apache.hadoop.hbase.client.HConnectionManager.HConnectable;
33 import org.apache.hadoop.hbase.client.HTable;
34 import org.apache.hadoop.hbase.client.Put;
35 import org.apache.hadoop.hbase.client.Result;
36 import org.apache.hadoop.hbase.client.ResultScanner;
37 import org.apache.hadoop.hbase.client.Scan;
38 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
39 import org.apache.hadoop.hbase.mapreduce.TableInputFormat;
40 import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
41 import org.apache.hadoop.hbase.mapreduce.TableMapper;
42 import org.apache.hadoop.hbase.replication.ReplicationPeer;
43 import org.apache.hadoop.hbase.replication.ReplicationZookeeper;
44 import org.apache.hadoop.hbase.util.Bytes;
45 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
46 import org.apache.hadoop.mapreduce.Job;
47 import org.apache.hadoop.mapreduce.lib.output.NullOutputFormat;
48 import org.apache.zookeeper.KeeperException;
49
50
51
52
53
54
55
56
57
58
59
60 public class VerifyReplication {
61
62 private static final Log LOG =
63 LogFactory.getLog(VerifyReplication.class);
64
65 public final static String NAME = "verifyrep";
66 static long startTime = 0;
67 static long endTime = 0;
68 static String tableName = null;
69 static String families = null;
70 static String peerId = null;
71
72
73
74
75 public static class Verifier
76 extends TableMapper<ImmutableBytesWritable, Put> {
77
78 public static enum Counters {GOODROWS, BADROWS}
79
80 private ResultScanner replicatedScanner;
81
82
83
84
85
86
87
88
89
90 @Override
91 public void map(ImmutableBytesWritable row, final Result value,
92 Context context)
93 throws IOException {
94 if (replicatedScanner == null) {
95 Configuration conf = context.getConfiguration();
96 final Scan scan = new Scan();
97 scan.setCaching(conf.getInt(TableInputFormat.SCAN_CACHEDROWS, 1));
98 long startTime = conf.getLong(NAME + ".startTime", 0);
99 long endTime = conf.getLong(NAME + ".endTime", 0);
100 String families = conf.get(NAME + ".families", null);
101 if(families != null) {
102 String[] fams = families.split(",");
103 for(String fam : fams) {
104 scan.addFamily(Bytes.toBytes(fam));
105 }
106 }
107 if (startTime != 0) {
108 scan.setTimeRange(startTime,
109 endTime == 0 ? HConstants.LATEST_TIMESTAMP : endTime);
110 }
111 HConnectionManager.execute(new HConnectable<Void>(conf) {
112 @Override
113 public Void connect(HConnection conn) throws IOException {
114 String zkClusterKey = conf.get(NAME + ".peerQuorumAddress");
115 Configuration peerConf = HBaseConfiguration.create(conf);
116 ZKUtil.applyClusterKeyToConf(peerConf, zkClusterKey);
117
118 HTable replicatedTable = new HTable(peerConf, conf.get(NAME + ".tableName"));
119 scan.setStartRow(value.getRow());
120 replicatedScanner = replicatedTable.getScanner(scan);
121 return null;
122 }
123 });
124 }
125 Result res = replicatedScanner.next();
126 try {
127 Result.compareResults(value, res);
128 context.getCounter(Counters.GOODROWS).increment(1);
129 } catch (Exception e) {
130 LOG.warn("Bad row", e);
131 context.getCounter(Counters.BADROWS).increment(1);
132 }
133 }
134
135 protected void cleanup(Context context) {
136 if (replicatedScanner != null) {
137 replicatedScanner.close();
138 replicatedScanner = null;
139 }
140 }
141 }
142
143 private static String getPeerQuorumAddress(final Configuration conf) throws IOException {
144 HConnection conn = HConnectionManager.getConnection(conf);
145 try {
146 ReplicationZookeeper zk = new ReplicationZookeeper(conn, conf,
147 conn.getZooKeeperWatcher());
148
149 ReplicationPeer peer = zk.getPeer(peerId);
150 if (peer == null) {
151 throw new IOException("Couldn't get peer conf!");
152 }
153
154 Configuration peerConf = peer.getConfiguration();
155 return ZKUtil.getZooKeeperClusterKey(peerConf);
156 } catch (KeeperException e) {
157 throw new IOException("Got a ZK exception", e);
158 } finally {
159 conn.close();
160 }
161 }
162
163
164
165
166
167
168
169
170
171 public static Job createSubmittableJob(Configuration conf, String[] args)
172 throws IOException {
173 if (!doCommandLine(args)) {
174 return null;
175 }
176 if (!conf.getBoolean(HConstants.REPLICATION_ENABLE_KEY, false)) {
177 throw new IOException("Replication needs to be enabled to verify it.");
178 }
179 HConnectionManager.execute(new HConnectable<Void>(conf) {
180 @Override
181 public Void connect(HConnection conn) throws IOException {
182 try {
183 ReplicationZookeeper zk = new ReplicationZookeeper(conn, conf,
184 conn.getZooKeeperWatcher());
185
186 ReplicationPeer peer = zk.getPeer(peerId);
187 if (peer == null) {
188 throw new IOException("Couldn't get access to the slave cluster," +
189 "please see the log");
190 }
191 } catch (KeeperException ex) {
192 throw new IOException("Couldn't get access to the slave cluster" +
193 " because: ", ex);
194 }
195 return null;
196 }
197 });
198 conf.set(NAME+".peerId", peerId);
199 conf.set(NAME+".tableName", tableName);
200 conf.setLong(NAME+".startTime", startTime);
201 conf.setLong(NAME+".endTime", endTime);
202 if (families != null) {
203 conf.set(NAME+".families", families);
204 }
205
206 String peerQuorumAddress = getPeerQuorumAddress(conf);
207 conf.set(NAME + ".peerQuorumAddress", peerQuorumAddress);
208 LOG.info("Peer Quorum Address: " + peerQuorumAddress);
209
210 Job job = new Job(conf, NAME + "_" + tableName);
211 job.setJarByClass(VerifyReplication.class);
212
213 Scan scan = new Scan();
214 if (startTime != 0) {
215 scan.setTimeRange(startTime,
216 endTime == 0 ? HConstants.LATEST_TIMESTAMP : endTime);
217 }
218 if(families != null) {
219 String[] fams = families.split(",");
220 for(String fam : fams) {
221 scan.addFamily(Bytes.toBytes(fam));
222 }
223 }
224 TableMapReduceUtil.initTableMapperJob(tableName, scan,
225 Verifier.class, null, null, job);
226
227
228 TableMapReduceUtil.initCredentialsForCluster(job, peerQuorumAddress);
229
230 job.setOutputFormatClass(NullOutputFormat.class);
231 job.setNumReduceTasks(0);
232 return job;
233 }
234
235 private static boolean doCommandLine(final String[] args) {
236 if (args.length < 2) {
237 printUsage(null);
238 return false;
239 }
240 try {
241 for (int i = 0; i < args.length; i++) {
242 String cmd = args[i];
243 if (cmd.equals("-h") || cmd.startsWith("--h")) {
244 printUsage(null);
245 return false;
246 }
247
248 final String startTimeArgKey = "--starttime=";
249 if (cmd.startsWith(startTimeArgKey)) {
250 startTime = Long.parseLong(cmd.substring(startTimeArgKey.length()));
251 continue;
252 }
253
254 final String endTimeArgKey = "--endtime=";
255 if (cmd.startsWith(endTimeArgKey)) {
256 endTime = Long.parseLong(cmd.substring(endTimeArgKey.length()));
257 continue;
258 }
259
260 final String familiesArgKey = "--families=";
261 if (cmd.startsWith(familiesArgKey)) {
262 families = cmd.substring(familiesArgKey.length());
263 continue;
264 }
265
266 if (i == args.length-2) {
267 peerId = cmd;
268 }
269
270 if (i == args.length-1) {
271 tableName = cmd;
272 }
273 }
274 } catch (Exception e) {
275 e.printStackTrace();
276 printUsage("Can't start because " + e.getMessage());
277 return false;
278 }
279 return true;
280 }
281
282
283
284
285 private static void printUsage(final String errorMsg) {
286 if (errorMsg != null && errorMsg.length() > 0) {
287 System.err.println("ERROR: " + errorMsg);
288 }
289 System.err.println("Usage: verifyrep [--starttime=X]" +
290 " [--stoptime=Y] [--families=A] <peerid> <tablename>");
291 System.err.println();
292 System.err.println("Options:");
293 System.err.println(" starttime beginning of the time range");
294 System.err.println(" without endtime means from starttime to forever");
295 System.err.println(" stoptime end of the time range");
296 System.err.println(" families comma-separated list of families to copy");
297 System.err.println();
298 System.err.println("Args:");
299 System.err.println(" peerid Id of the peer used for verification, must match the one given for replication");
300 System.err.println(" tablename Name of the table to verify");
301 System.err.println();
302 System.err.println("Examples:");
303 System.err.println(" To verify the data replicated from TestTable for a 1 hour window with peer #5 ");
304 System.err.println(" $ bin/hbase " +
305 "org.apache.hadoop.hbase.mapreduce.replication.VerifyReplication" +
306 " --starttime=1265875194289 --stoptime=1265878794289 5 TestTable ");
307 }
308
309
310
311
312
313
314
315 public static void main(String[] args) throws Exception {
316 Configuration conf = HBaseConfiguration.create();
317 Job job = createSubmittableJob(conf, args);
318 if (job != null) {
319 System.exit(job.waitForCompletion(true) ? 0 : 1);
320 }
321 }
322 }