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.ipc;
019
020import java.util.HashMap;
021import java.util.Map;
022import org.apache.hadoop.conf.Configuration;
023import org.apache.hadoop.hbase.net.Address;
024import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
025import org.apache.yetus.audience.InterfaceAudience;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * A class to manage a list of servers that failed recently.
031 */
032@InterfaceAudience.Private
033public class FailedServers {
034  private final Map<Address, Long> failedServers = new HashMap<Address, Long>();
035  private long latestExpiry = 0;
036  private final int recheckServersTimeout;
037  private static final Logger LOG = LoggerFactory.getLogger(FailedServers.class);
038
039  public FailedServers(Configuration conf) {
040    this.recheckServersTimeout =
041      conf.getInt(RpcClient.FAILED_SERVER_EXPIRY_KEY, RpcClient.FAILED_SERVER_EXPIRY_DEFAULT);
042  }
043
044  /**
045   * Add an address to the list of the failed servers list.
046   */
047  public synchronized void addToFailedServers(Address address, Throwable throwable) {
048    final long expiry = EnvironmentEdgeManager.currentTime() + recheckServersTimeout;
049    this.failedServers.put(address, expiry);
050    this.latestExpiry = expiry;
051    if (LOG.isDebugEnabled()) {
052      LOG.debug("Added failed server with address " + address + " to list caused by "
053        + throwable.toString());
054    }
055  }
056
057  /**
058   * Check if the server should be considered as bad. Clean the old entries of the list.
059   * @return true if the server is in the failed servers list
060   */
061  public synchronized boolean isFailedServer(final Address address) {
062    if (failedServers.isEmpty()) {
063      return false;
064    }
065    final long now = EnvironmentEdgeManager.currentTime();
066    if (now > this.latestExpiry) {
067      failedServers.clear();
068      return false;
069    }
070    Long expiry = this.failedServers.get(address);
071    if (expiry == null) {
072      return false;
073    }
074    if (expiry >= now) {
075      return true;
076    } else {
077      this.failedServers.remove(address);
078    }
079    return false;
080  }
081}