Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* This file is part of VoltDB.
* Copyright (C) 2008-2018 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see .
*/
package org.voltcore.zk;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google_voltpatches.common.collect.ImmutableList;
import org.apache.zookeeper_voltpatches.KeeperException;
import org.apache.zookeeper_voltpatches.WatchedEvent;
import org.apache.zookeeper_voltpatches.Watcher;
import org.apache.zookeeper_voltpatches.ZooKeeper;
import org.apache.zookeeper_voltpatches.data.Stat;
import org.voltcore.logging.VoltLogger;
import org.voltcore.utils.CoreUtils;
import org.voltcore.utils.Pair;
import org.voltdb.VoltDB;
/**
* BabySitter watches a zookeeper node and alerts on appearances
* and disappearances of direct children.
*
* Note: if you are using this to watch a LeaderElector chain,
* be aware that the BabySitter notices race with notices of
* becoming the Leader. That is, a non-leader's babysitter can
* change before the non-leader knows it is the new leader.
*
* It is easier to use as the Leader -- in this case the leader
* can observe appearances and disappearances of its non-leader
* peers.
*/
public class BabySitter
{
private static final VoltLogger repairLog = new VoltLogger("REPAIR");
private final String m_dir; // the directory to monitor
private final Callback m_cb; // the callback when children change
private final ZooKeeper m_zk;
private final ExecutorService m_es;
private boolean m_isExecutorServiceLocal = false;
private volatile List m_children = ImmutableList.of();
private AtomicBoolean m_shutdown = new AtomicBoolean(false);
/**
* Callback is passed an immutable child list when a child changes.
* Callback runs in the BabySitter's ES (not the zk trigger thread).
*/
public abstract static class Callback
{
abstract public void run(List children);
}
/** lastSeenChildren returns the last recorded list of children */
public List lastSeenChildren()
{
if (m_shutdown.get()) {
throw new RuntimeException("Requested children from shutdown babysitter.");
}
return m_children;
}
/**
* shutdown silences the babysitter and causes watches to not reset.
* Note that shutting down will churn ephemeral ZK nodes - shutdown
* allows the programmer to not set watches on nodes from terminated session.
*/
synchronized public void shutdown()
{
m_shutdown.set(true);
if (m_isExecutorServiceLocal) {
try {
m_es.shutdown();
m_es.awaitTermination(365, TimeUnit.DAYS);
} catch (InterruptedException e) {
repairLog.warn("Unexpected interrupted exception", e);
}
}
}
private BabySitter(ZooKeeper zk, String dir, Callback cb, ExecutorService es)
{
m_zk = zk;
m_dir = dir;
m_cb = cb;
m_es = es;
}
/**
* Create a new BabySitter and block on reading the initial children list.
*/
public static Pair> blockingFactory(ZooKeeper zk, String dir, Callback cb)
throws InterruptedException, ExecutionException
{
ExecutorService es = CoreUtils.getCachedSingleThreadExecutor("Babysitter-" + dir, 15000);
Pair> babySitter = blockingFactory(zk, dir, cb, es);
babySitter.getFirst().m_isExecutorServiceLocal = true;
return babySitter;
}
/**
* Create a new BabySitter and block on reading the initial children list.
* Use the provided ExecutorService to queue events to, rather than
* creating a private ExecutorService. The initial set of children will be retrieved
* in the current thread and not the ExecutorService because it is assumed
* this is being called from the ExecutorService
*/
public static Pair> blockingFactory(ZooKeeper zk, String dir, Callback cb,
ExecutorService es)
throws InterruptedException, ExecutionException
{
BabySitter bs = new BabySitter(zk, dir, cb, es);
List initialChildren;
try {
initialChildren = bs.m_eventHandler.call();
} catch (Exception e) {
throw new ExecutionException(e);
}
return new Pair>(bs, initialChildren);
}
/**
* Create a new BabySitter and make sure it reads the initial children list.
* Use the provided ExecutorService to queue events to, rather than
* creating a private ExecutorService.
*/
public static BabySitter nonblockingFactory(ZooKeeper zk, String dir,
Callback cb, ExecutorService es)
throws InterruptedException, ExecutionException
{
BabySitter bs = new BabySitter(zk, dir, cb, es);
bs.m_es.submit(bs.m_eventHandler);
return bs;
}
// eventHandler fetches the new children and resets the watch.
// It is always run in m_es (the ExecutorService).
private final Callable> m_eventHandler = new Callable>() {
@Override
public List call() throws InterruptedException, KeeperException
{
synchronized(BabySitter.this) {
// ignore post-shutdown events. don't reset watch.
if (m_shutdown.get() == true) {
return null;
}
List newChildren = watch();
if (m_cb != null) {
m_cb.run(newChildren);
}
return newChildren;
}
}
};
private final Watcher m_watcher = new Watcher()
{
@Override
public void process(WatchedEvent event)
{
try {
m_es.submit(m_eventHandler);
} catch (RejectedExecutionException e) {
if (m_shutdown.get()) return;
VoltDB.crashLocalVoltDB("Unexpected rejected execution exception", true, e);
}
}
};
private List watch() throws InterruptedException, KeeperException
{
Stat stat = new Stat();
List zkchildren = m_zk.getChildren(m_dir, m_watcher, stat);
// Sort on the ephemeral sequential part, the prefix is not padded, so string sort doesn't work
Collections.sort(zkchildren, new Comparator() {
@Override
public int compare(String left, String right)
{
return CoreZK.getSuffixFromChildName(left).compareTo(CoreZK.getSuffixFromChildName(right));
}
});
m_children = ImmutableList.copyOf(zkchildren);
return m_children;
}
}