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