View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.zookeeper;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.NavigableMap;
26  import java.util.TreeMap;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.hbase.Abortable;
31  import org.apache.hadoop.hbase.ServerName;
32  import org.apache.hadoop.hbase.master.ServerManager;
33  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
34  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionServerInfo;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.zookeeper.KeeperException;
37  
38  /**
39   * Tracks the online region servers via ZK.
40   *
41   * <p>Handling of new RSs checking in is done via RPC.  This class
42   * is only responsible for watching for expired nodes.  It handles
43   * listening for changes in the RS node list and watching each node.
44   *
45   * <p>If an RS node gets deleted, this automatically handles calling of
46   * {@link ServerManager#expireServer(ServerName)}
47   */
48  public class RegionServerTracker extends ZooKeeperListener {
49    private static final Log LOG = LogFactory.getLog(RegionServerTracker.class);
50    private NavigableMap<ServerName, RegionServerInfo> regionServers =
51  		  new TreeMap<ServerName, RegionServerInfo>();
52    private ServerManager serverManager;
53    private Abortable abortable;
54  
55    public RegionServerTracker(ZooKeeperWatcher watcher,
56        Abortable abortable, ServerManager serverManager) {
57      super(watcher);
58      this.abortable = abortable;
59      this.serverManager = serverManager;
60    }
61  
62    /**
63     * Starts the tracking of online RegionServers.
64     *
65     * <p>All RSs will be tracked after this method is called.
66     *
67     * @throws KeeperException
68     * @throws IOException
69     */
70    public void start() throws KeeperException, IOException {
71      watcher.registerListener(this);
72      List<String> servers =
73        ZKUtil.listChildrenAndWatchThem(watcher, watcher.rsZNode);
74      add(servers);
75    }
76  
77    private void add(final List<String> servers) throws IOException {
78      synchronized(this.regionServers) {
79        this.regionServers.clear();
80        for (String n: servers) {
81          ServerName sn = ServerName.parseServerName(ZKUtil.getNodeName(n));
82          if (regionServers.get(sn) == null) {
83            RegionServerInfo.Builder rsInfoBuilder = RegionServerInfo.newBuilder();
84            try {
85              String nodePath = ZKUtil.joinZNode(watcher.rsZNode, n);
86              byte[] data = ZKUtil.getData(watcher, nodePath);
87              LOG.info("Added tracking of RS " + nodePath);
88              if (data != null && data.length > 0 && ProtobufUtil.isPBMagicPrefix(data)) {
89                int magicLen = ProtobufUtil.lengthOfPBMagic();
90                rsInfoBuilder.mergeFrom(data, magicLen, data.length - magicLen);
91              }
92            } catch (KeeperException e) {
93              LOG.warn("Get Rs info port from ephemeral node", e);
94            } catch (IOException e) {
95              LOG.warn("Illegal data from ephemeral node", e);
96            }
97            this.regionServers.put(sn, rsInfoBuilder.build());
98          }
99        }
100     }
101   }
102 
103   private void remove(final ServerName sn) {
104     synchronized(this.regionServers) {
105       this.regionServers.remove(sn);
106     }
107   }
108 
109   @Override
110   public void nodeDeleted(String path) {
111     if (path.startsWith(watcher.rsZNode)) {
112       String serverName = ZKUtil.getNodeName(path);
113       LOG.info("RegionServer ephemeral node deleted, processing expiration [" +
114         serverName + "]");
115       ServerName sn = ServerName.parseServerName(serverName);
116       if (!serverManager.isServerOnline(sn)) {
117         LOG.warn(serverName.toString() + " is not online or isn't known to the master."+
118          "The latter could be caused by a DNS misconfiguration.");
119         return;
120       }
121       remove(sn);
122       this.serverManager.expireServer(sn);
123     }
124   }
125 
126   @Override
127   public void nodeChildrenChanged(String path) {
128     if (path.equals(watcher.rsZNode)) {
129       try {
130         List<String> servers =
131           ZKUtil.listChildrenAndWatchThem(watcher, watcher.rsZNode);
132         add(servers);
133       } catch (IOException e) {
134         abortable.abort("Unexpected zk exception getting RS nodes", e);
135       } catch (KeeperException e) {
136         abortable.abort("Unexpected zk exception getting RS nodes", e);
137       }
138     }
139   }
140 
141   public RegionServerInfo getRegionServerInfo(final ServerName sn) {
142     return regionServers.get(sn);
143   }
144 
145   /**
146    * Gets the online servers.
147    * @return list of online servers
148    */
149   public List<ServerName> getOnlineServers() {
150     synchronized (this.regionServers) {
151       return new ArrayList<ServerName>(this.regionServers.keySet());
152     }
153   }
154 }