001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.master;
019
020import java.io.IOException;
021import java.util.List;
022import java.util.NavigableSet;
023import java.util.TreeSet;
024
025import org.apache.hadoop.hbase.zookeeper.ZKListener;
026import org.apache.hadoop.hbase.zookeeper.ZKUtil;
027import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
028import org.apache.yetus.audience.InterfaceAudience;
029import org.apache.hadoop.hbase.Abortable;
030import org.apache.hadoop.hbase.ServerName;
031import org.apache.zookeeper.KeeperException;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034
035/**
036 * Tracks the list of draining region servers via ZK.
037 *
038 * <p>This class is responsible for watching for changes to the draining
039 * servers list.  It handles adds/deletes in the draining RS list and
040 * watches each node.
041 *
042 * <p>If an RS gets deleted from draining list, we call
043 * {@link ServerManager#removeServerFromDrainList(ServerName)}
044 *
045 * <p>If an RS gets added to the draining list, we add a watcher to it and call
046 * {@link ServerManager#addServerToDrainList(ServerName)}
047 *
048 * <p>This class is deprecated in 2.0 because decommission/draining API goes through
049 * master in 2.0. Can remove this class in 3.0.
050 *
051 */
052@InterfaceAudience.Private
053public class DrainingServerTracker extends ZKListener {
054  private static final Logger LOG = LoggerFactory.getLogger(DrainingServerTracker.class);
055
056  private ServerManager serverManager;
057  private final NavigableSet<ServerName> drainingServers = new TreeSet<>();
058  private Abortable abortable;
059
060  public DrainingServerTracker(ZKWatcher watcher,
061      Abortable abortable, ServerManager serverManager) {
062    super(watcher);
063    this.abortable = abortable;
064    this.serverManager = serverManager;
065  }
066
067  /**
068   * Starts the tracking of draining RegionServers.
069   *
070   * <p>All Draining RSs will be tracked after this method is called.
071   *
072   * @throws KeeperException
073   */
074  public void start() throws KeeperException, IOException {
075    watcher.registerListener(this);
076    // Add a ServerListener to check if a server is draining when it's added.
077    serverManager.registerListener(new ServerListener() {
078      @Override
079      public void serverAdded(ServerName sn) {
080        if (drainingServers.contains(sn)){
081          serverManager.addServerToDrainList(sn);
082        }
083      }
084    });
085    List<String> servers =
086      ZKUtil.listChildrenAndWatchThem(watcher, watcher.getZNodePaths().drainingZNode);
087    add(servers);
088  }
089
090  private void add(final List<String> servers) throws IOException {
091    synchronized(this.drainingServers) {
092      this.drainingServers.clear();
093      for (String n: servers) {
094        final ServerName sn = ServerName.valueOf(ZKUtil.getNodeName(n));
095        this.drainingServers.add(sn);
096        this.serverManager.addServerToDrainList(sn);
097        LOG.info("Draining RS node created, adding to list [" +
098            sn + "]");
099
100      }
101    }
102  }
103
104  private void remove(final ServerName sn) {
105    synchronized(this.drainingServers) {
106      this.drainingServers.remove(sn);
107      this.serverManager.removeServerFromDrainList(sn);
108    }
109  }
110
111  @Override
112  public void nodeDeleted(final String path) {
113    if(path.startsWith(watcher.getZNodePaths().drainingZNode)) {
114      final ServerName sn = ServerName.valueOf(ZKUtil.getNodeName(path));
115      LOG.info("Draining RS node deleted, removing from list [" +
116          sn + "]");
117      remove(sn);
118    }
119  }
120
121  @Override
122  public void nodeChildrenChanged(final String path) {
123    if(path.equals(watcher.getZNodePaths().drainingZNode)) {
124      try {
125        final List<String> newNodes =
126          ZKUtil.listChildrenAndWatchThem(watcher, watcher.getZNodePaths().drainingZNode);
127        add(newNodes);
128      } catch (KeeperException e) {
129        abortable.abort("Unexpected zk exception getting RS nodes", e);
130      } catch (IOException e) {
131        abortable.abort("Unexpected zk exception getting RS nodes", e);
132      }
133    }
134  }
135}