/* 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.sysprocs; import java.util.List; import java.util.Map; import org.apache.zookeeper_voltpatches.KeeperException.BadVersionException; import org.apache.zookeeper_voltpatches.KeeperException.Code; import org.apache.zookeeper_voltpatches.ZooKeeper; import org.apache.zookeeper_voltpatches.data.Stat; import org.voltcore.logging.VoltLogger; import org.voltdb.DependencyPair; import org.voltdb.OperationMode; import org.voltdb.ParameterSet; import org.voltdb.ProcInfo; import org.voltdb.SystemProcedureExecutionContext; import org.voltdb.VoltDB; import org.voltdb.VoltDBInterface; import org.voltdb.VoltSystemProcedure; import org.voltdb.VoltTable; import org.voltdb.VoltZK; import org.voltdb.snmp.SnmpTrapSender; @ProcInfo(singlePartition = false) public class Pause extends VoltSystemProcedure { private final static VoltLogger LOG = new VoltLogger("HOST"); protected volatile Stat m_stat = null; private final static OperationMode PAUSED = OperationMode.PAUSED; @Override public long[] getPlanFragmentIds() { return new long[]{}; } @Override public DependencyPair executePlanFragment( Map<Integer, List<VoltTable>> dependencies, long fragmentId, ParameterSet params, SystemProcedureExecutionContext context) { throw new RuntimeException("Pause was given an " + "invalid fragment id: " + String.valueOf(fragmentId)); } protected static String ll(long l) { return Long.toString(l, Character.MAX_RADIX); } /** * Enter admin mode * @param ctx Internal parameter. Not user-accessible. * @return Standard STATUS table. */ public VoltTable[] run(SystemProcedureExecutionContext ctx) { // Choose the lowest site ID on this host to actually flip the bit if (ctx.isLowestSiteId()) { VoltDBInterface voltdb = VoltDB.instance(); OperationMode opMode = voltdb.getMode(); if (LOG.isDebugEnabled()) { LOG.debug("voltdb opmode is " + opMode); } ZooKeeper zk = voltdb.getHostMessenger().getZK(); try { Stat stat; OperationMode zkMode = null; Code code; do { stat = new Stat(); code = Code.BADVERSION; try { byte [] data = zk.getData(VoltZK.operationMode, false, stat); if (LOG.isDebugEnabled()) { LOG.debug("zkMode is " + (zkMode == null ? "(null)" : OperationMode.valueOf(data))); } zkMode = data == null ? opMode : OperationMode.valueOf(data); if (zkMode == PAUSED) { if (LOG.isDebugEnabled()) { LOG.debug("read node at version " + stat.getVersion() + ", txn " + ll(stat.getMzxid())); } break; } stat = zk.setData(VoltZK.operationMode, PAUSED.getBytes(), stat.getVersion()); code = Code.OK; zkMode = PAUSED; if (LOG.isDebugEnabled()) { LOG.debug("!WROTE! node at version " + stat.getVersion() + ", txn " + ll(stat.getMzxid())); } break; } catch (BadVersionException ex) { code = ex.code(); } } while (zkMode != PAUSED && code == Code.BADVERSION); m_stat = stat; voltdb.getHostMessenger().pause(); voltdb.setMode(PAUSED); // for snmp SnmpTrapSender snmp = voltdb.getSnmpTrapSender(); if (snmp != null) { snmp.pause("Cluster paused."); } } catch (Exception e) { throw new RuntimeException(e); } } // Force a tick so that stats will be updated. // Primarily added to get latest table stats for DR pause and empty db check. ctx.getSiteProcedureConnection().tick(); VoltTable t = new VoltTable(VoltSystemProcedure.STATUS_SCHEMA); t.addRow(VoltSystemProcedure.STATUS_OK); return (new VoltTable[] {t}); } }