/* This file is part of VoltDB.
* Copyright (C) 2008-2017 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 <http://www.gnu.org/licenses/>.
*/
package org.voltdb.iv2;
import java.lang.InterruptedException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import com.google_voltpatches.common.base.Supplier;
import com.google_voltpatches.common.collect.ImmutableSortedSet;
import org.apache.zookeeper_voltpatches.ZooKeeper;
import org.voltcore.logging.VoltLogger;
import org.voltcore.utils.CoreUtils;
import org.voltdb.VoltDB;
import org.voltdb.VoltZK;
import com.google_voltpatches.common.collect.ImmutableMap;
public class MpTerm implements Term
{
VoltLogger tmLog = new VoltLogger("TM");
private final String m_whoami;
private final InitiatorMailbox m_mailbox;
private final ZooKeeper m_zk;
private volatile SortedSet<Long> m_knownLeaders = ImmutableSortedSet.of();
// Initialized in start() -- when the term begins.
protected LeaderCache m_leaderCache;
// runs on the babysitter thread when a replica changes.
// simply forward the notice to the initiator mailbox; it controls
// the Term processing.
// NOTE: The contract with LeaderCache is that it always
// returns a full cache (one entry for every partition). Returning a
// partially filled cache is NotSoGood(tm).
LeaderCache.Callback m_leadersChangeHandler = new LeaderCache.Callback()
{
@Override
public void run(ImmutableMap<Integer, Long> cache)
{
ImmutableSortedSet.Builder<Long> builder = ImmutableSortedSet.naturalOrder();
for (Long HSId : cache.values()) {
builder.add(HSId);
}
final SortedSet<Long> updatedLeaders = builder.build();
tmLog.debug(m_whoami + "updating leaders: " + CoreUtils.hsIdCollectionToString(updatedLeaders));
tmLog.debug(m_whoami
+ "LeaderCache change handler updating leader list to: "
+ CoreUtils.hsIdCollectionToString(updatedLeaders));
m_knownLeaders = updatedLeaders;
m_mailbox.updateReplicas(new ArrayList<Long>(m_knownLeaders), cache);
}
};
/**
* Setup a new Term but don't take any action to take responsibility.
*/
public MpTerm(ZooKeeper zk, long initiatorHSId, InitiatorMailbox mailbox,
String whoami)
{
m_zk = zk;
m_mailbox = mailbox;
m_whoami = whoami;
}
/**
* Start a new Term. This starts watching followers via ZK. Block on an
* appropriate repair algorithm to watch final promotion to leader.
*/
@Override
public void start()
{
try {
m_leaderCache = new LeaderCache(m_zk, VoltZK.iv2masters, m_leadersChangeHandler);
m_leaderCache.start(true);
}
catch (ExecutionException ee) {
VoltDB.crashLocalVoltDB("Unable to create babysitter starting term.", true, ee);
} catch (InterruptedException e) {
VoltDB.crashLocalVoltDB("Unable to create babysitter starting term.", true, e);
}
}
@Override
public void shutdown()
{
if (m_leaderCache != null) {
try {
m_leaderCache.shutdown();
} catch (InterruptedException e) {
// We're shutting down...this may jsut be faster.
}
}
}
@Override
public Supplier<List<Long>> getInterestingHSIds()
{
return new Supplier<List<Long>>() {
@Override
public List<Long> get() {
return new ArrayList<Long>(m_knownLeaders);
}
};
}
}