1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.replication;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.TreeMap;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.hbase.HBaseConfiguration;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.hbase.Abortable;
37 import org.apache.hadoop.hbase.CompoundConfiguration;
38 import org.apache.hadoop.hbase.TableName;
39 import org.apache.hadoop.hbase.exceptions.DeserializationException;
40 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
41 import org.apache.hadoop.hbase.replication.ReplicationPeer.PeerState;
42 import org.apache.hadoop.hbase.util.Pair;
43 import org.apache.hadoop.hbase.zookeeper.ZKConfig;
44 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
45 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
46 import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp;
47 import org.apache.zookeeper.KeeperException;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 @InterfaceAudience.Private
76 public class ReplicationPeersZKImpl extends ReplicationStateZKBase implements ReplicationPeers {
77
78
79 private Map<String, ReplicationPeerZKImpl> peerClusters;
80 private final ReplicationQueuesClient queuesClient;
81
82 private static final Log LOG = LogFactory.getLog(ReplicationPeersZKImpl.class);
83
84 public ReplicationPeersZKImpl(final ZooKeeperWatcher zk, final Configuration conf,
85 final ReplicationQueuesClient queuesClient, Abortable abortable) {
86 super(zk, conf, abortable);
87 this.peerClusters = new ConcurrentHashMap<String, ReplicationPeerZKImpl>();
88 this.queuesClient = queuesClient;
89 }
90
91 @Override
92 public void init() throws ReplicationException {
93 try {
94 if (ZKUtil.checkExists(this.zookeeper, this.peersZNode) < 0) {
95 ZKUtil.createWithParents(this.zookeeper, this.peersZNode);
96 }
97 } catch (KeeperException e) {
98 throw new ReplicationException("Could not initialize replication peers", e);
99 }
100 addExistingPeers();
101 }
102
103 @Override
104 public void addPeer(String id, ReplicationPeerConfig peerConfig)
105 throws ReplicationException {
106 try {
107 if (peerExists(id)) {
108 throw new IllegalArgumentException("Cannot add a peer with id=" + id
109 + " because that id already exists.");
110 }
111
112 if(id.contains("-") || id.equals(ReplicationQueuesZKImpl.RS_LOCK_ZNODE)) {
113 throw new IllegalArgumentException("Found invalid peer name:" + id);
114 }
115
116 if (peerConfig.getClusterKey() != null) {
117 try {
118 ZKConfig.validateClusterKey(peerConfig.getClusterKey());
119 } catch (IOException ioe) {
120 throw new IllegalArgumentException(ioe.getMessage());
121 }
122 }
123
124 checkQueuesDeleted(id);
125
126 ZKUtil.createWithParents(this.zookeeper, this.peersZNode);
127
128 List<ZKUtilOp> listOfOps = new ArrayList<ZKUtil.ZKUtilOp>();
129 ZKUtilOp op1 = ZKUtilOp.createAndFailSilent(getPeerNode(id),
130 ReplicationSerDeHelper.toByteArray(peerConfig));
131
132
133
134
135 ZKUtilOp op2 = ZKUtilOp.createAndFailSilent(getPeerStateNode(id), ENABLED_ZNODE_BYTES);
136 listOfOps.add(op1);
137 listOfOps.add(op2);
138 ZKUtil.multiOrSequential(this.zookeeper, listOfOps, false);
139
140 } catch (KeeperException e) {
141 throw new ReplicationException("Could not add peer with id=" + id
142 + ", peerConfif=>" + peerConfig, e);
143 }
144 }
145
146 @Override
147 public void removePeer(String id) throws ReplicationException {
148 try {
149 if (!peerExists(id)) {
150 throw new IllegalArgumentException("Cannot remove peer with id=" + id
151 + " because that id does not exist.");
152 }
153 ZKUtil.deleteNodeRecursively(this.zookeeper, ZKUtil.joinZNode(this.peersZNode, id));
154 } catch (KeeperException e) {
155 throw new ReplicationException("Could not remove peer with id=" + id, e);
156 }
157 }
158
159 @Override
160 public void enablePeer(String id) throws ReplicationException {
161 changePeerState(id, ZooKeeperProtos.ReplicationState.State.ENABLED);
162 LOG.info("peer " + id + " is enabled");
163 }
164
165 @Override
166 public void disablePeer(String id) throws ReplicationException {
167 changePeerState(id, ZooKeeperProtos.ReplicationState.State.DISABLED);
168 LOG.info("peer " + id + " is disabled");
169 }
170
171 @Override
172 public Map<TableName, List<String>> getPeerTableCFsConfig(String id) throws ReplicationException {
173 try {
174 if (!peerExists(id)) {
175 throw new IllegalArgumentException("peer " + id + " doesn't exist");
176 }
177 try {
178 ReplicationPeerConfig rpc = getReplicationPeerConfig(id);
179 if (rpc == null) {
180 throw new ReplicationException("Unable to get tableCFs of the peer with id=" + id);
181 }
182 return rpc.getTableCFsMap();
183 } catch (Exception e) {
184 throw new ReplicationException(e);
185 }
186 } catch (KeeperException e) {
187 throw new ReplicationException("Unable to get tableCFs of the peer with id=" + id, e);
188 }
189 }
190
191 @Override
192 public void setPeerTableCFsConfig(String id,
193 Map<TableName, ? extends Collection<String>> tableCFs) throws ReplicationException {
194 try {
195 if (!peerExists(id)) {
196 throw new IllegalArgumentException("Cannot set peer tableCFs because id=" + id
197 + " does not exist.");
198 }
199 ReplicationPeerConfig rpc = getReplicationPeerConfig(id);
200 if (rpc == null) {
201 throw new ReplicationException("Unable to get tableCFs of the peer with id=" + id);
202 }
203 rpc.setTableCFsMap(tableCFs);
204 ZKUtil.setData(this.zookeeper, getPeerNode(id),
205 ReplicationSerDeHelper.toByteArray(rpc));
206 LOG.info("Peer tableCFs with id= " + id + " is now "
207 + ReplicationSerDeHelper.convertToString(tableCFs));
208 } catch (KeeperException e) {
209 throw new ReplicationException("Unable to change tableCFs of the peer with id=" + id, e);
210 }
211 }
212
213 @Override
214 public Map<TableName, List<String>> getTableCFs(String id) throws IllegalArgumentException {
215 ReplicationPeer replicationPeer = this.peerClusters.get(id);
216 if (replicationPeer == null) {
217 throw new IllegalArgumentException("Peer with id= " + id + " is not connected");
218 }
219 return replicationPeer.getTableCFs();
220 }
221
222 @Override
223 public boolean getStatusOfPeer(String id) {
224 ReplicationPeer replicationPeer = this.peerClusters.get(id);
225 if (replicationPeer == null) {
226 throw new IllegalArgumentException("Peer with id= " + id + " is not connected");
227 }
228 return replicationPeer.getPeerState() == PeerState.ENABLED;
229 }
230
231 @Override
232 public boolean getStatusOfPeerFromBackingStore(String id) throws ReplicationException {
233 try {
234 if (!peerExists(id)) {
235 throw new IllegalArgumentException("peer " + id + " doesn't exist");
236 }
237 String peerStateZNode = getPeerStateNode(id);
238 try {
239 return ReplicationPeerZKImpl.isStateEnabled(ZKUtil.getData(this.zookeeper, peerStateZNode));
240 } catch (KeeperException e) {
241 throw new ReplicationException(e);
242 } catch (DeserializationException e) {
243 throw new ReplicationException(e);
244 }
245 } catch (KeeperException e) {
246 throw new ReplicationException("Unable to get status of the peer with id=" + id +
247 " from backing store", e);
248 } catch (InterruptedException e) {
249 throw new ReplicationException(e);
250 }
251 }
252
253 @Override
254 public Map<String, ReplicationPeerConfig> getAllPeerConfigs() {
255 Map<String, ReplicationPeerConfig> peers = new TreeMap<String, ReplicationPeerConfig>();
256 List<String> ids = null;
257 try {
258 ids = ZKUtil.listChildrenNoWatch(this.zookeeper, this.peersZNode);
259 for (String id : ids) {
260 ReplicationPeerConfig peerConfig = getReplicationPeerConfig(id);
261 if (peerConfig == null) {
262 LOG.warn("Failed to get replication peer configuration of clusterid=" + id
263 + " znode content, continuing.");
264 continue;
265 }
266 peers.put(id, peerConfig);
267 }
268 } catch (KeeperException e) {
269 this.abortable.abort("Cannot get the list of peers ", e);
270 } catch (ReplicationException e) {
271 this.abortable.abort("Cannot get the list of peers ", e);
272 }
273 return peers;
274 }
275
276 @Override
277 public ReplicationPeer getPeer(String peerId) {
278 return peerClusters.get(peerId);
279 }
280
281 @Override
282 public Set<String> getPeerIds() {
283 return peerClusters.keySet();
284 }
285
286
287
288
289 @Override
290 public ReplicationPeerConfig getReplicationPeerConfig(String peerId)
291 throws ReplicationException {
292 String znode = getPeerNode(peerId);
293 byte[] data = null;
294 try {
295 data = ZKUtil.getData(this.zookeeper, znode);
296 } catch (InterruptedException e) {
297 LOG.warn("Could not get configuration for peer because the thread " +
298 "was interrupted. peerId=" + peerId);
299 Thread.currentThread().interrupt();
300 return null;
301 } catch (KeeperException e) {
302 throw new ReplicationException("Error getting configuration for peer with id="
303 + peerId, e);
304 }
305 if (data == null) {
306 LOG.error("Could not get configuration for peer because it doesn't exist. peerId=" + peerId);
307 return null;
308 }
309
310 try {
311 return ReplicationSerDeHelper.parsePeerFrom(data);
312 } catch (DeserializationException e) {
313 LOG.warn("Failed to parse cluster key from peerId=" + peerId
314 + ", specifically the content from the following znode: " + znode);
315 return null;
316 }
317 }
318
319 @Override
320 public Pair<ReplicationPeerConfig, Configuration> getPeerConf(String peerId)
321 throws ReplicationException {
322 ReplicationPeerConfig peerConfig = getReplicationPeerConfig(peerId);
323
324 if (peerConfig == null) {
325 return null;
326 }
327
328 Configuration otherConf;
329 try {
330 otherConf = HBaseConfiguration.createClusterConf(this.conf, peerConfig.getClusterKey());
331 } catch (IOException e) {
332 LOG.error("Can't get peer configuration for peerId=" + peerId + " because:", e);
333 return null;
334 }
335
336 if (!peerConfig.getConfiguration().isEmpty()) {
337 CompoundConfiguration compound = new CompoundConfiguration();
338 compound.add(otherConf);
339 compound.addStringMap(peerConfig.getConfiguration());
340 return new Pair<ReplicationPeerConfig, Configuration>(peerConfig, compound);
341 }
342
343 return new Pair<ReplicationPeerConfig, Configuration>(peerConfig, otherConf);
344 }
345
346 @Override
347 public void updatePeerConfig(String id, ReplicationPeerConfig newConfig)
348 throws ReplicationException {
349 ReplicationPeer peer = getPeer(id);
350 if (peer == null){
351 throw new ReplicationException("Could not find peer Id " + id);
352 }
353 ReplicationPeerConfig existingConfig = peer.getPeerConfig();
354 if (newConfig.getClusterKey() != null && !newConfig.getClusterKey().isEmpty() &&
355 !newConfig.getClusterKey().equals(existingConfig.getClusterKey())){
356 throw new ReplicationException("Changing the cluster key on an existing peer is not allowed."
357 + " Existing key '" + existingConfig.getClusterKey() + "' does not match new key '"
358 + newConfig.getClusterKey() +
359 "'");
360 }
361 String existingEndpointImpl = existingConfig.getReplicationEndpointImpl();
362 if (newConfig.getReplicationEndpointImpl() != null &&
363 !newConfig.getReplicationEndpointImpl().isEmpty() &&
364 !newConfig.getReplicationEndpointImpl().equals(existingEndpointImpl)){
365 throw new ReplicationException("Changing the replication endpoint implementation class " +
366 "on an existing peer is not allowed. Existing class '"
367 + existingConfig.getReplicationEndpointImpl()
368 + "' does not match new class '" + newConfig.getReplicationEndpointImpl() + "'");
369 }
370
371
372 existingConfig.getConfiguration().putAll(newConfig.getConfiguration());
373 existingConfig.getPeerData().putAll(newConfig.getPeerData());
374 existingConfig.setTableCFsMap(newConfig.getTableCFsMap());
375 existingConfig.setBandwidth(newConfig.getBandwidth());
376 try {
377 ZKUtil.setData(this.zookeeper, getPeerNode(id),
378 ReplicationSerDeHelper.toByteArray(existingConfig));
379 }
380 catch(KeeperException ke){
381 throw new ReplicationException("There was a problem trying to save changes to the " +
382 "replication peer " + id, ke);
383 }
384 }
385
386
387
388 @Override
389 public List<String> getAllPeerIds() {
390 List<String> ids = null;
391 try {
392 ids = ZKUtil.listChildrenAndWatchThem(this.zookeeper, this.peersZNode);
393 } catch (KeeperException e) {
394 this.abortable.abort("Cannot get the list of peers ", e);
395 }
396 return ids;
397 }
398
399
400
401
402
403 private void addExistingPeers() throws ReplicationException {
404 List<String> znodes = null;
405 try {
406 znodes = ZKUtil.listChildrenNoWatch(this.zookeeper, this.peersZNode);
407 } catch (KeeperException e) {
408 throw new ReplicationException("Error getting the list of peer clusters.", e);
409 }
410 if (znodes != null) {
411 for (String z : znodes) {
412 createAndAddPeer(z);
413 }
414 }
415 }
416
417 @Override
418 public boolean peerAdded(String peerId) throws ReplicationException {
419 return createAndAddPeer(peerId);
420 }
421
422 @Override
423 public void peerRemoved(String peerId) {
424 ReplicationPeer rp = this.peerClusters.get(peerId);
425 if (rp != null) {
426 ((ConcurrentMap<String, ReplicationPeerZKImpl>) peerClusters).remove(peerId, rp);
427 }
428 }
429
430
431
432
433
434
435 public boolean createAndAddPeer(String peerId) throws ReplicationException {
436 if (peerClusters == null) {
437 return false;
438 }
439 if (this.peerClusters.containsKey(peerId)) {
440 return false;
441 }
442
443 ReplicationPeerZKImpl peer = null;
444 try {
445 peer = createPeer(peerId);
446 } catch (Exception e) {
447 throw new ReplicationException("Error adding peer with id=" + peerId, e);
448 }
449 if (peer == null) {
450 return false;
451 }
452 ReplicationPeerZKImpl previous =
453 ((ConcurrentMap<String, ReplicationPeerZKImpl>) peerClusters).putIfAbsent(peerId, peer);
454 if (previous == null) {
455 LOG.info("Added new peer cluster=" + peer.getPeerConfig().getClusterKey());
456 } else {
457 LOG.info("Peer already present, " + previous.getPeerConfig().getClusterKey() +
458 ", new cluster=" + peer.getPeerConfig().getClusterKey());
459 }
460 return true;
461 }
462
463
464
465
466
467
468 private void changePeerState(String id, ZooKeeperProtos.ReplicationState.State state)
469 throws ReplicationException {
470 try {
471 if (!peerExists(id)) {
472 throw new IllegalArgumentException("Cannot enable/disable peer because id=" + id
473 + " does not exist.");
474 }
475 String peerStateZNode = getPeerStateNode(id);
476 byte[] stateBytes =
477 (state == ZooKeeperProtos.ReplicationState.State.ENABLED) ? ENABLED_ZNODE_BYTES
478 : DISABLED_ZNODE_BYTES;
479 if (ZKUtil.checkExists(this.zookeeper, peerStateZNode) != -1) {
480 ZKUtil.setData(this.zookeeper, peerStateZNode, stateBytes);
481 } else {
482 ZKUtil.createAndWatch(this.zookeeper, peerStateZNode, stateBytes);
483 }
484 LOG.info("Peer with id= " + id + " is now " + state.name());
485 } catch (KeeperException e) {
486 throw new ReplicationException("Unable to change state of the peer with id=" + id, e);
487 }
488 }
489
490
491
492
493
494
495
496 private ReplicationPeerZKImpl createPeer(String peerId) throws ReplicationException {
497 Pair<ReplicationPeerConfig, Configuration> pair = getPeerConf(peerId);
498 if (pair == null) {
499 return null;
500 }
501 Configuration peerConf = pair.getSecond();
502
503 ReplicationPeerZKImpl peer = new ReplicationPeerZKImpl(zookeeper, peerConf, peerId,
504 pair.getFirst(), abortable);
505 try {
506 peer.startStateTracker(getPeerStateNode(peerId));
507 } catch (KeeperException e) {
508 throw new ReplicationException("Error starting the peer state tracker for peerId=" +
509 peerId, e);
510 }
511
512 try {
513 peer.startPeerConfigTracker(this.zookeeper, this.getPeerNode(peerId));
514 }
515 catch(KeeperException e) {
516 throw new ReplicationException("Error starting the peer config tracker for peerId=" +
517 peerId, e);
518 }
519
520 return peer;
521 }
522
523 private void checkQueuesDeleted(String peerId) throws ReplicationException {
524 if (queuesClient == null) return;
525 try {
526 List<String> replicators = queuesClient.getListOfReplicators();
527 if (replicators == null || replicators.isEmpty()) {
528 return;
529 }
530 for (String replicator : replicators) {
531 List<String> queueIds = queuesClient.getAllQueues(replicator);
532 for (String queueId : queueIds) {
533 ReplicationQueueInfo queueInfo = new ReplicationQueueInfo(queueId);
534 if (queueInfo.getPeerId().equals(peerId)) {
535 throw new ReplicationException("undeleted queue for peerId: " + peerId
536 + ", replicator: " + replicator + ", queueId: " + queueId);
537 }
538 }
539 }
540
541 if (-1 != ZKUtil.checkExists(zookeeper, hfileRefsZNode)
542 && queuesClient.getAllPeersFromHFileRefsQueue().contains(peerId)) {
543 throw new ReplicationException("Undeleted queue for peerId: " + peerId
544 + ", found in hfile-refs node path " + hfileRefsZNode);
545 }
546 } catch (KeeperException e) {
547 throw new ReplicationException("Could not check queues deleted with id=" + peerId, e);
548 }
549 }
550 }