package org.voltdb.sysprocs; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.voltdb.DependencySet; import org.voltdb.ParameterSet; import org.voltdb.ProcInfo; import org.voltdb.VoltSystemProcedure; import org.voltdb.VoltTable; import org.voltdb.VoltTable.ColumnInfo; import org.voltdb.VoltType; import org.voltdb.exceptions.ServerFaultException; import org.voltdb.types.TimestampType; import edu.brown.hstore.PartitionExecutor; import edu.brown.hstore.conf.HStoreConf; import edu.brown.logging.LoggerUtil.LoggerBoolean; import edu.brown.utils.CollectionUtil; import edu.brown.utils.StringUtil; /** * Set HStoreConf parameters throughout the cluster * Note that this is not persistent. */ @ProcInfo(singlePartition = false) public class SetConfiguration extends VoltSystemProcedure { private static final Logger LOG = Logger.getLogger(SetConfiguration.class); private static final LoggerBoolean debug = new LoggerBoolean(); public static final ColumnInfo nodeResultsColumns[] = { new ColumnInfo("SITE", VoltType.INTEGER), new ColumnInfo("CONF_NAME", VoltType.STRING), new ColumnInfo("CONF_VALUE", VoltType.STRING), }; public static final ColumnInfo aggregateResultsColumns[] = { new ColumnInfo("CONF_NAME", VoltType.STRING), new ColumnInfo("CONF_VALUE", VoltType.STRING), new ColumnInfo("UPDATED", VoltType.TIMESTAMP), }; private static final int DISTRIBUTE_ID = SysProcFragmentId.PF_setConfDistribute; private static final int AGGREGATE_ID = SysProcFragmentId.PF_setConfAggregate; @Override public void initImpl() { executor.registerPlanFragment(AGGREGATE_ID, this); executor.registerPlanFragment(DISTRIBUTE_ID, this); } @Override public DependencySet executePlanFragment(Long txn_id, Map<Integer, List<VoltTable>> dependencies, int fragmentId, ParameterSet params, PartitionExecutor.SystemProcedureExecutionContext context) { DependencySet result = null; assert(params.size() == 2); String confNames[] = (String[])params.toArray()[0]; String confValues[] = (String[])params.toArray()[1]; switch (fragmentId) { case DISTRIBUTE_ID: { HStoreConf hstore_conf = executor.getHStoreConf(); assert(hstore_conf != null); // Put the conf name+value pairs into a map and shove that to // the HStoreConf. It will know how to process them and convert // the string values into the proper types Map<String, String> m = new HashMap<String, String>(); for (int i = 0; i < confNames.length; i++) { m.put(confNames[i], confValues[i]); } // FOR hstore_conf.loadFromArgs(m); if (debug.val) LOG.debug(String.format("Updating %d conf parameters on %s", m.size(), executor.getHStoreSite().getSiteName())); // Update our local HStoreSite context.getHStoreSite().updateConf(hstore_conf, confNames); // Create the result table VoltTable vt = new VoltTable(nodeResultsColumns); for (int i = 0; i < confNames.length; i++) { Object row[] = { executor.getSiteId(), confNames[i], hstore_conf.get(confNames[i]).toString(), }; vt.addRow(row); } // FOR result = new DependencySet(DISTRIBUTE_ID, vt); if (debug.val) LOG.info(String.format("%s - Sending back result for partition %d", hstore_site.getTransaction(txn_id), this.executor.getPartitionId())); break; } // Aggregate Results case AGGREGATE_ID: List<VoltTable> siteResults = dependencies.get(DISTRIBUTE_ID); if (siteResults == null || siteResults.isEmpty()) { String msg = "Missing site results"; throw new ServerFaultException(msg, txn_id); } if (debug.val) LOG.debug("# of Results: " + siteResults.size() + "\n" + StringUtil.join("\n************\n", siteResults)); // Make sure that everyone is the same value VoltTable vt = new VoltTable(aggregateResultsColumns); TimestampType timestamp = new TimestampType(); Set<String> values = new HashSet<String>(); for (int i = 0; i < confNames.length; i++) { if (i > 0) values.clear(); for (VoltTable site_vt : siteResults) { if (i > 0) site_vt.resetRowPosition(); while (site_vt.advanceRow()) { if (site_vt.getString(1).equalsIgnoreCase(confNames[i])) { values.add(site_vt.getString(2)); break; } } // WHILE } // FOR (site results) if (values.isEmpty()) { String msg = "Failed to find updated configuration values for '" + confNames[i] + "'"; throw new VoltAbortException(msg); } else if (values.size() > 1) { String msg = String.format("Unexpected multiple values for '%s': %s", confNames[i], values); throw new VoltAbortException(msg); } vt.addRow(confNames[i], CollectionUtil.first(values).toString(), timestamp); } // FOR result = new DependencySet(AGGREGATE_ID, vt); break; default: String msg = "Unexpected sysproc fragmentId '" + fragmentId + "'"; throw new ServerFaultException(msg, txn_id); } // SWITCH // Invalid! return (result); } public VoltTable[] run(String confNames[], String confValues[]) { if (confNames.length != confValues.length) { String msg = String.format("The number of conf names and values are not equal [%d != %d]", confNames.length, confValues.length); throw new VoltAbortException(msg); } HStoreConf hstore_conf = executor.getHStoreConf(); for (int i = 0; i < confNames.length; i++) { if (hstore_conf.hasParameter(confNames[i]) == false) { String msg = String.format("Invalid configuration parameter '%s'", confNames[i]); throw new VoltAbortException(msg); } } // FOR ParameterSet params = new ParameterSet(confNames, confValues); return this.executeOncePerSite(DISTRIBUTE_ID, AGGREGATE_ID, params); } }