/* * Copyright (c) 2011-2015 EPFL DATA Laboratory * Copyright (c) 2014-2015 The Squall Collaboration (see NOTICE) * * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ch.epfl.data.squall.utilities; import java.util.List; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.HashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import java.io.IOException; import ch.epfl.data.squall.query_plans.QueryBuilder; import ch.epfl.data.squall.storage.BasicStore; import ch.epfl.data.squall.utilities.StormWrapper; import ch.epfl.data.squall.utilities.ReaderProvider; import ch.epfl.data.squall.components.DataSourceComponent; import ch.epfl.data.squall.operators.StoreOperator; import backtype.storm.generated.Nimbus.Client; import backtype.storm.generated.ClusterSummary; import backtype.storm.generated.TopologySummary; import backtype.storm.generated.TopologyInfo; import backtype.storm.generated.NotAliveException; import org.apache.log4j.Logger; import backtype.storm.Config; /* This class represents a context of execution. It provides a unified * interface for creating and submitting plans or running queries. */ public class SquallContext { private static Logger LOG = Logger.getLogger(SquallContext.class); private Config conf; private boolean local; private List<ReaderProvider> readerProviders; public SquallContext() { this(new Config()); Map stormConf = backtype.storm.utils.Utils.readStormConfig(); conf.putAll(stormConf); // Load default values SystemParameters.putInMap(conf, "DIP_EXTENSION", ".tbl"); SystemParameters.putInMap(conf, "DIP_READ_SPLIT_DELIMITER", "\\|"); SystemParameters.putInMap(conf, "DIP_GLOBAL_ADD_DELIMITER", "|"); SystemParameters.putInMap(conf, "DIP_GLOBAL_SPLIT_DELIMITER", "\\|"); SystemParameters.putInMap(conf, "DIP_KILL_AT_THE_END", "true"); SystemParameters.putInMap(conf, "STORAGE_LOCAL_DIR", "/tmp/ramdisk"); SystemParameters.putInMap(conf, "STORAGE_CLUSTER_DIR", "/data/squall_zone/storage"); SystemParameters.putInMap(conf, "STORAGE_COLD_START", "true"); SystemParameters.putInMap(conf, "STORAGE_MEMORY_SIZE_MB", "4096"); SystemParameters.putInMap(conf, "DIP_NUM_ACKERS", 0); // TODO: load "local" from the configuration } public SquallContext(Config conf) { this.conf = conf; this.readerProviders = new ArrayList<ReaderProvider>(2); this.registerReaderProvider(new FileReaderProvider(".")); this.registerReaderProvider(new FileReaderProvider("../test/data/tpch/0.01G/")); this.registerReaderProvider(new FileReaderProvider("./test/data/tpch/0.01G/")); // TODO: there should be a different provider for distributed mode this.registerReaderProvider(new FileReaderProvider("/data/tpch/0.01G/")); } @Deprecated public Config getConfiguration() { return conf; } public void submit(String name, QueryBuilder plan) { if (local) { submitLocal(name, plan); } else { submitDistributed(name, plan); } } public BasicStore<Object> submitLocalAndWait(String name, QueryBuilder plan) throws InterruptedException { setLocal(); // TODO: name should be given in the plan somehow, as it is a property of // the query SystemParameters.putInMap(conf, "DIP_QUERY_NAME", name); SystemParameters.putInMap(conf, "DIP_TOPOLOGY_NAME", name); SystemParameters.putInMap(conf, "DIP_KILL_AT_THE_END", "true"); // TODO: use parallelisms that were already set // TODO: take the parallelism from the component setAllParallelisms(plan); return StormWrapper.localSubmitAndWait(this, plan); } public Map<String,String> submitLocal(String name, QueryBuilder plan) { setLocal(); // TODO: name should be given in the plan somehow, as it is a property of // the query SystemParameters.putInMap(conf, "DIP_QUERY_NAME", name); SystemParameters.putInMap(conf, "DIP_TOPOLOGY_NAME", name); SystemParameters.putInMap(conf, "DIP_KILL_AT_THE_END", "false"); // TODO: use parallelisms that were already set // TODO: take the parallelism from the component setAllParallelisms(plan); StoreOperator storeOperator = new StoreOperator(); plan.getLastComponent().getChainOperator().addOperator(storeOperator); StormWrapper.submitTopology(this, plan.createTopology(this)); return storeOperator.getStore(); } public void submitDistributed(String name, QueryBuilder plan) { setDistributed(); // TODO: name should be given in the plan somehow, as it is a property of // the query SystemParameters.putInMap(conf, "DIP_QUERY_NAME", name); SystemParameters.putInMap(conf, "DIP_TOPOLOGY_NAME", name); SystemParameters.putInMap(conf, "DIP_KILL_AT_THE_END", "true"); // TODO: use parallelisms that were already set // TODO: take the parallelism from the component setAllParallelisms(plan); StormWrapper.submitTopology(this, plan.createTopology(this)); } private void setAllParallelisms(QueryBuilder plan) { for (String componentName: plan.getComponentNames()) { SystemParameters.putInMap(conf, componentName + "_PAR", "1"); } } public void setLocal() { SystemParameters.putInMap(conf, "storm.cluster.mode", "local"); SystemParameters.putInMap(conf, "DIP_DISTRIBUTED", "false"); SystemParameters.putInMap(conf, "DIP_DATA_PATH", "../test/data/tpch/0.01G/"); local = true; } public void setDistributed() { SystemParameters.putInMap(conf, "storm.cluster.mode", "distributed"); SystemParameters.putInMap(conf, "DIP_DISTRIBUTED", "true"); SystemParameters.putInMap(conf, "DIP_DATA_PATH", "/data/tpch/0.01G/"); local = false; } public boolean isLocal() { return local; } public boolean isDistributed() { return !local; } public void registerReaderProvider(ReaderProvider provider) { readerProviders.add(0, provider); } public ReaderProvider getProviderFor(String resource) { ReaderProvider provider = null; Iterator<ReaderProvider> iterator = readerProviders.iterator(); while (iterator.hasNext() && provider == null) { ReaderProvider next = iterator.next(); if (next.canProvide(this, resource)) { provider = next; } } return provider; } public DataSourceComponent createDataSource(String table) throws IOException { String resource = table + SystemParameters.getString(conf, "DIP_EXTENSION"); ReaderProvider provider = getProviderFor(resource); if (provider == null) { provider = getProviderFor(table); if (provider != null) { resource = table; } } if (provider == null) { String error = "Could not find table '" + table + "'. Registered providers in search order:\n"; for(ReaderProvider p : readerProviders) { error = error + "\t" + p + "\n"; } throw new IOException(error); } return new DataSourceComponent(table, provider, resource); } public ClusterSummary getStormClusterSummary() { return StormWrapper.getClusterInfo(isLocal(), conf); } public List<String> getQueries() { ClusterSummary cluster = getStormClusterSummary(); List<String> result = new ArrayList(); for (TopologySummary topology : cluster.get_topologies()) { result.add(topology.get_name()); } return result; } public void killQuery(String name) { try { StormWrapper.killTopology(isLocal(), conf, name); } catch (NotAliveException e) { LOG.warn("Tried to kill topology '" + name + "' but it was not running."); } } private String getTopologyIdFromName(String name) { ClusterSummary cluster = getStormClusterSummary(); String id = null; for (TopologySummary topology : cluster.get_topologies()) { if (topology.get_id().startsWith(name)) { id = topology.get_id(); } } return id; } public String getQueryStatus(String name) { try { String id = getTopologyIdFromName(name); if (id != null) { TopologyInfo topology = StormWrapper.getTopology(isLocal(), conf, id); return topology.get_status(); } else { return null; } } catch (NotAliveException e) { LOG.warn("Tried to get status for topology '" + name + "' but it was not running."); return null; } } public void setDbtoasterClassDir(String classdir) { SystemParameters.putInMap(conf, "squall.dbtoaster.classdir", classdir); } }