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