/* 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;
import org.apache.zookeeper_voltpatches.ZooKeeper;
import org.apache.zookeeper_voltpatches.data.Stat;
import org.voltcore.logging.VoltLogger;
import org.voltcore.messaging.HostMessenger;
import org.voltcore.utils.CoreUtils;
import org.voltcore.utils.Pair;
import org.voltdb.CatalogContext;
import org.voltdb.CatalogSpecificPlanner;
import org.voltdb.DependencyPair;
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.VoltTable.ColumnInfo;
import org.voltdb.VoltType;
import org.voltdb.VoltZK;
import org.voltdb.dtxn.DtxnConstants;
import org.voltdb.settings.ClusterSettings;
import org.voltdb.settings.SettingsException;
import org.voltdb.utils.VoltTableUtil;
@ProcInfo(singlePartition = false)
public class UpdateSettings extends VoltSystemProcedure {
private static final int DEP_updateSettingsBarrier = (int)
SysProcFragmentId.PF_updateSettingsBarrier | DtxnConstants.MULTIPARTITION_DEPENDENCY;
private static final int DEP_updateSettingsBarrierAggregate = (int)
SysProcFragmentId.PF_updateSettingsBarrierAggregate;
private static final int DEP_updateSettings = (int)
SysProcFragmentId.PF_updateSettings | DtxnConstants.MULTIPARTITION_DEPENDENCY;
private static final int DEP_updateSettingsAggregate = (int)
SysProcFragmentId.PF_updateSettingsAggregate;
private final static VoltLogger log = new VoltLogger("HOST");
@Override
public long[] getPlanFragmentIds() {
return new long[]{
SysProcFragmentId.PF_updateSettingsBarrier,
SysProcFragmentId.PF_updateSettingsBarrierAggregate,
SysProcFragmentId.PF_updateSettings,
SysProcFragmentId.PF_updateSettingsAggregate
};
}
public UpdateSettings() {
}
private VoltDBInterface getVoltDB() {
return VoltDB.instance();
}
private HostMessenger getHostMessenger() {
return VoltDB.instance().getHostMessenger();
}
private VoltTable getVersionResponse(int version) {
VoltTable table = new VoltTable(new ColumnInfo[] { new ColumnInfo("VERSION", VoltType.INTEGER) });
table.addRow(version);
return table;
}
@Override
public DependencyPair executePlanFragment(
Map<Integer, List<VoltTable>> dependencies, long fragmentId,
ParameterSet params, SystemProcedureExecutionContext context) {
if (fragmentId == SysProcFragmentId.PF_updateSettingsBarrier) {
DependencyPair success = new DependencyPair.TableDependencyPair(DEP_updateSettingsBarrier,
new VoltTable(new ColumnInfo[] { new ColumnInfo("UNUSED", VoltType.BIGINT) } ));
if (log.isInfoEnabled()) {
log.info("Site " + CoreUtils.hsIdToString(m_site.getCorrespondingSiteId()) +
" reached settings update barrier.");
}
return success;
} else if (fragmentId == SysProcFragmentId.PF_updateSettingsBarrierAggregate) {
Object [] paramarr = params.toArray();
byte [] settingsBytes = (byte[])paramarr[0];
int version = ((Integer)paramarr[1]).intValue();
ZooKeeper zk = getHostMessenger().getZK();
Stat stat = null;
try {
stat = zk.setData(VoltZK.cluster_settings, settingsBytes, version);
} catch (KeeperException | InterruptedException e) {
String msg = "Failed to update cluster settings";
log.error(msg,e);
throw new SettingsException(msg, e);
}
log.info("Saved new cluster settings state");
return new DependencyPair.TableDependencyPair(DEP_updateSettingsBarrierAggregate,
getVersionResponse(stat.getVersion()));
} else if (fragmentId == SysProcFragmentId.PF_updateSettings) {
Object [] paramarr = params.toArray();
byte [] settingsBytes = (byte[])paramarr[0];
int version = ((Integer)paramarr[1]).intValue();
ClusterSettings settings = ClusterSettings.create(settingsBytes);
Pair<CatalogContext, CatalogSpecificPlanner> ctgdef =
getVoltDB().settingsUpdate(settings, version);
context.updateSettings(ctgdef.getFirst(), ctgdef.getSecond());
VoltTable result = new VoltTable(VoltSystemProcedure.STATUS_SCHEMA);
result.addRow(VoltSystemProcedure.STATUS_OK);
return new DependencyPair.TableDependencyPair(DEP_updateSettings, result);
} else if (fragmentId == SysProcFragmentId.PF_updateSettingsAggregate) {
VoltTable result = VoltTableUtil.unionTables(dependencies.get(DEP_updateSettings));
return new DependencyPair.TableDependencyPair(DEP_updateSettingsAggregate, result);
} else {
VoltDB.crashLocalVoltDB(
"Received unrecognized plan fragment id " + fragmentId + " in UpdateSettings",
false,
null);
}
throw new RuntimeException("Should not reach this code");
}
private SynthesizedPlanFragment[] createBarrierFragment(byte[] settingsBytes, int version) {
SynthesizedPlanFragment pfs[] = new SynthesizedPlanFragment[2];
pfs[0] = new SynthesizedPlanFragment();
pfs[0].fragmentId = SysProcFragmentId.PF_updateSettingsBarrier;
pfs[0].outputDepId = DEP_updateSettingsBarrier;
pfs[0].inputDepIds = new int[]{};
pfs[0].multipartition = true;
pfs[0].parameters = ParameterSet.emptyParameterSet();
pfs[1] = new SynthesizedPlanFragment();
pfs[1].fragmentId = SysProcFragmentId.PF_updateSettingsBarrierAggregate;
pfs[1].outputDepId = DEP_updateSettingsBarrierAggregate;
pfs[1].inputDepIds = new int[] {DEP_updateSettingsBarrier};
pfs[1].multipartition = false;
pfs[1].parameters = ParameterSet.fromArrayNoCopy(new Object[] { settingsBytes, version });
return pfs;
}
private SynthesizedPlanFragment[] createUpdateFragment(byte[] settingsBytes, int version) {
SynthesizedPlanFragment pfs[] = new SynthesizedPlanFragment[2];
pfs[0] = new SynthesizedPlanFragment();
pfs[0].fragmentId = SysProcFragmentId.PF_updateSettings;
pfs[0].outputDepId = DEP_updateSettings;
pfs[0].inputDepIds = new int[]{};
pfs[0].multipartition = true;
pfs[0].parameters = ParameterSet.fromArrayNoCopy(new Object[] { settingsBytes, version });
pfs[1] = new SynthesizedPlanFragment();
pfs[1].fragmentId = SysProcFragmentId.PF_updateSettingsAggregate;
pfs[1].outputDepId = DEP_updateSettingsAggregate;
pfs[1].inputDepIds = new int[] {DEP_updateSettings};
pfs[1].multipartition = false;
pfs[1].parameters = ParameterSet.emptyParameterSet();
return pfs;
}
public VoltTable[] run(SystemProcedureExecutionContext ctx, byte[] settingsBytes) {
ZooKeeper zk = getHostMessenger().getZK();
Stat stat = null;
try {
stat = zk.exists(VoltZK.cluster_settings, false);
} catch (KeeperException | InterruptedException e) {
String msg = "Failed to stat cluster settings zookeeper node";
log.error(msg, e);
throw new VoltAbortException(msg);
}
final int version = stat.getVersion();
executeSysProcPlanFragments(
createBarrierFragment(settingsBytes, version), DEP_updateSettingsBarrierAggregate);
return executeSysProcPlanFragments(
createUpdateFragment(settingsBytes, version), DEP_updateSettingsAggregate);
}
}