Package com.facebook.zookeeper.connection

Source Code of com.facebook.zookeeper.connection.ZkConnectionManagerImpl$ConnectionWatcher

/*
* Copyright (C) 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.zookeeper.connection;

import com.facebook.concurrency.ErrorLoggingRunnable;
import com.facebook.concurrency.NamedThreadFactory;
import com.facebook.zookeeper.ZooKeeperFactory;
import com.facebook.zookeeper.ZooKeeperIface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class ZkConnectionManagerImpl implements ZkConnectionManager {
  private static final Logger LOG =
    LoggerFactory.getLogger(ZkConnectionManagerImpl.class);

  private final ZooKeeperFactory zooKeeperFactory;
  private final List<Watcher> registeredWatchers =
    new CopyOnWriteArrayList<Watcher>();
  private final ConnectionWatcher connectionWatcher = new ConnectionWatcher();
  private final ConnectionRenewer connectionRenewer =
    new ConnectionRenewer();
  private final int connectTimeoutMillis;
  private final int retryIntervalMillis;
  private volatile ZooKeeperIface zk = null;
  private volatile boolean isStarted = false;
  private volatile boolean isShutDown = false;

  public ZkConnectionManagerImpl(
    ZooKeeperFactory zooKeeperFactory,
    int connectTimeoutMillis,
    int retryIntervalMillis
  ) {
    this.zooKeeperFactory = zooKeeperFactory;
    this.connectTimeoutMillis = connectTimeoutMillis;
    this.retryIntervalMillis = retryIntervalMillis;
  }

  // Instance must be started before it becomes valid for use
  public synchronized void start() {
    if (isStarted) {
      throw new IllegalStateException("Should only be started once");
    }
    // Connect to the ZooKeeper cluster
    try {
      // Call connect first to guarantee zk is not null when this method exits
      connect();
    } catch (IOException e) {
      connectionRenewer.activate();
    }
    isStarted = true;
  }

  private void verifyOperational() {
    if (!isStarted) {
      throw new IllegalStateException("Not yet started");
    }
    if (isShutDown) {
      throw new IllegalStateException("Already closed");
    }
  }

  private boolean isAlive() {
    return zk != null && zk.getState().isAlive();
  }

  private synchronized void connect() throws IOException {
    if (!isShutDown && !isAlive()) {
      LOG.info("Initializing ZooKeeper connection");
      connectionWatcher.reset();
      zk = zooKeeperFactory.create(connectionWatcher);
    }
  }

  @Override
  public ZooKeeperIface getClient() throws InterruptedException {
    verifyOperational();
    // Wait if we are in the process of connecting
    if (!connectionWatcher.waitForConnect(connectTimeoutMillis, TimeUnit.MILLISECONDS)) {
      LOG.error("Exceeded " + connectTimeoutMillis + " ms waiting for " +
        "connection to be established! Using disconnected client...");
    }
    return zk;
  }

  @Override
  public ZooKeeper.States registerWatcher(Watcher watcher) {
    // This operation may legitimately happen at any time without problems

    // Note: the setting of the watch MUST precede the reading of the state
    // in order to ensure that the caller doesn't miss any watches after
    // getting the state.
    registeredWatchers.add(watcher);
    return (zk == null) ? ZooKeeper.States.CLOSED : zk.getState();
  }

  public synchronized void shutdown() throws InterruptedException {
    LOG.info("Closing ZooKeeper connection");
    verifyOperational();
    try {
      connectionRenewer.shutdown();
      if (isAlive()) {
        zk.close();
      }
    } finally {
      isShutDown = true;
    }
  }

  /**
   * When activated, will try to connect to ZooKeeper until it succeeds.
   */
  private class ConnectionRenewer {
    private final ScheduledExecutorService retryExecutor =
      Executors.newSingleThreadScheduledExecutor(
        new NamedThreadFactory("ZkConnectionManager-renewer")
      );
    private final AtomicBoolean isScheduled = new AtomicBoolean(false);

    public void activate() {
      if (isScheduled.compareAndSet(false, true)) {
        retryExecutor.execute(new ErrorLoggingRunnable(new Runnable() {
          @Override
          public void run() {
            try {
              connect();
              return; // Success, don't reschedule
            } catch (IOException e) {
              // Try again after sleeping...
              LOG.error("Failed to connect to ZooKeeper", e);
            } finally {
              isScheduled.set(false);
            }
            if (isScheduled.compareAndSet(false, true)) {
              retryExecutor.schedule(
                this, retryIntervalMillis, TimeUnit.MILLISECONDS
              );
            }
          }
        }));
      }
    }

    public void shutdown() {
      retryExecutor.shutdown();
    }
  }

  private class ConnectionWatcher implements Watcher {
    private volatile CountDownLatch connectedSignal = new CountDownLatch(1);

    public synchronized void reset() {
      connectedSignal.countDown(); // Unblock any prior threads
      connectedSignal = new CountDownLatch(1);
    }

    public boolean waitForConnect(int timeout, TimeUnit timeUnit)
      throws InterruptedException {
      return connectedSignal.await(timeout, timeUnit);
    }

    @Override
    public void process(WatchedEvent event) {
      // Handle the connection event signals. No thread needed because all
      // operations are non-blocking
      switch (event.getState()) {
        case SyncConnected:
          LOG.info("ZooKeeper connected");
          connectedSignal.countDown();
          break;
        case Disconnected:
          LOG.warn("ZooKeeper disconnected!");
          break;
        case Expired:
          LOG.warn("ZooKeeper session expired!");
          // Reset connection to the ZooKeeper cluster
          connectionRenewer.activate();
          break;
      }

      // Signal the registered watchers with the connection event
      for (Watcher watcher : registeredWatchers) {
        try {
          // All watchers should have non-blocking implementations
          watcher.process(event);
        } catch (Throwable t) {
          LOG.error("Registered watcher failed handling connection event", t);
        }
      }
    }
  }
}
TOP

Related Classes of com.facebook.zookeeper.connection.ZkConnectionManagerImpl$ConnectionWatcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.