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 org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.hbase.Abortable;
26  import org.apache.hadoop.hbase.ServerName;
27  import org.apache.hadoop.hbase.exceptions.DeserializationException;
28  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
29  import org.apache.hadoop.hbase.zookeeper.ZooKeeperNodeTracker;
30  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
31  import org.apache.zookeeper.KeeperException;
32  
33  import java.io.Closeable;
34  import java.io.IOException;
35  import java.util.ArrayList;
36  import java.util.List;
37  import java.util.concurrent.atomic.AtomicBoolean;
38  
39  /**
40   * This class acts as a wrapper for all the objects used to identify and
41   * communicate with remote peers and is responsible for answering to expired
42   * sessions and re-establishing the ZK connections.
43   */
44  @InterfaceAudience.Private
45  public class ReplicationPeer implements Abortable, Closeable {
46    private static final Log LOG = LogFactory.getLog(ReplicationPeer.class);
47  
48    private final String clusterKey;
49    private final String id;
50    private List<ServerName> regionServers = new ArrayList<ServerName>(0);
51    private final AtomicBoolean peerEnabled = new AtomicBoolean();
52    // Cannot be final since a new object needs to be recreated when session fails
53    private ZooKeeperWatcher zkw;
54    private final Configuration conf;
55  
56    private PeerStateTracker peerStateTracker;
57  
58    /**
59     * Constructor that takes all the objects required to communicate with the
60     * specified peer, except for the region server addresses.
61     * @param conf configuration object to this peer
62     * @param key cluster key used to locate the peer
63     * @param id string representation of this peer's identifier
64     */
65    public ReplicationPeer(Configuration conf, String key,
66        String id) throws IOException {
67      this.conf = conf;
68      this.clusterKey = key;
69      this.id = id;
70      this.reloadZkWatcher();
71    }
72  
73    /**
74     * start a state tracker to check whether this peer is enabled or not
75     *
76     * @param zookeeper zk watcher for the local cluster
77     * @param peerStateNode path to zk node which stores peer state
78     * @throws KeeperException
79     */
80    public void startStateTracker(ZooKeeperWatcher zookeeper, String peerStateNode)
81        throws KeeperException {
82      ReplicationZookeeper.ensurePeerEnabled(zookeeper, peerStateNode);
83      this.peerStateTracker = new PeerStateTracker(peerStateNode, zookeeper, this);
84      this.peerStateTracker.start();
85      try {
86        this.readPeerStateZnode();
87      } catch (DeserializationException e) {
88        throw ZKUtil.convert(e);
89      }
90    }
91  
92    private void readPeerStateZnode() throws DeserializationException {
93      this.peerEnabled.set(ReplicationZookeeper.isStateEnabled(this.peerStateTracker.getData(false)));
94    }
95  
96    /**
97     * Get the cluster key of that peer
98     * @return string consisting of zk ensemble addresses, client port
99     * and root znode
100    */
101   public String getClusterKey() {
102     return clusterKey;
103   }
104 
105   /**
106    * Get the state of this peer
107    * @return atomic boolean that holds the status
108    */
109   public AtomicBoolean getPeerEnabled() {
110     return peerEnabled;
111   }
112 
113   /**
114    * Get a list of all the addresses of all the region servers
115    * for this peer cluster
116    * @return list of addresses
117    */
118   public List<ServerName> getRegionServers() {
119     return regionServers;
120   }
121 
122   /**
123    * Set the list of region servers for that peer
124    * @param regionServers list of addresses for the region servers
125    */
126   public void setRegionServers(List<ServerName> regionServers) {
127     this.regionServers = regionServers;
128   }
129 
130   /**
131    * Get the ZK connection to this peer
132    * @return zk connection
133    */
134   public ZooKeeperWatcher getZkw() {
135     return zkw;
136   }
137 
138   /**
139    * Get the identifier of this peer
140    * @return string representation of the id (short)
141    */
142   public String getId() {
143     return id;
144   }
145 
146   /**
147    * Get the configuration object required to communicate with this peer
148    * @return configuration object
149    */
150   public Configuration getConfiguration() {
151     return conf;
152   }
153 
154   @Override
155   public void abort(String why, Throwable e) {
156     LOG.fatal("The ReplicationPeer coresponding to peer " + clusterKey
157         + " was aborted for the following reason(s):" + why, e);
158   }
159 
160   /**
161    * Closes the current ZKW (if not null) and creates a new one
162    * @throws IOException If anything goes wrong connecting
163    */
164   public void reloadZkWatcher() throws IOException {
165     if (zkw != null) zkw.close();
166     zkw = new ZooKeeperWatcher(conf,
167         "connection to cluster: " + id, this);
168   }
169 
170   @Override
171   public boolean isAborted() {
172     // Currently the replication peer is never "Aborted", we just log when the
173     // abort method is called.
174     return false;
175   }
176 
177   @Override
178   public void close() throws IOException {
179     if (zkw != null){
180       zkw.close();
181     }
182   }
183 
184   /**
185    * Tracker for state of this peer
186    */
187   public class PeerStateTracker extends ZooKeeperNodeTracker {
188 
189     public PeerStateTracker(String peerStateZNode, ZooKeeperWatcher watcher,
190         Abortable abortable) {
191       super(watcher, peerStateZNode, abortable);
192     }
193 
194     @Override
195     public synchronized void nodeDataChanged(String path) {
196       if (path.equals(node)) {
197         super.nodeDataChanged(path);
198         try {
199           readPeerStateZnode();
200         } catch (DeserializationException e) {
201           LOG.warn("Failed deserializing the content of " + path, e);
202         }
203       }
204     }
205   }
206 }