View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.replication;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.SortedMap;
24  import java.util.SortedSet;
25  import java.util.TreeMap;
26  import java.util.TreeSet;
27  
28  import com.google.common.annotations.VisibleForTesting;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.Abortable;
34  import org.apache.hadoop.hbase.HConstants;
35  import org.apache.hadoop.hbase.exceptions.DeserializationException;
36  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
37  import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
38  import org.apache.hadoop.hbase.util.Bytes;
39  import org.apache.hadoop.hbase.util.Pair;
40  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
41  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
42  import org.apache.hadoop.hbase.zookeeper.ZKUtil.ZKUtilOp;
43  import org.apache.zookeeper.KeeperException;
44  
45  /**
46   * This class provides an implementation of the ReplicationQueues interface using Zookeeper. The
47   * base znode that this class works at is the myQueuesZnode. The myQueuesZnode contains a list of
48   * all outstanding WAL files on this region server that need to be replicated. The myQueuesZnode is
49   * the regionserver name (a concatenation of the region server’s hostname, client port and start
50   * code). For example:
51   *
52   * /hbase/replication/rs/hostname.example.org,6020,1234
53   *
54   * Within this znode, the region server maintains a set of WAL replication queues. These queues are
55   * represented by child znodes named using there give queue id. For example:
56   *
57   * /hbase/replication/rs/hostname.example.org,6020,1234/1
58   * /hbase/replication/rs/hostname.example.org,6020,1234/2
59   *
60   * Each queue has one child znode for every WAL that still needs to be replicated. The value of
61   * these WAL child znodes is the latest position that has been replicated. This position is updated
62   * every time a WAL entry is replicated. For example:
63   *
64   * /hbase/replication/rs/hostname.example.org,6020,1234/1/23522342.23422 [VALUE: 254]
65   */
66  @InterfaceAudience.Private
67  public class ReplicationQueuesZKImpl extends ReplicationStateZKBase implements ReplicationQueues {
68  
69    /** Znode containing all replication queues for this region server. */
70    private String myQueuesZnode;
71    /** Name of znode we use to lock during failover */
72    public final static String RS_LOCK_ZNODE = "lock";
73  
74    private static final Log LOG = LogFactory.getLog(ReplicationQueuesZKImpl.class);
75  
76    public ReplicationQueuesZKImpl(final ZooKeeperWatcher zk, Configuration conf,
77        Abortable abortable) {
78      super(zk, conf, abortable);
79    }
80  
81    @Override
82    public void init(String serverName) throws ReplicationException {
83      this.myQueuesZnode = ZKUtil.joinZNode(this.queuesZNode, serverName);
84      try {
85        ZKUtil.createWithParents(this.zookeeper, this.myQueuesZnode);
86      } catch (KeeperException e) {
87        throw new ReplicationException("Could not initialize replication queues.", e);
88      }
89      if (conf.getBoolean(HConstants.REPLICATION_BULKLOAD_ENABLE_KEY,
90        HConstants.REPLICATION_BULKLOAD_ENABLE_DEFAULT)) {
91        try {
92          ZKUtil.createWithParents(this.zookeeper, this.hfileRefsZNode);
93        } catch (KeeperException e) {
94          throw new ReplicationException("Could not initialize hfile references replication queue.",
95              e);
96        }
97      }
98    }
99  
100   @Override
101   public void removeQueue(String queueId) {
102     try {
103       ZKUtil.deleteNodeRecursively(this.zookeeper, ZKUtil.joinZNode(this.myQueuesZnode, queueId));
104     } catch (KeeperException e) {
105       this.abortable.abort("Failed to delete queue (queueId=" + queueId + ")", e);
106     }
107   }
108 
109   @Override
110   public void addLog(String queueId, String filename) throws ReplicationException {
111     String znode = ZKUtil.joinZNode(this.myQueuesZnode, queueId);
112     znode = ZKUtil.joinZNode(znode, filename);
113     try {
114       ZKUtil.createWithParents(this.zookeeper, znode);
115     } catch (KeeperException e) {
116       throw new ReplicationException(
117           "Could not add log because znode could not be created. queueId=" + queueId
118               + ", filename=" + filename);
119     }
120   }
121 
122   @Override
123   public void removeLog(String queueId, String filename) {
124     try {
125       String znode = ZKUtil.joinZNode(this.myQueuesZnode, queueId);
126       znode = ZKUtil.joinZNode(znode, filename);
127       ZKUtil.deleteNode(this.zookeeper, znode);
128     } catch (KeeperException e) {
129       this.abortable.abort("Failed to remove wal from queue (queueId=" + queueId + ", filename="
130           + filename + ")", e);
131     }
132   }
133 
134   @Override
135   public void setLogPosition(String queueId, String filename, long position) {
136     try {
137       String znode = ZKUtil.joinZNode(this.myQueuesZnode, queueId);
138       znode = ZKUtil.joinZNode(znode, filename);
139       // Why serialize String of Long and not Long as bytes?
140       ZKUtil.setData(this.zookeeper, znode, ZKUtil.positionToByteArray(position));
141     } catch (KeeperException e) {
142       this.abortable.abort("Failed to write replication wal position (filename=" + filename
143           + ", position=" + position + ")", e);
144     }
145   }
146 
147   @Override
148   public long getLogPosition(String queueId, String filename) throws ReplicationException {
149     String clusterZnode = ZKUtil.joinZNode(this.myQueuesZnode, queueId);
150     String znode = ZKUtil.joinZNode(clusterZnode, filename);
151     byte[] bytes = null;
152     try {
153       bytes = ZKUtil.getData(this.zookeeper, znode);
154     } catch (KeeperException e) {
155       throw new ReplicationException("Internal Error: could not get position in log for queueId="
156           + queueId + ", filename=" + filename, e);
157     } catch (InterruptedException e) {
158       Thread.currentThread().interrupt();
159       return 0;
160     }
161     try {
162       return ZKUtil.parseWALPositionFrom(bytes);
163     } catch (DeserializationException de) {
164       LOG.warn("Failed to parse WALPosition for queueId=" + queueId + " and wal=" + filename
165           + " znode content, continuing.");
166     }
167     // if we can not parse the position, start at the beginning of the wal file
168     // again
169     return 0;
170   }
171 
172   @Override
173   public boolean isThisOurZnode(String znode) {
174     return ZKUtil.joinZNode(this.queuesZNode, znode).equals(this.myQueuesZnode);
175   }
176 
177   @Override
178   public void removeAllQueues() {
179     try {
180       ZKUtil.deleteNodeRecursively(this.zookeeper, this.myQueuesZnode);
181     } catch (KeeperException e) {
182       // if the znode is already expired, don't bother going further
183       if (e instanceof KeeperException.SessionExpiredException) {
184         return;
185       }
186       this.abortable.abort("Failed to delete replication queues for region server: "
187           + this.myQueuesZnode, e);
188     }
189   }
190 
191   @Override
192   public List<String> getLogsInQueue(String queueId) {
193     String znode = ZKUtil.joinZNode(this.myQueuesZnode, queueId);
194     List<String> result = null;
195     try {
196       result = ZKUtil.listChildrenNoWatch(this.zookeeper, znode);
197     } catch (KeeperException e) {
198       this.abortable.abort("Failed to get list of wals for queueId=" + queueId, e);
199     }
200     return result;
201   }
202 
203   @Override
204   public List<String> getAllQueues() {
205     List<String> listOfQueues = null;
206     try {
207       listOfQueues = ZKUtil.listChildrenNoWatch(this.zookeeper, this.myQueuesZnode);
208     } catch (KeeperException e) {
209       this.abortable.abort("Failed to get a list of queues for region server: "
210           + this.myQueuesZnode, e);
211     }
212     return listOfQueues;
213   }
214 
215   @Override
216   public boolean isThisOurRegionServer(String regionserver) {
217     return ZKUtil.joinZNode(this.queuesZNode, regionserver).equals(this.myQueuesZnode);
218   }
219 
220   @Override
221   public List<String> getUnClaimedQueueIds(String regionserver) {
222     if (isThisOurRegionServer(regionserver)) {
223       return null;
224     }
225     String rsZnodePath = ZKUtil.joinZNode(this.queuesZNode, regionserver);
226     List<String> queues = null;
227     try {
228       queues = ZKUtil.listChildrenNoWatch(this.zookeeper, rsZnodePath);
229     } catch (KeeperException e) {
230       this.abortable.abort("Failed to getUnClaimedQueueIds for " + regionserver, e);
231     }
232     if (queues != null) {
233       queues.remove(RS_LOCK_ZNODE);
234     }
235     return queues;
236   }
237 
238   @Override
239   public Pair<String, SortedSet<String>> claimQueue(String regionserver, String queueId) {
240     if (conf.getBoolean(HConstants.ZOOKEEPER_USEMULTI, true)) {
241       LOG.info("Atomically moving " + regionserver + "/" + queueId + "'s WALs to my queue");
242       return moveQueueUsingMulti(regionserver, queueId);
243     } else {
244       LOG.info("Moving " + regionserver + "/" + queueId + "'s wals to my queue");
245       if (!lockOtherRS(regionserver)) {
246         LOG.info("Can not take the lock now");
247         return null;
248       }
249       Pair<String, SortedSet<String>> newQueues;
250       try {
251         newQueues = copyQueueFromLockedRS(regionserver, queueId);
252         removeQueueFromLockedRS(regionserver, queueId);
253       } finally {
254         unlockOtherRS(regionserver);
255       }
256       return newQueues;
257     }
258   }
259 
260   private void removeQueueFromLockedRS(String znode, String peerId) {
261     String nodePath = ZKUtil.joinZNode(this.queuesZNode, znode);
262     String peerPath = ZKUtil.joinZNode(nodePath, peerId);
263     try {
264       ZKUtil.deleteNodeRecursively(this.zookeeper, peerPath);
265     } catch (KeeperException e) {
266       LOG.warn("Remove copied queue failed", e);
267     }
268   }
269 
270   @Override
271   public void removeReplicatorIfQueueIsEmpty(String regionserver) {
272     String rsPath = ZKUtil.joinZNode(this.queuesZNode, regionserver);
273     try {
274       List<String> list = ZKUtil.listChildrenNoWatch(this.zookeeper, rsPath);
275       if (list != null && list.size() == 0){
276         ZKUtil.deleteNode(this.zookeeper, rsPath);
277       }
278     } catch (KeeperException e) {
279       LOG.warn("Got error while removing replicator", e);
280     }
281   }
282 
283   /**
284    * Try to set a lock in another region server's znode.
285    * @param znode the server names of the other server
286    * @return true if the lock was acquired, false in every other cases
287    */
288   @VisibleForTesting
289   public boolean lockOtherRS(String znode) {
290     try {
291       String parent = ZKUtil.joinZNode(this.queuesZNode, znode);
292       if (parent.equals(this.myQueuesZnode)) {
293         LOG.warn("Won't lock because this is us, we're dead!");
294         return false;
295       }
296       String p = ZKUtil.joinZNode(parent, RS_LOCK_ZNODE);
297       ZKUtil.createAndWatch(this.zookeeper, p, lockToByteArray(this.myQueuesZnode));
298     } catch (KeeperException e) {
299       // This exception will pop up if the znode under which we're trying to
300       // create the lock is already deleted by another region server, meaning
301       // that the transfer already occurred.
302       // NoNode => transfer is done and znodes are already deleted
303       // NodeExists => lock znode already created by another RS
304       if (e instanceof KeeperException.NoNodeException
305           || e instanceof KeeperException.NodeExistsException) {
306         LOG.info("Won't transfer the queue," + " another RS took care of it because of: "
307             + e.getMessage());
308       } else {
309         LOG.info("Failed lock other rs", e);
310       }
311       return false;
312     }
313     return true;
314   }
315 
316   public String getLockZNode(String znode) {
317     return this.queuesZNode + "/" + znode + "/" + RS_LOCK_ZNODE;
318   }
319 
320   @VisibleForTesting
321   public boolean checkLockExists(String znode) throws KeeperException {
322     return ZKUtil.checkExists(zookeeper, getLockZNode(znode)) >= 0;
323   }
324 
325   private void unlockOtherRS(String znode){
326     String parent = ZKUtil.joinZNode(this.queuesZNode, znode);
327     String p = ZKUtil.joinZNode(parent, RS_LOCK_ZNODE);
328     try {
329       ZKUtil.deleteNode(this.zookeeper, p);
330     } catch (KeeperException e) {
331       this.abortable.abort("Remove lock failed", e);
332     }
333   }
334 
335   /**
336    * Delete all the replication queues for a given region server.
337    * @param regionserverZnode The znode of the region server to delete.
338    */
339   private void deleteAnotherRSQueues(String regionserverZnode) {
340     String fullpath = ZKUtil.joinZNode(this.queuesZNode, regionserverZnode);
341     try {
342       List<String> clusters = ZKUtil.listChildrenNoWatch(this.zookeeper, fullpath);
343       for (String cluster : clusters) {
344         // No need to delete, it will be deleted later.
345         if (cluster.equals(RS_LOCK_ZNODE)) {
346           continue;
347         }
348         String fullClusterPath = ZKUtil.joinZNode(fullpath, cluster);
349         ZKUtil.deleteNodeRecursively(this.zookeeper, fullClusterPath);
350       }
351       // Finish cleaning up
352       ZKUtil.deleteNodeRecursively(this.zookeeper, fullpath);
353     } catch (KeeperException e) {
354       if (e instanceof KeeperException.NoNodeException
355           || e instanceof KeeperException.NotEmptyException) {
356         // Testing a special case where another region server was able to
357         // create a lock just after we deleted it, but then was also able to
358         // delete the RS znode before us or its lock znode is still there.
359         if (e.getPath().equals(fullpath)) {
360           return;
361         }
362       }
363       this.abortable.abort("Failed to delete replication queues for region server: "
364           + regionserverZnode, e);
365     }
366   }
367 
368   /**
369    * It "atomically" copies all the wals queues from another region server and returns them all
370    * sorted per peer cluster (appended with the dead server's znode).
371    * @param znode pertaining to the region server to copy the queues from
372    */
373   private Pair<String, SortedSet<String>> moveQueueUsingMulti(String znode, String peerId) {
374     try {
375       // hbase/replication/rs/deadrs
376       String deadRSZnodePath = ZKUtil.joinZNode(this.queuesZNode, znode);
377       List<ZKUtilOp> listOfOps = new ArrayList<>();
378       ReplicationQueueInfo replicationQueueInfo = new ReplicationQueueInfo(peerId);
379       if (!peerExists(replicationQueueInfo.getPeerId())) {
380         // the orphaned queues must be moved, otherwise the delete op of dead rs will fail,
381         // this will cause the whole multi op fail.
382         // NodeFailoverWorker will skip the orphaned queues.
383         LOG.warn("Peer " + peerId +
384             " didn't exist, will move its queue to avoid the failure of multi op");
385       }
386       String newPeerId = peerId + "-" + znode;
387       String newPeerZnode = ZKUtil.joinZNode(this.myQueuesZnode, newPeerId);
388       // check the logs queue for the old peer cluster
389       String oldClusterZnode = ZKUtil.joinZNode(deadRSZnodePath, peerId);
390       List<String> wals = ZKUtil.listChildrenNoWatch(this.zookeeper, oldClusterZnode);
391       SortedSet<String> logQueue = new TreeSet<>();
392       if (wals == null || wals.size() == 0) {
393         listOfOps.add(ZKUtilOp.deleteNodeFailSilent(oldClusterZnode));
394       } else {
395         // create the new cluster znode
396         ZKUtilOp op = ZKUtilOp.createAndFailSilent(newPeerZnode, HConstants.EMPTY_BYTE_ARRAY);
397         listOfOps.add(op);
398         // get the offset of the logs and set it to new znodes
399         for (String wal : wals) {
400           String oldWalZnode = ZKUtil.joinZNode(oldClusterZnode, wal);
401           byte[] logOffset = ZKUtil.getData(this.zookeeper, oldWalZnode);
402           LOG.debug("Creating " + wal + " with data " + Bytes.toString(logOffset));
403           String newLogZnode = ZKUtil.joinZNode(newPeerZnode, wal);
404           listOfOps.add(ZKUtilOp.createAndFailSilent(newLogZnode, logOffset));
405           listOfOps.add(ZKUtilOp.deleteNodeFailSilent(oldWalZnode));
406           logQueue.add(wal);
407         }
408         // add delete op for peer
409         listOfOps.add(ZKUtilOp.deleteNodeFailSilent(oldClusterZnode));
410 
411         if (LOG.isTraceEnabled())
412           LOG.trace(" The multi list size is: " + listOfOps.size());
413       }
414       ZKUtil.multiOrSequential(this.zookeeper, listOfOps, false);
415       if (LOG.isTraceEnabled())
416         LOG.trace("Atomically moved the dead regionserver logs. ");
417       return new Pair<>(newPeerId, logQueue);
418     } catch (KeeperException e) {
419       // Multi call failed; it looks like some other regionserver took away the logs.
420       LOG.warn("Got exception in copyQueuesFromRSUsingMulti: ", e);
421     } catch (InterruptedException e) {
422       LOG.warn("Got exception in copyQueuesFromRSUsingMulti: ", e);
423       Thread.currentThread().interrupt();
424     }
425     return null;
426   }
427 
428   /**
429    * This methods moves all the wals queues from another region server and returns them all sorted
430    * per peer cluster (appended with the dead server's znode)
431    * @param znode server names to copy
432    * @return all wals for the peer of that cluster, null if an error occurred
433    */
434   private Pair<String, SortedSet<String>> copyQueueFromLockedRS(String znode, String peerId) {
435     // TODO this method isn't atomic enough, we could start copying and then
436     // TODO fail for some reason and we would end up with znodes we don't want.
437     try {
438       String nodePath = ZKUtil.joinZNode(this.queuesZNode, znode);
439       ReplicationQueueInfo replicationQueueInfo = new ReplicationQueueInfo(peerId);
440       String clusterPath = ZKUtil.joinZNode(nodePath, peerId);
441       if (!peerExists(replicationQueueInfo.getPeerId())) {
442         LOG.warn("Peer " + peerId + " didn't exist, skipping the replay");
443         // Protection against moving orphaned queues
444         return null;
445       }
446       // We add the name of the recovered RS to the new znode, we can even
447       // do that for queues that were recovered 10 times giving a znode like
448       // number-startcode-number-otherstartcode-number-anotherstartcode-etc
449       String newCluster = peerId + "-" + znode;
450       String newClusterZnode = ZKUtil.joinZNode(this.myQueuesZnode, newCluster);
451 
452       List<String> wals = ZKUtil.listChildrenNoWatch(this.zookeeper, clusterPath);
453       // That region server didn't have anything to replicate for this cluster
454       if (wals == null || wals.size() == 0) {
455         return null;
456       }
457       ZKUtil.createNodeIfNotExistsAndWatch(this.zookeeper, newClusterZnode,
458           HConstants.EMPTY_BYTE_ARRAY);
459       SortedSet<String> logQueue = new TreeSet<>();
460       for (String wal : wals) {
461         String z = ZKUtil.joinZNode(clusterPath, wal);
462         byte[] positionBytes = ZKUtil.getData(this.zookeeper, z);
463         long position = 0;
464         try {
465           position = ZKUtil.parseWALPositionFrom(positionBytes);
466         } catch (DeserializationException e) {
467           LOG.warn("Failed parse of wal position from the following znode: " + z
468               + ", Exception: " + e);
469         }
470         LOG.debug("Creating " + wal + " with data " + position);
471         String child = ZKUtil.joinZNode(newClusterZnode, wal);
472         // Position doesn't actually change, we are just deserializing it for
473         // logging, so just use the already serialized version
474         ZKUtil.createNodeIfNotExistsAndWatch(this.zookeeper, child, positionBytes);
475         logQueue.add(wal);
476       }
477       return new Pair<>(newCluster, logQueue);
478     } catch (KeeperException e) {
479       LOG.warn("Got exception in copyQueueFromLockedRS: ", e);
480     } catch (InterruptedException e) {
481       LOG.warn(e);
482       Thread.currentThread().interrupt();
483     }
484     return null;
485   }
486 
487   /**
488    * @param lockOwner
489    * @return Serialized protobuf of <code>lockOwner</code> with pb magic prefix prepended suitable
490    *         for use as content of an replication lock during region server fail over.
491    */
492   static byte[] lockToByteArray(final String lockOwner) {
493     byte[] bytes =
494         ZooKeeperProtos.ReplicationLock.newBuilder().setLockOwner(lockOwner).build().toByteArray();
495     return ProtobufUtil.prependPBMagic(bytes);
496   }
497 
498   @Override
499   public void addHFileRefs(String peerId, List<String> files) throws ReplicationException {
500     String peerZnode = ZKUtil.joinZNode(this.hfileRefsZNode, peerId);
501     boolean debugEnabled = LOG.isDebugEnabled();
502     if (debugEnabled) {
503       LOG.debug("Adding hfile references " + files + " in queue " + peerZnode);
504     }
505     List<ZKUtilOp> listOfOps = new ArrayList<ZKUtil.ZKUtilOp>();
506     int size = files.size();
507     for (int i = 0; i < size; i++) {
508       listOfOps.add(ZKUtilOp.createAndFailSilent(ZKUtil.joinZNode(peerZnode, files.get(i)),
509         HConstants.EMPTY_BYTE_ARRAY));
510     }
511     if (debugEnabled) {
512       LOG.debug(" The multi list size for adding hfile references in zk for node " + peerZnode
513           + " is " + listOfOps.size());
514     }
515     try {
516       ZKUtil.multiOrSequential(this.zookeeper, listOfOps, true);
517     } catch (KeeperException e) {
518       throw new ReplicationException("Failed to create hfile reference znode=" + e.getPath(), e);
519     }
520   }
521 
522   @Override
523   public void removeHFileRefs(String peerId, List<String> files) {
524     String peerZnode = ZKUtil.joinZNode(this.hfileRefsZNode, peerId);
525     boolean debugEnabled = LOG.isDebugEnabled();
526     if (debugEnabled) {
527       LOG.debug("Removing hfile references " + files + " from queue " + peerZnode);
528     }
529     List<ZKUtilOp> listOfOps = new ArrayList<ZKUtil.ZKUtilOp>();
530     int size = files.size();
531     for (int i = 0; i < size; i++) {
532       listOfOps.add(ZKUtilOp.deleteNodeFailSilent(ZKUtil.joinZNode(peerZnode, files.get(i))));
533     }
534     if (debugEnabled) {
535       LOG.debug(" The multi list size for removing hfile references in zk for node " + peerZnode
536           + " is " + listOfOps.size());
537     }
538     try {
539       ZKUtil.multiOrSequential(this.zookeeper, listOfOps, true);
540     } catch (KeeperException e) {
541       LOG.error("Failed to remove hfile reference znode=" + e.getPath(), e);
542     }
543   }
544 
545   @Override
546   public void addPeerToHFileRefs(String peerId) throws ReplicationException {
547     String peerZnode = ZKUtil.joinZNode(this.hfileRefsZNode, peerId);
548     try {
549       if (ZKUtil.checkExists(this.zookeeper, peerZnode) == -1) {
550         LOG.info("Adding peer " + peerId + " to hfile reference queue.");
551         ZKUtil.createWithParents(this.zookeeper, peerZnode);
552       }
553     } catch (KeeperException e) {
554       throw new ReplicationException("Failed to add peer " + peerId + " to hfile reference queue.",
555           e);
556     }
557   }
558 
559   @Override
560   public void removePeerFromHFileRefs(String peerId) {
561     final String peerZnode = ZKUtil.joinZNode(this.hfileRefsZNode, peerId);
562     try {
563       if (ZKUtil.checkExists(this.zookeeper, peerZnode) == -1) {
564         if (LOG.isDebugEnabled()) {
565           LOG.debug("Peer " + peerZnode + " not found in hfile reference queue.");
566         }
567         return;
568       } else {
569         LOG.info("Removing peer " + peerZnode + " from hfile reference queue.");
570         ZKUtil.deleteNodeRecursively(this.zookeeper, peerZnode);
571       }
572     } catch (KeeperException e) {
573       LOG.error("Ignoring the exception to remove peer " + peerId + " from hfile reference queue.",
574         e);
575     }
576   }
577 }