/* 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;
import com.google_voltpatches.common.collect.ImmutableMap;
import org.apache.zookeeper_voltpatches.CreateMode;
import org.apache.zookeeper_voltpatches.KeeperException;
import org.apache.zookeeper_voltpatches.ZooDefs;
import org.voltcore.logging.VoltLogger;
import org.voltcore.zk.ZKUtil;
import org.voltdb.sysprocs.saverestore.SnapshotWritePlan;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* Wraps deferred snapshot setup work and run it on the snapshot IO agent thread.
*/
public class DeferredSnapshotSetup implements Callable<DeferredSnapshotSetup> {
private static final VoltLogger SNAP_LOG = new VoltLogger("SNAPSHOT");
private final SnapshotWritePlan m_plan;
private final Callable<Boolean> m_deferredSetup;
private final long m_txnId;
private final Map<Integer, Long> m_partitionTransactionIds;
private volatile Exception m_error = null;
public DeferredSnapshotSetup(SnapshotWritePlan plan, Callable<Boolean> deferredSetup, long txnId,
final Map<Integer, Long> partitionTransactionIds)
{
m_plan = plan;
m_deferredSetup = deferredSetup;
m_txnId = txnId;
m_partitionTransactionIds = ImmutableMap.copyOf(partitionTransactionIds);
}
public SnapshotWritePlan getPlan()
{
return m_plan;
}
public Exception getError()
{
return m_error;
}
@Override
public DeferredSnapshotSetup call() throws Exception
{
if (m_deferredSetup != null) {
try {
m_deferredSetup.call();
} catch (Exception e) {
m_error = e;
SNAP_LOG.error("Failed to run deferred snapshot setup", e);
// Data target creation failed, close all created ones and replace them with DevNull.
m_plan.createAllDevNullTargets();
}
}
/*
* Inform the SnapshotCompletionMonitor of what the partition specific txnids for
* this snapshot were so it can forward that to completion interests.
*/
VoltDB.instance().getSnapshotCompletionMonitor().registerPartitionTxnIdsForSnapshot(
m_txnId, m_partitionTransactionIds);
// Provide the truncation request ID so the monitor can recognize a specific snapshot.
logSnapshotStartToZK(m_txnId);
return this;
}
private static void logSnapshotStartToZK(long txnId) {
/*
* Going to send out the requests async to make snapshot init move faster
*/
ZKUtil.StringCallback cb1 = new ZKUtil.StringCallback();
/*
* Log that we are currently snapshotting this snapshot
*/
try {
//This node shouldn't already exist... should have been erased when the last snapshot finished
assert(VoltDB.instance().getHostMessenger().getZK().exists(
VoltZK.nodes_currently_snapshotting + "/" + VoltDB.instance().getHostMessenger().getHostId(), false)
== null);
ByteBuffer snapshotTxnId = ByteBuffer.allocate(8);
snapshotTxnId.putLong(txnId);
VoltDB.instance().getHostMessenger().getZK().create(
VoltZK.nodes_currently_snapshotting + "/" + VoltDB.instance().getHostMessenger().getHostId(),
snapshotTxnId.array(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, cb1, null);
} catch (KeeperException.NodeExistsException e) {
SNAP_LOG.warn("Didn't expect the snapshot node to already exist", e);
} catch (Exception e) {
VoltDB.crashLocalVoltDB(e.getMessage(), true, e);
}
try {
cb1.get();
} catch (KeeperException.NodeExistsException e) {
SNAP_LOG.warn("Didn't expect the snapshot node to already exist", e);
} catch (Exception e) {
VoltDB.crashLocalVoltDB(e.getMessage(), true, e);
}
}
}