/***************************************************************************
* Copyright (C) 2011 by H-Store Project *
* Brown University *
* Massachusetts Institute of Technology *
* Yale University *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
***************************************************************************/
package edu.brown.hstore;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.apache.log4j.Logger;
import org.voltdb.BackendTarget;
import org.voltdb.CatalogContext;
import org.voltdb.ProcedureProfiler;
import org.voltdb.TheHashinator;
import org.voltdb.catalog.Database;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.hstore.estimators.TransactionEstimator;
import edu.brown.hstore.estimators.fixed.AbstractFixedEstimator;
import edu.brown.hstore.estimators.markov.MarkovEstimator;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.mappings.ParameterMappingsSet;
import edu.brown.markov.MarkovUtil;
import edu.brown.markov.containers.MarkovGraphsContainerUtil;
import edu.brown.markov.containers.MarkovGraphsContainer;
import edu.brown.utils.ArgumentsParser;
import edu.brown.utils.ClassUtil;
import edu.brown.utils.PartitionEstimator;
import edu.brown.utils.StringBoxUtil;
import edu.brown.utils.ThreadUtil;
import edu.brown.workload.Workload;
/**
* Main Wrapper Class for an HStoreSite
* @author pavlo
*/
public abstract class HStore {
private static final Logger LOG = Logger.getLogger(HStore.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.setupLogging();
LoggerUtil.attachObserver(LOG, debug, trace);
}
private static HStoreSite singleton;
private static String buildString;
private static String versionString;
private static boolean m_ariesRecovery;
/**
* Retrieve a reference to the main HStoreSite running in this JVM.
* When running a real server (and not a test harness), this instance will only
* be useful after calling HStore.initialize().
*
* @return A reference to the underlying HStoreSite object.
*/
public static final HStoreSite instance() {
return singleton;
}
/**
* Exit the process, dumping any useful info and notifying any
* important parties beforehand.
*
* For now, just die.
*/
public static void crashDB() {
// if (HStore.instance().ignoreCrash()) {
// return;
// }
Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
StackTraceElement[] myTrace = traces.get(Thread.currentThread());
for (StackTraceElement t : myTrace) {
System.err.println(t.toString());
}
HStoreSite handle = instance();
if (handle != null) {
handle.shutdown();
System.exit(-1);
// FIXME handle.getHStoreCoordinator().shutdownCluster();
} else {
System.err.println("H-Store has encountered an unrecoverable error and is exiting.");
System.err.println("The log may contain additional information.");
System.exit(-1);
}
}
/**
* Initialize the HStore server.
*/
public synchronized static final HStoreSite initialize(CatalogContext catalogContext, int site_id, HStoreConf hstore_conf) {
singleton = new HStoreSite(site_id, catalogContext, hstore_conf);
// For every partition in our local site, we want to setup a new ExecutionSite
// Thankfully I had enough sense to have PartitionEstimator take in the local partition
// as a parameter, so we can share a single instance across all ExecutionSites
PartitionEstimator p_estimator = singleton.getPartitionEstimator();
// ----------------------------------------------------------------------------
// MarkovGraphs
// ----------------------------------------------------------------------------
Map<Integer, MarkovGraphsContainer> markovs = null;
if (hstore_conf.site.markov_path != null) {
File path = new File(hstore_conf.site.markov_path);
if (path.exists()) {
long start = System.currentTimeMillis();
try {
markovs = MarkovGraphsContainerUtil.loadIds(catalogContext, path,
singleton.getLocalPartitionIds());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
MarkovGraphsContainerUtil.setHasher(markovs, singleton.getPartitionEstimator().getHasher());
long load_time = System.currentTimeMillis() - start;
LOG.info(String.format("Finished loading %s '%s' in %.1f sec",
MarkovGraphsContainer.class.getSimpleName(), path, (load_time / 1000d)));
} else if (debug.val) LOG.warn("The Markov Graphs file '" + path + "' does not exist");
ThreadUtil.shutdownGlobalPool(); // HACK
}
// ----------------------------------------------------------------------------
// ParameterMappings
// ----------------------------------------------------------------------------
ParameterMappingsSet mappings = new ParameterMappingsSet();
if (hstore_conf.site.mappings_path != null) {
File path = new File(hstore_conf.site.mappings_path);
if (path.exists()) {
Database catalog_db = catalogContext.database;
try {
mappings.load(path, catalog_db);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
} else if (debug.val) LOG.warn("The ParameterMappings file '" + path + "' does not exist");
}
// ----------------------------------------------------------------------------
// PartitionExecutor Initialization
// ----------------------------------------------------------------------------
boolean first = true;
for (int local_partition : singleton.getLocalPartitionIds().values()) {
MarkovGraphsContainer local_markovs = null;
if (markovs != null) {
if (markovs.containsKey(MarkovUtil.GLOBAL_MARKOV_CONTAINER_ID)) {
local_markovs = markovs.get(MarkovUtil.GLOBAL_MARKOV_CONTAINER_ID);
} else {
local_markovs = markovs.get(local_partition);
}
assert(local_markovs != null) :
"Failed to retrieve MarkovGraphsContainer for partition #" + local_partition;
}
// Initialize TransactionEstimator stuff
// Load the Markov models if we were given an input path and pass them to t_estimator
// Load in all the partition-specific TransactionEstimators and ExecutionSites in order to
// stick them into the HStoreSite
if (debug.val)
LOG.debug(String.format("Creating %s for %s",
TransactionEstimator.class.getSimpleName(), singleton.getSiteName()));
TransactionEstimator t_estimator = null;
if (hstore_conf.site.markov_enable) {
if (hstore_conf.site.markov_fixed == false && markovs != null) {
t_estimator = new MarkovEstimator(catalogContext, p_estimator, local_markovs);
} else if (hstore_conf.site.markov_fixed) {
t_estimator = AbstractFixedEstimator.factory(p_estimator, singleton.getCatalogContext());
}
}
if (first && t_estimator != null)
LOG.info(String.format("All incoming txn requests will be processed with %s at this site",
t_estimator.getClass().getSimpleName()));
// setup the EE
if (debug.val)
LOG.debug(String.format("Creating %s for Partition #%02d",
PartitionExecutor.class.getSimpleName(), local_partition));
PartitionExecutor executor = new PartitionExecutor(
local_partition,
singleton.getCatalogContext(),
BackendTarget.NATIVE_EE_JNI, // BackendTarget.NULL,
p_estimator,
t_estimator);
singleton.addPartitionExecutor(local_partition, executor);
first = false;
} // FOR
TheHashinator.initialize(catalogContext.catalog);
return (singleton);
}
/**
* Main Start-up Method
* @param vargs
* @throws Exception
*/
public static void main(String[] vargs) throws Exception {
if (ClassUtil.isAssertsEnabled()) {
LOG.warn("\n" + HStore.getAssertWarning());
}
ArgumentsParser args = ArgumentsParser.load(vargs,
ArgumentsParser.PARAM_CATALOG,
ArgumentsParser.PARAM_SITE_ID,
ArgumentsParser.PARAM_CONF
);
// HStoreSite Stuff
final int site_id = args.getIntParam(ArgumentsParser.PARAM_SITE_ID);
Thread t = Thread.currentThread();
t.setName(HStoreThreadManager.getThreadName(site_id, null, "main"));
HStoreConf hstore_conf = HStoreConf.initArgumentsParser(args);
if (debug.val)
LOG.debug("HStoreConf Parameters:\n" + HStoreConf.singleton().toString(true));
HStoreSite hstore_site = HStore.initialize(args.catalogContext, site_id, hstore_conf);
// ----------------------------------------------------------------------------
// Workload Trace Output
// ----------------------------------------------------------------------------
if (args.hasParam(ArgumentsParser.PARAM_WORKLOAD_OUTPUT)) {
ProcedureProfiler.profilingLevel = ProcedureProfiler.Level.INTRUSIVE;
String traceClass = Workload.class.getName();
String tracePath = args.getParam(ArgumentsParser.PARAM_WORKLOAD_OUTPUT) + "-" + site_id;
String traceIgnore = args.getParam(ArgumentsParser.PARAM_WORKLOAD_PROC_EXCLUDE);
ProcedureProfiler.initializeWorkloadTrace(args.catalog, traceClass, tracePath, traceIgnore);
LOG.info("Enabled workload logging '" + tracePath + "'");
}
if (args.thresholds != null) hstore_site.setThresholds(args.thresholds);
// ----------------------------------------------------------------------------
// Bombs Away!
// ----------------------------------------------------------------------------
if (debug.val)
LOG.debug("Instantiating HStoreSite network connections for " + hstore_site.getSiteName());
hstore_site.run();
}
public static String getAssertWarning() {
String url = HStoreConstants.HSTORE_WEBSITE + "/documentation/deployment/client-configuration";
String msg = "!!! WARNING !!!\n" +
"H-Store is executing with JVM asserts enabled. This will degrade runtime performance.\n" +
"You can disable them by setting the config option 'site.jvm_asserts' to FALSE\n" +
"See the online documentation for more information:\n " + url;
return StringBoxUtil.heavyBox(msg);
}
public static String getBuildString() {
if (buildString == null) {
synchronized (HStore.class) {
if (buildString == null) readBuildInfo();
} // SYNCH
}
return (buildString);
}
public static String getVersionString() {
if (versionString == null) {
synchronized (HStore.class) {
if (versionString == null) readBuildInfo();
} // SYNCH
}
return (versionString);
}
private static void readBuildInfo() {
StringBuilder sb = new StringBuilder(64);
byte b = -1;
try {
InputStream buildstringStream =
ClassLoader.getSystemResourceAsStream("buildstring.txt");
while ((b = (byte) buildstringStream.read()) != -1) {
sb.append((char)b);
}
sb.append("\n");
String parts[] = sb.toString().split(" ", 2);
if (parts.length != 2) {
throw new RuntimeException("Invalid buildstring.txt file.");
}
versionString = parts[0].trim();
buildString = parts[1].trim();
} catch (Exception ignored) {
try {
InputStream buildstringStream = new FileInputStream("version.txt");
while ((b = (byte) buildstringStream.read()) != -1) {
sb.append((char)b);
}
versionString = sb.toString().trim();
}
catch (Exception ignored2) {
throw new RuntimeException(ignored);
}
} finally {
if (buildString == null) buildString = "H-Store";
}
LOG.debug("Build: " + versionString + " " + buildString);
}
}