DRILL-1163: Estimate memory and re-planning query + system options UI.
Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/ba027c7f Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/ba027c7f Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/ba027c7f Branch: refs/heads/master Commit: ba027c7f555782a0369aeffaeee1dd0bd60072df Parents: bb21263 Author: Sudheesh Katkam <skat...@maprtech.com> Authored: Tue Aug 12 22:37:44 2014 +0530 Committer: Aditya Kishore <adi...@maprtech.com> Committed: Mon Aug 18 14:56:51 2014 +0530 ---------------------------------------------------------------------- .../org/apache/drill/exec/ExecConstants.java | 33 +++++++ .../drill/exec/compile/QueryClassLoader.java | 25 +++-- .../apache/drill/exec/ops/FragmentContext.java | 26 +++--- .../org/apache/drill/exec/ops/QueryContext.java | 16 +++- .../apache/drill/exec/opt/BasicOptimizer.java | 15 ++- .../drill/exec/planner/cost/DrillCostBase.java | 33 +++++-- .../exec/planner/physical/HashAggPrel.java | 42 +++++---- .../exec/planner/physical/HashAggPrule.java | 10 +- .../exec/planner/physical/HashJoinPrel.java | 27 ++++-- .../exec/planner/physical/HashJoinPrule.java | 13 +-- .../exec/planner/physical/PlannerSettings.java | 8 ++ .../drill/exec/planner/physical/SortPrel.java | 21 +++-- .../visitor/MemoryEstimationVisitor.java | 66 +++++++++++++ .../planner/sql/handlers/DefaultSqlHandler.java | 33 +++++-- .../planner/sql/handlers/SetOptionHandler.java | 32 ++++--- .../apache/drill/exec/rpc/user/UserSession.java | 14 ++- .../server/options/FragmentOptionManager.java | 82 +++++++++++++++++ .../server/options/FragmentOptionsManager.java | 85 ----------------- .../exec/server/options/OptionManager.java | 4 +- .../drill/exec/server/options/OptionValue.java | 33 ++++++- .../exec/server/options/QueryOptionManager.java | 97 ++++++++++++++++++++ .../server/options/SessionOptionManager.java | 43 +++++---- .../server/options/SystemOptionManager.java | 36 ++++---- .../exec/server/options/TypeValidators.java | 30 +++++- .../drill/exec/server/rest/DrillRoot.java | 62 ++++++++++++- .../drill/exec/server/rest/StatusResources.java | 96 ++++++++++++++++++- .../apache/drill/exec/work/foreman/Foreman.java | 2 +- .../src/main/resources/rest/generic.ftl | 6 +- .../java-exec/src/main/resources/rest/index.ftl | 13 ++- .../src/main/resources/rest/options.ftl | 47 ++++++++++ .../src/main/resources/rest/status.ftl | 1 + .../java/org/apache/drill/PlanningBase.java | 29 +++--- 32 files changed, 802 insertions(+), 278 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java index f2a84ee..f018b78 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java @@ -23,6 +23,7 @@ import org.apache.drill.exec.server.options.TypeValidators.BooleanValidator; import org.apache.drill.exec.server.options.TypeValidators.DoubleValidator; import org.apache.drill.exec.server.options.TypeValidators.LongValidator; import org.apache.drill.exec.server.options.TypeValidators.PositiveLongValidator; +import org.apache.drill.exec.server.options.TypeValidators.PowerOfTwoLongValidator; import org.apache.drill.exec.server.options.TypeValidators.StringValidator; public interface ExecConstants { @@ -118,6 +119,38 @@ public interface ExecConstants { public static final String AFFINITY_FACTOR_KEY = "planner.affinity_factor"; public static final OptionValidator AFFINITY_FACTOR = new DoubleValidator(AFFINITY_FACTOR_KEY, 1.2d); + public static final String ENABLE_MEMORY_ESTIMATION_KEY = "planner.memory.enable_memory_estimation"; + public static final OptionValidator ENABLE_MEMORY_ESTIMATION = new BooleanValidator(ENABLE_MEMORY_ESTIMATION_KEY, false); + + /** + * Maximum query memory per node (in MB). Re-plan with cheaper operators if memory estimation exceeds this limit. + * <p/> + * DEFAULT: 2048 MB + */ + public static final String MAX_QUERY_MEMORY_PER_NODE_KEY = "planner.memory.max_query_memory_per_node"; + public static final OptionValidator MAX_QUERY_MEMORY_PER_NODE = new PowerOfTwoLongValidator( + MAX_QUERY_MEMORY_PER_NODE_KEY, Runtime.getRuntime().maxMemory(), 1 << 11); + + /** + * Extra query memory per node for non-blocking operators. + * NOTE: This option is currently used only for memory estimation. + * <p/> + * DEFAULT: 64 MB + * MAXIMUM: 2048 MB + */ + public static final String NON_BLOCKING_OPERATORS_MEMORY_KEY = "planner.memory.non_blocking_operators_memory"; + public static final OptionValidator NON_BLOCKING_OPERATORS_MEMORY = new PowerOfTwoLongValidator( + NON_BLOCKING_OPERATORS_MEMORY_KEY, 1 << 11, 1 << 6); + + public static final String HASH_JOIN_TABLE_FACTOR_KEY = "planner.memory.hash_join_table_factor"; + public static final OptionValidator HASH_JOIN_TABLE_FACTOR = new DoubleValidator(HASH_JOIN_TABLE_FACTOR_KEY, 1.1d); + + public static final String HASH_AGG_TABLE_FACTOR_KEY = "planner.memory.hash_agg_table_factor"; + public static final OptionValidator HASH_AGG_TABLE_FACTOR = new DoubleValidator(HASH_AGG_TABLE_FACTOR_KEY, 1.1d); + + public static final String AVERAGE_FIELD_WIDTH_KEY = "planner.memory.average_field_width"; + public static final OptionValidator AVERAGE_FIELD_WIDTH = new PositiveLongValidator(AVERAGE_FIELD_WIDTH_KEY, Long.MAX_VALUE, 8); + public static final String ENABLE_QUEUE_KEY = "exec.queue.enable"; public static final OptionValidator ENABLE_QUEUE = new BooleanValidator(ENABLE_QUEUE_KEY, false); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java index 8de14ec..2dcb52b 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java @@ -17,13 +17,7 @@ */ package org.apache.drill.exec.compile; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; - +import com.google.common.collect.MapMaker; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.ExpressionParsingException; import org.apache.drill.exec.compile.ClassTransformer.ClassNames; @@ -35,9 +29,13 @@ import org.apache.drill.exec.server.options.TypeValidators.BooleanValidator; import org.apache.drill.exec.server.options.TypeValidators.LongValidator; import org.apache.drill.exec.server.options.TypeValidators.StringValidator; import org.codehaus.commons.compiler.CompileException; -import org.eigenbase.sql.SqlLiteral; -import com.google.common.collect.MapMaker; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; public class QueryClassLoader extends URLClassLoader { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(QueryClassLoader.class); @@ -45,15 +43,14 @@ public class QueryClassLoader extends URLClassLoader { public static final String JAVA_COMPILER_OPTION = "exec.java_compiler"; public static final StringValidator JAVA_COMPILER_VALIDATOR = new StringValidator(JAVA_COMPILER_OPTION, CompilerPolicy.DEFAULT.toString()) { @Override - public OptionValue validate(SqlLiteral value) throws ExpressionParsingException { - OptionValue ov = super.validate(value); + public void validate(OptionValue v) throws ExpressionParsingException { + super.validate(v); try { - CompilerPolicy.valueOf(ov.string_val.toUpperCase()); + CompilerPolicy.valueOf(v.string_val.toUpperCase()); } catch (IllegalArgumentException e) { throw new ExpressionParsingException(String.format("Invalid value '%s' specified for option '%s'. Valid values are %s.", - ov.string_val, getOptionName(), Arrays.toString(CompilerPolicy.values()))); + v.string_val, getOptionName(), Arrays.toString(CompilerPolicy.values()))); } - return ov; } }; http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java index 0b8b88a..8a670fb 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java @@ -17,14 +17,10 @@ */ package org.apache.drill.exec.ops; -import java.io.Closeable; -import java.io.IOException; -import java.util.List; -import java.util.Map; - +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import net.hydromatic.optiq.SchemaPlus; import net.hydromatic.optiq.jdbc.SimpleOptiqSchema; - import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.ExecutionSetupException; import org.apache.drill.exec.compile.ClassTransformer; @@ -42,13 +38,15 @@ import org.apache.drill.exec.rpc.control.ControlTunnel; import org.apache.drill.exec.rpc.data.DataTunnel; import org.apache.drill.exec.rpc.user.UserServer.UserClientConnection; import org.apache.drill.exec.server.DrillbitContext; -import org.apache.drill.exec.server.options.FragmentOptionsManager; +import org.apache.drill.exec.server.options.FragmentOptionManager; import org.apache.drill.exec.server.options.OptionList; import org.apache.drill.exec.server.options.OptionManager; import org.apache.drill.exec.work.batch.IncomingBuffers; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; +import java.io.Closeable; +import java.io.IOException; +import java.util.List; +import java.util.Map; /** * Contextual objects required for execution of a particular fragment. @@ -71,7 +69,7 @@ public class FragmentContext implements Closeable { private IncomingBuffers buffers; private final long queryStartTime; private final int rootFragmentTimeZone; - private final OptionManager sessionOptions; + private final OptionManager fragmentOptions; private volatile Throwable failureCause; private volatile boolean failed = false; @@ -96,16 +94,16 @@ public class FragmentContext implements Closeable { }else{ list = dbContext.getConfig().getMapper().readValue(fragment.getOptionsJson(), OptionList.class); } - this.sessionOptions = new FragmentOptionsManager(context.getOptionManager(), list); + this.fragmentOptions = new FragmentOptionManager(context.getOptionManager(), list); }catch(Exception e){ throw new ExecutionSetupException("Failure while reading plan options.", e); } this.allocator = context.getAllocator().getChildAllocator(fragment.getHandle(), fragment.getMemInitial(), fragment.getMemMax()); - this.loader = new QueryClassLoader(dbContext.getConfig(), sessionOptions); + this.loader = new QueryClassLoader(dbContext.getConfig(), fragmentOptions); } - public OptionManager getOptions(){ - return sessionOptions; + public OptionManager getOptions() { + return fragmentOptions; } public void setBuffers(IncomingBuffers buffers) { http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/ops/QueryContext.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/QueryContext.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/QueryContext.java index 78e98fb..50d753f 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/QueryContext.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/QueryContext.java @@ -17,11 +17,8 @@ */ package org.apache.drill.exec.ops; -import java.util.Collection; - import net.hydromatic.optiq.SchemaPlus; import net.hydromatic.optiq.jdbc.SimpleOptiqSchema; - import org.apache.drill.common.config.DrillConfig; import org.apache.drill.exec.cache.DistributedCache; import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry; @@ -35,9 +32,12 @@ import org.apache.drill.exec.rpc.data.DataConnectionCreator; import org.apache.drill.exec.rpc.user.UserSession; import org.apache.drill.exec.server.DrillbitContext; import org.apache.drill.exec.server.options.OptionManager; +import org.apache.drill.exec.server.options.QueryOptionManager; import org.apache.drill.exec.store.StoragePluginRegistry; import org.apache.drill.exec.store.sys.PStoreProvider; +import java.util.Collection; + public class QueryContext{ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(QueryContext.class); @@ -45,6 +45,7 @@ public class QueryContext{ private final DrillbitContext drillbitContext; private final WorkEventBus workBus; private UserSession session; + private OptionManager queryOptions; public final Multitimer<QuerySetup> timer; private final PlannerSettings plannerSettings; private final DrillOperatorTable table; @@ -56,7 +57,8 @@ public class QueryContext{ this.workBus = drllbitContext.getWorkBus(); this.session = session; this.timer = new Multitimer<>(QuerySetup.class); - this.plannerSettings = new PlannerSettings(session.getOptions()); + this.queryOptions = new QueryOptionManager(session.getOptions()); + this.plannerSettings = new PlannerSettings(queryOptions); this.plannerSettings.setNumEndPoints(this.getActiveEndpoints().size()); this.table = new DrillOperatorTable(getFunctionRegistry()); } @@ -89,7 +91,11 @@ public class QueryContext{ return rootSchema; } - public OptionManager getOptions(){ + public OptionManager getOptions() { + return queryOptions; + } + + public OptionManager getSessionOptions() { return session.getOptions(); } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/opt/BasicOptimizer.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/opt/BasicOptimizer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/opt/BasicOptimizer.java index 24d9cfe..1f473c5 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/opt/BasicOptimizer.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/opt/BasicOptimizer.java @@ -17,12 +17,7 @@ */ package org.apache.drill.exec.opt; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - +import com.google.common.collect.Lists; import org.apache.drill.common.JSONOptions; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.ExecutionSetupException; @@ -60,7 +55,11 @@ import org.apache.drill.exec.store.StoragePlugin; import org.eigenbase.rel.RelFieldCollation.Direction; import org.eigenbase.rel.RelFieldCollation.NullDirection; -import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; public class BasicOptimizer extends Optimizer{ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(BasicOptimizer.class); @@ -125,7 +124,7 @@ public class BasicOptimizer extends Optimizer{ .type(PlanProperties.PlanType.APACHE_DRILL_PHYSICAL) .version(plan.getProperties().version) .generator(plan.getProperties().generator) - .options(new JSONOptions(context.getOptions().getSessionOptionList())).build(); + .options(new JSONOptions(context.getOptions().getOptionList())).build(); PhysicalPlan p = new PhysicalPlan(props, physOps); return p; //return new PhysicalPlan(props, physOps); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/cost/DrillCostBase.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/cost/DrillCostBase.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/cost/DrillCostBase.java index 412c218..50e4fb6 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/cost/DrillCostBase.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/cost/DrillCostBase.java @@ -112,12 +112,18 @@ public class DrillCostBase implements DrillRelOptCost { final double cpu; final double io; final double network; - + final double memory; + public DrillCostBase(double rowCount, double cpu, double io, double network) { + this(rowCount, cpu, io, network, 0); + } + + public DrillCostBase(double rowCount, double cpu, double io, double network, double memory) { this.rowCount = rowCount; this.cpu = cpu; this.io = io; this.network = network; + this.memory = memory; } @Override @@ -140,6 +146,10 @@ public class DrillCostBase implements DrillRelOptCost { return network; } + public double getMemory() { + return memory; + } + @Override public int hashCode() { return Util.hashCode(rowCount) + Util.hashCode(cpu) + Util.hashCode(io) + Util.hashCode(network); @@ -211,8 +221,9 @@ public class DrillCostBase implements DrillRelOptCost { return new DrillCostBase( this.rowCount + that.rowCount, this.cpu + that.cpu, - this.io + that.io, - this.network + that.network); + this.io + that.io, + this.network + that.network, + this.memory + that.memory); } @Override @@ -224,8 +235,9 @@ public class DrillCostBase implements DrillRelOptCost { return new DrillCostBase( this.rowCount - that.rowCount, this.cpu - that.cpu, - this.io - that.io, - this.network - that.network); + this.io - that.io, + this.network - that.network, + this.memory - that.memory); } @Override @@ -279,16 +291,21 @@ public class DrillCostBase implements DrillRelOptCost { } public String toString() { - return "{" + rowCount + " rows, " + cpu + " cpu, " + io + " io, " + network + " network}"; + return "{" + rowCount + " rows, " + cpu + " cpu, " + io + " io, " + network + " network, " + memory + " memory}"; } public static class DrillCostFactory implements DrillRelOptCostFactory { + + public RelOptCost makeCost(double dRows, double dCpu, double dIo, double dNetwork, double dMemory) { + return new DrillCostBase(dRows, dCpu, dIo, dNetwork, dMemory); + } + public RelOptCost makeCost(double dRows, double dCpu, double dIo, double dNetwork) { - return new DrillCostBase(dRows, dCpu, dIo, dNetwork); + return new DrillCostBase(dRows, dCpu, dIo, dNetwork, 0); } public RelOptCost makeCost(double dRows, double dCpu, double dIo) { - return new DrillCostBase(dRows, dCpu, dIo, 0); + return new DrillCostBase(dRows, dCpu, dIo, 0, 0); } public RelOptCost makeHugeCost() { http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrel.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrel.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrel.java index 34c0b5a..c1b1fba 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrel.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrel.java @@ -17,27 +17,13 @@ */ package org.apache.drill.exec.planner.physical; -import java.io.IOException; -import java.util.BitSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import net.hydromatic.linq4j.Ord; -import net.hydromatic.optiq.util.BitSets; - -import org.apache.drill.common.expression.ExpressionPosition; -import org.apache.drill.common.expression.FieldReference; -import org.apache.drill.common.expression.FunctionCall; -import org.apache.drill.common.expression.LogicalExpression; -import org.apache.drill.common.expression.ValueExpressions; import org.apache.drill.common.logical.data.NamedExpression; +import org.apache.drill.exec.ExecConstants; +import org.apache.drill.exec.expr.holders.IntHolder; import org.apache.drill.exec.physical.base.PhysicalOperator; import org.apache.drill.exec.physical.config.HashAggregate; import org.apache.drill.exec.planner.cost.DrillCostBase; import org.apache.drill.exec.planner.cost.DrillCostBase.DrillCostFactory; -import org.apache.drill.exec.planner.logical.DrillParseContext; -import org.apache.drill.exec.planner.physical.visitor.PrelVisitor; import org.apache.drill.exec.record.BatchSchema.SelectionVectorMode; import org.eigenbase.rel.AggregateCall; import org.eigenbase.rel.AggregateRelBase; @@ -49,7 +35,9 @@ import org.eigenbase.relopt.RelOptCost; import org.eigenbase.relopt.RelOptPlanner; import org.eigenbase.relopt.RelTraitSet; -import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.BitSet; +import java.util.List; public class HashAggPrel extends AggPrelBase implements Prel{ @@ -84,8 +72,24 @@ public class HashAggPrel extends AggPrelBase implements Prel{ // add cpu cost for computing the aggregate functions cpuCost += DrillCostBase.FUNC_CPU_COST * numAggrFields * inputRows; double diskIOCost = 0; // assume in-memory for now until we enforce operator-level memory constraints - DrillCostFactory costFactory = (DrillCostFactory)planner.getCostFactory(); - return costFactory.makeCost(inputRows, cpuCost, diskIOCost, 0 /* network cost */); + + // TODO: use distinct row count + // + hash table template stuff + double factor = PrelUtil.getPlannerSettings(planner).getOptions() + .getOption(ExecConstants.HASH_AGG_TABLE_FACTOR_KEY).float_val; + long fieldWidth = PrelUtil.getPlannerSettings(planner).getOptions() + .getOption(ExecConstants.AVERAGE_FIELD_WIDTH_KEY).num_val; + + // table + hashValues + links + double memCost = + ( + (fieldWidth * numGroupByFields) + + IntHolder.WIDTH + + IntHolder.WIDTH + ) * inputRows * factor; + + DrillCostFactory costFactory = (DrillCostFactory) planner.getCostFactory(); + return costFactory.makeCost(inputRows, cpuCost, diskIOCost, 0 /* network cost */, memCost); } @Override http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrule.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrule.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrule.java index 471e165..e2ee57f 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrule.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashAggPrule.java @@ -17,8 +17,7 @@ */ package org.apache.drill.exec.planner.physical; -import java.util.logging.Logger; - +import com.google.common.collect.ImmutableList; import org.apache.drill.exec.planner.logical.DrillAggregateRel; import org.apache.drill.exec.planner.logical.RelOptHelper; import org.apache.drill.exec.planner.physical.AggPrelBase.OperatorPhase; @@ -30,7 +29,7 @@ import org.eigenbase.relopt.RelTrait; import org.eigenbase.relopt.RelTraitSet; import org.eigenbase.trace.EigenbaseTrace; -import com.google.common.collect.ImmutableList; +import java.util.logging.Logger; public class HashAggPrule extends AggPruleBase { public static final RelOptRule INSTANCE = new HashAggPrule(); @@ -42,11 +41,14 @@ public class HashAggPrule extends AggPruleBase { @Override public boolean matches(RelOptRuleCall call) { - return PrelUtil.getPlannerSettings(call.getPlanner()).isHashAggEnabled(); + PlannerSettings settings = PrelUtil.getPlannerSettings(call.getPlanner()); + return settings.isMemoryEstimationEnabled() || settings.isHashAggEnabled(); } @Override public void onMatch(RelOptRuleCall call) { + if (!PrelUtil.getPlannerSettings(call.getPlanner()).isHashAggEnabled()) return; + final DrillAggregateRel aggregate = (DrillAggregateRel) call.rel(0); final RelNode input = call.rel(1); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java index 136eb4c..aaf18b1 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java @@ -17,11 +17,11 @@ */ package org.apache.drill.exec.planner.physical; -import java.io.IOException; -import java.util.List; - +import com.google.common.collect.Lists; import org.apache.drill.common.expression.FieldReference; import org.apache.drill.common.logical.data.JoinCondition; +import org.apache.drill.exec.ExecConstants; +import org.apache.drill.exec.expr.holders.IntHolder; import org.apache.drill.exec.physical.base.PhysicalOperator; import org.apache.drill.exec.physical.config.HashJoinPOP; import org.apache.drill.exec.planner.cost.DrillCostBase; @@ -40,7 +40,8 @@ import org.eigenbase.relopt.RelTraitSet; import org.eigenbase.rex.RexNode; import org.eigenbase.util.Pair; -import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.List; public class HashJoinPrel extends JoinPrel { @@ -78,8 +79,22 @@ public class HashJoinPrel extends JoinPrel { double joinConditionCost = DrillCostBase.COMPARE_CPU_COST * this.getLeftKeys().size(); double cpuCost = joinConditionCost * (buildRowCount + probeRowCount) + cpuCostBuild + cpuCostProbe; - DrillCostFactory costFactory = (DrillCostFactory)planner.getCostFactory(); - return costFactory.makeCost(buildRowCount + probeRowCount, cpuCost, 0, 0); + + double factor = PrelUtil.getPlannerSettings(planner).getOptions() + .getOption(ExecConstants.HASH_JOIN_TABLE_FACTOR_KEY).float_val; + long fieldWidth = PrelUtil.getPlannerSettings(planner).getOptions() + .getOption(ExecConstants.AVERAGE_FIELD_WIDTH_KEY).num_val; + + // table + hashValues + links + double memCost = + ( + (fieldWidth * this.getRightKeys().size()) + + IntHolder.WIDTH + + IntHolder.WIDTH + ) * buildRowCount * factor; + + DrillCostFactory costFactory = (DrillCostFactory) planner.getCostFactory(); + return costFactory.makeCost(buildRowCount + probeRowCount, cpuCost, 0, 0, memCost); } @Override http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrule.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrule.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrule.java index 9ae4783..8588425 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrule.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrule.java @@ -17,21 +17,15 @@ */ package org.apache.drill.exec.planner.physical; -import java.util.logging.Logger; - import org.apache.drill.exec.planner.logical.DrillJoinRel; import org.apache.drill.exec.planner.logical.RelOptHelper; import org.eigenbase.rel.InvalidRelException; -import org.eigenbase.rel.RelCollation; import org.eigenbase.rel.RelNode; -import org.eigenbase.rel.metadata.RelMetadataQuery; import org.eigenbase.relopt.RelOptRule; import org.eigenbase.relopt.RelOptRuleCall; -import org.eigenbase.relopt.RelTraitSet; -import org.eigenbase.relopt.volcano.RelSubset; import org.eigenbase.trace.EigenbaseTrace; -import com.google.common.collect.ImmutableList; +import java.util.logging.Logger; public class HashJoinPrule extends JoinPruleBase { public static final RelOptRule INSTANCE = new HashJoinPrule(); @@ -44,11 +38,14 @@ public class HashJoinPrule extends JoinPruleBase { @Override public boolean matches(RelOptRuleCall call) { - return PrelUtil.getPlannerSettings(call.getPlanner()).isHashJoinEnabled(); + PlannerSettings settings = PrelUtil.getPlannerSettings(call.getPlanner()); + return settings.isMemoryEstimationEnabled() || settings.isHashJoinEnabled(); } @Override public void onMatch(RelOptRuleCall call) { + if (!PrelUtil.getPlannerSettings(call.getPlanner()).isHashJoinEnabled()) return; + final DrillJoinRel join = (DrillJoinRel) call.rel(0); final RelNode left = join.getLeft(); final RelNode right = join.getRight(); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PlannerSettings.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PlannerSettings.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PlannerSettings.java index 998ecc0..5ec52c9 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PlannerSettings.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PlannerSettings.java @@ -53,6 +53,10 @@ public class PlannerSettings implements Context{ this.options = options; } + public OptionManager getOptions() { + return options; + } + public boolean isSingleMode() { return options.getOption(EXCHANGE.getOptionName()).bool_val; } @@ -113,6 +117,10 @@ public class PlannerSettings implements Context{ return options.getOption(ExecConstants.SLICE_TARGET).num_val; } + public boolean isMemoryEstimationEnabled() { + return options.getOption(ExecConstants.ENABLE_MEMORY_ESTIMATION_KEY).bool_val; + } + @Override public <T> T unwrap(Class<T> clazz) { if(clazz == PlannerSettings.class){ http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/SortPrel.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/SortPrel.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/SortPrel.java index 3ef33ae..0926f60 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/SortPrel.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/SortPrel.java @@ -17,12 +17,9 @@ */ package org.apache.drill.exec.planner.physical; -import java.io.IOException; -import java.util.Iterator; - +import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.physical.base.PhysicalOperator; import org.apache.drill.exec.physical.config.ExternalSort; -import org.apache.drill.exec.physical.config.SingleMergeExchange; import org.apache.drill.exec.physical.config.Sort; import org.apache.drill.exec.planner.cost.DrillCostBase; import org.apache.drill.exec.planner.cost.DrillCostBase.DrillCostFactory; @@ -38,6 +35,9 @@ import org.eigenbase.relopt.RelOptPlanner; import org.eigenbase.relopt.RelTraitSet; import org.eigenbase.rex.RexNode; +import java.io.IOException; +import java.util.Iterator; + public class SortPrel extends SortRel implements Prel { /** Creates a DrillSortRel. */ @@ -63,8 +63,17 @@ public class SortPrel extends SortRel implements Prel { int numSortFields = this.collation.getFieldCollations().size(); double cpuCost = DrillCostBase.COMPARE_CPU_COST * numSortFields * inputRows * (Math.log(inputRows)/Math.log(2)); double diskIOCost = 0; // assume in-memory for now until we enforce operator-level memory constraints - DrillCostFactory costFactory = (DrillCostFactory)planner.getCostFactory(); - return costFactory.makeCost(inputRows, cpuCost, diskIOCost, 0); + + // TODO: use rowWidth instead of avgFieldWidth * numFields + // avgFieldWidth * numFields * inputRows + double numFields = this.getRowType().getFieldCount(); + long fieldWidth = PrelUtil.getPlannerSettings(planner).getOptions() + .getOption(ExecConstants.AVERAGE_FIELD_WIDTH_KEY).num_val; + + double memCost = fieldWidth * numFields * inputRows; + + DrillCostFactory costFactory = (DrillCostFactory) planner.getCostFactory(); + return costFactory.makeCost(inputRows, cpuCost, diskIOCost, 0, memCost); } @Override http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/MemoryEstimationVisitor.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/MemoryEstimationVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/MemoryEstimationVisitor.java new file mode 100644 index 0000000..0fd1dd0 --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/visitor/MemoryEstimationVisitor.java @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.drill.exec.planner.physical.visitor; + +import org.apache.drill.exec.ExecConstants; +import org.apache.drill.exec.planner.cost.DrillCostBase; +import org.apache.drill.exec.planner.physical.Prel; +import org.apache.drill.exec.server.options.OptionManager; +import org.eigenbase.rel.metadata.RelMetadataQuery; + +public class MemoryEstimationVisitor extends BasePrelVisitor<Double, Void, RuntimeException> { + + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MemoryEstimationVisitor.class); + + public static boolean enoughMemory(Prel prel, OptionManager options, int numDrillbits) { + long allottedMemory = options.getOption(ExecConstants.MAX_QUERY_MEMORY_PER_NODE_KEY).num_val * numDrillbits; + long estimatedMemory = (long) Math.ceil(prel.accept(new MemoryEstimationVisitor(), null) / (1024.0 * 1024.0)); + estimatedMemory += options.getOption(ExecConstants.NON_BLOCKING_OPERATORS_MEMORY_KEY).num_val * numDrillbits; + + if (estimatedMemory > allottedMemory) { + logger.debug("Estimated memory (" + estimatedMemory + ") exceeds maximum allowed (" + allottedMemory + ")"); + } else { + logger.debug("Estimated memory (" + estimatedMemory + ") within maximum allowed (" + allottedMemory + ")"); + } + return estimatedMemory <= allottedMemory; + } + + public static Double estimateMemory(Prel prel) { + return prel.accept(new MemoryEstimationVisitor(), null); + } + + public MemoryEstimationVisitor() { + } + + @Override + public Double visitPrel(Prel prel, Void value) throws RuntimeException { + return ((DrillCostBase) RelMetadataQuery.getCumulativeCost(prel)).getMemory(); +// return findCost(prel); + } + + private double findCost(Prel prel) { + DrillCostBase cost = (DrillCostBase) RelMetadataQuery.getNonCumulativeCost(prel); + double memory = cost.getMemory(); + + for (Prel child : prel) { + memory += findCost(child); + } + return memory; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java index 177331d..c5d342f 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java @@ -17,9 +17,9 @@ */ package org.apache.drill.exec.planner.sql.handlers; -import java.io.IOException; -import java.util.Collection; -import java.util.List; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import net.hydromatic.optiq.tools.Planner; import net.hydromatic.optiq.tools.RelConversionException; @@ -44,27 +44,28 @@ import org.apache.drill.exec.planner.physical.PhysicalPlanCreator; import org.apache.drill.exec.planner.physical.PlannerSettings; import org.apache.drill.exec.planner.physical.Prel; import org.apache.drill.exec.planner.physical.explain.PrelSequencer; +import org.apache.drill.exec.planner.physical.visitor.ComplexToJsonPrelVisitor; import org.apache.drill.exec.planner.physical.visitor.ExcessiveExchangeIdentifier; import org.apache.drill.exec.planner.physical.visitor.FinalColumnReorderer; -import org.apache.drill.exec.planner.physical.visitor.ComplexToJsonPrelVisitor; import org.apache.drill.exec.planner.physical.visitor.JoinPrelRenameVisitor; +import org.apache.drill.exec.planner.physical.visitor.MemoryEstimationVisitor; import org.apache.drill.exec.planner.physical.visitor.ProducerConsumerPrelVisitor; import org.apache.drill.exec.planner.physical.visitor.RelUniqifier; import org.apache.drill.exec.planner.physical.visitor.SelectionVectorPrelVisitor; -import org.apache.drill.exec.planner.sql.DrillOperatorTable; import org.apache.drill.exec.planner.physical.visitor.StarColumnConverter; import org.apache.drill.exec.planner.sql.DrillSqlWorker; +import org.apache.drill.exec.server.options.OptionManager; +import org.apache.drill.exec.server.options.OptionValue; import org.apache.drill.exec.util.Pointer; import org.eigenbase.rel.RelNode; import org.eigenbase.relopt.RelOptUtil; import org.eigenbase.relopt.RelTraitSet; -import org.eigenbase.rex.RexBuilder; import org.eigenbase.sql.SqlExplainLevel; import org.eigenbase.sql.SqlNode; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.Collection; +import java.util.List; public class DefaultSqlHandler extends AbstractSqlHandler { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DefaultSqlHandler.class); @@ -155,6 +156,18 @@ public class DefaultSqlHandler extends AbstractSqlHandler { Preconditions.checkArgument(drel.getConvention() == DrillRel.DRILL_LOGICAL); RelTraitSet traits = drel.getTraitSet().plus(Prel.DRILL_PHYSICAL).plus(DrillDistributionTrait.SINGLETON); Prel phyRelNode = (Prel) planner.transform(DrillSqlWorker.PHYSICAL_MEM_RULES, traits, drel); + OptionManager queryOptions = context.getOptions(); + + if (context.getPlannerSettings().isMemoryEstimationEnabled() + && !MemoryEstimationVisitor.enoughMemory(phyRelNode, queryOptions, context.getActiveEndpoints().size())) { + log("Not enough memory for this plan", phyRelNode); + logger.debug("Re-planning without hash operations."); + + queryOptions.setOption(OptionValue.createBoolean(OptionValue.OptionType.QUERY, PlannerSettings.HASHJOIN.getOptionName(), false)); + queryOptions.setOption(OptionValue.createBoolean(OptionValue.OptionType.QUERY, PlannerSettings.HASHAGG.getOptionName(), false)); + + phyRelNode = (Prel) planner.transform(DrillSqlWorker.PHYSICAL_MEM_RULES, traits, drel); + } /* The order of the following transformation is important */ @@ -234,7 +247,7 @@ public class DefaultSqlHandler extends AbstractSqlHandler { PlanPropertiesBuilder propsBuilder = PlanProperties.builder(); propsBuilder.type(PlanType.APACHE_DRILL_PHYSICAL); propsBuilder.version(1); - propsBuilder.options(new JSONOptions(context.getOptions().getSessionOptionList())); + propsBuilder.options(new JSONOptions(context.getOptions().getOptionList())); propsBuilder.resultMode(ResultMode.EXEC); propsBuilder.generator(this.getClass().getSimpleName(), ""); return new PhysicalPlan(propsBuilder.build(), getPops(op)); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/SetOptionHandler.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/SetOptionHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/SetOptionHandler.java index eafc8d9..028f569 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/SetOptionHandler.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/SetOptionHandler.java @@ -17,18 +17,18 @@ */ package org.apache.drill.exec.planner.sql.handlers; -import java.io.IOException; - import net.hydromatic.optiq.tools.RelConversionException; import net.hydromatic.optiq.tools.ValidationException; - import org.apache.drill.exec.ops.QueryContext; import org.apache.drill.exec.physical.PhysicalPlan; import org.apache.drill.exec.planner.sql.DirectPlan; +import org.apache.drill.exec.server.options.OptionValue; import org.eigenbase.sql.SqlLiteral; import org.eigenbase.sql.SqlNode; import org.eigenbase.sql.SqlSetOption; +import java.io.IOException; + public class SetOptionHandler extends AbstractSqlHandler{ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SetOptionHandler.class); @@ -47,18 +47,22 @@ public class SetOptionHandler extends AbstractSqlHandler{ String scope = option.getScope(); String name = option.getName(); SqlNode value = option.getValue(); - if(value instanceof SqlLiteral){ - switch(scope.toLowerCase()){ - case "session": - context.getOptions().setOption(option.getName(), (SqlLiteral) value); - break; - case "system": - context.getOptions().getSystemManager().setOption(name, (SqlLiteral) value); - break; - default: - throw new ValidationException("Invalid OPTION scope. Scope must be SESSION or SYSTEM."); + OptionValue.OptionType type; + if (value instanceof SqlLiteral) { + switch (scope.toLowerCase()) { + case "session": + type = OptionValue.OptionType.SESSION; + break; + case "system": + type = OptionValue.OptionType.SYSTEM; + break; +// case "query": +// type = OptionValue.OptionType.QUERY; +// break; + default: + throw new ValidationException("Invalid OPTION scope. Scope must be SESSION or SYSTEM."); } - + context.getOptions().setOption(name, (SqlLiteral) value, type); }else{ throw new ValidationException("Sql options can only be literals."); } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserSession.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserSession.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserSession.java index 13414da..e7be380 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserSession.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserSession.java @@ -17,17 +17,15 @@ */ package org.apache.drill.exec.rpc.user; -import java.util.Map; - +import com.google.common.collect.Maps; import net.hydromatic.optiq.SchemaPlus; - import org.apache.drill.exec.proto.UserBitShared.UserCredentials; import org.apache.drill.exec.proto.UserProtos.Property; import org.apache.drill.exec.proto.UserProtos.UserProperties; import org.apache.drill.exec.server.options.OptionManager; import org.apache.drill.exec.server.options.SessionOptionManager; -import com.google.common.collect.Maps; +import java.util.Map; public class UserSession { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(UserSession.class); @@ -39,7 +37,7 @@ public class UserSession { private boolean supportComplexTypes = false; private UserCredentials credentials; private Map<String, String> properties; - private OptionManager options; + private OptionManager sessionOptions; public static class Builder { UserSession userSession; @@ -54,7 +52,7 @@ public class UserSession { } public Builder withOptionManager(OptionManager systemOptions) { - userSession.options = new SessionOptionManager(systemOptions); + userSession.sessionOptions = new SessionOptionManager(systemOptions); return this; } @@ -91,8 +89,8 @@ public class UserSession { return supportComplexTypes; } - public OptionManager getOptions(){ - return options; + public OptionManager getOptions() { + return sessionOptions; } public DrillUser getUser(){ http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionManager.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionManager.java new file mode 100644 index 0000000..aaf5719 --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionManager.java @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.drill.exec.server.options; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import org.eigenbase.sql.SqlLiteral; + +import java.util.Iterator; +import java.util.Map; + +public class FragmentOptionManager implements OptionManager { + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FragmentOptionManager.class); + + ImmutableMap<String, OptionValue> options; + OptionManager systemOptions; + + public FragmentOptionManager(OptionManager systemOptions, OptionList options) { + Map<String, OptionValue> tmp = Maps.newHashMap(); + for(OptionValue v : options){ + tmp.put(v.name, v); + } + this.options = ImmutableMap.copyOf(tmp); + this.systemOptions = systemOptions; + } + + @Override + public Iterator<OptionValue> iterator() { + return Iterables.concat(systemOptions, options.values()).iterator(); + } + + @Override + public OptionValue getOption(String name) { + OptionValue value = options.get(name); + if (value == null && systemOptions != null) { + value = systemOptions.getOption(name); + } + return value; + } + + @Override + public void setOption(OptionValue value) throws SetOptionException { + throw new UnsupportedOperationException(); + } + + @Override + public void setOption(String name, SqlLiteral literal, OptionValue.OptionType type) throws SetOptionException { + throw new UnsupportedOperationException(); + } + + @Override + public OptionAdmin getAdmin() { + throw new UnsupportedOperationException(); + } + + @Override + public OptionManager getSystemManager() { + throw new UnsupportedOperationException(); + } + + @Override + public OptionList getOptionList() { + throw new UnsupportedOperationException(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionsManager.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionsManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionsManager.java deleted file mode 100644 index 49d08d9..0000000 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/FragmentOptionsManager.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 org.apache.drill.exec.server.options; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.eigenbase.sql.SqlLiteral; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; - -public class FragmentOptionsManager implements OptionManager{ - static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FragmentOptionsManager.class); - - ImmutableMap<String, OptionValue> options; - OptionManager systemOptions; - - public FragmentOptionsManager(OptionManager systemOptions, OptionList options){ - Map<String, OptionValue> tmp = Maps.newHashMap(); - for(OptionValue v : options){ - tmp.put(v.name, v); - } - this.options = ImmutableMap.copyOf(tmp); - this.systemOptions = systemOptions; - } - - @Override - public Iterator<OptionValue> iterator() { - return Iterables.concat(systemOptions, options.values()).iterator(); - } - - @Override - public OptionValue getOption(String name) { - OptionValue value = options.get(name); - if (value == null && systemOptions != null) { - value = systemOptions.getOption(name); - } - return value; - } - - @Override - public void setOption(OptionValue value) throws SetOptionException { - throw new UnsupportedOperationException(); - } - - @Override - public void setOption(String name, SqlLiteral literal) throws SetOptionException { - throw new UnsupportedOperationException(); - } - - @Override - public OptionAdmin getAdmin() { - throw new UnsupportedOperationException(); - } - - @Override - public OptionManager getSystemManager() { - throw new UnsupportedOperationException(); - } - - @Override - public OptionList getSessionOptionList() { - throw new UnsupportedOperationException(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionManager.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionManager.java index 3833833..83af7db 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionManager.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionManager.java @@ -22,10 +22,10 @@ import org.eigenbase.sql.SqlLiteral; public interface OptionManager extends Iterable<OptionValue>{ public OptionValue getOption(String name); public void setOption(OptionValue value) throws SetOptionException; - public void setOption(String name, SqlLiteral literal) throws SetOptionException; + public void setOption(String name, SqlLiteral literal, OptionValue.OptionType type) throws SetOptionException; public OptionAdmin getAdmin(); public OptionManager getSystemManager(); - public OptionList getSessionOptionList(); + public OptionList getOptionList(); public interface OptionAdmin{ public void registerOptionType(OptionValidator validator); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionValue.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionValue.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionValue.java index 1f45522..7401246 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionValue.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/OptionValue.java @@ -17,6 +17,7 @@ */ package org.apache.drill.exec.server.options; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.google.common.base.Preconditions; @@ -25,7 +26,7 @@ import com.google.common.base.Preconditions; public class OptionValue{ public static enum OptionType { - BOOT, SYSTEM, SESSION + BOOT, SYSTEM, SESSION, QUERY } public static enum Kind { @@ -58,6 +59,21 @@ public class OptionValue{ public OptionValue(){} + public static OptionValue createOption(Kind kind, OptionType type, String name, String val) { + switch (kind) { + case BOOLEAN: + return createBoolean(type, name, Boolean.valueOf(val)); + case LONG: + return createLong(type, name, Long.valueOf(val)); + case STRING: + return createString(type, name, val); + case DOUBLE: + return createDouble(type, name, Double.valueOf(val)); + } + return null; + } + + private OptionValue(Kind kind, OptionType type, String name, Long num_val, String string_val, Boolean bool_val, Double float_val) { super(); Preconditions.checkArgument(num_val != null || string_val != null || bool_val != null || float_val != null); @@ -71,6 +87,21 @@ public class OptionValue{ this.type = type; } + @JsonIgnore + public Object getValue() { + switch (kind) { + case BOOLEAN: + return bool_val; + case LONG: + return num_val; + case STRING: + return string_val; + case DOUBLE: + return float_val; + } + return null; + } + @Override public int hashCode() { final int prime = 31; http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/QueryOptionManager.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/QueryOptionManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/QueryOptionManager.java new file mode 100644 index 0000000..8b5306f --- /dev/null +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/QueryOptionManager.java @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.drill.exec.server.options; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import org.eigenbase.sql.SqlLiteral; + +import java.util.Iterator; +import java.util.Map; + +public class QueryOptionManager implements OptionManager { + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SessionOptionManager.class); + + private Map<String, OptionValue> options = Maps.newConcurrentMap(); + private OptionManager sessionOptions; + + public QueryOptionManager(OptionManager sessionOptions) { + super(); + this.sessionOptions = sessionOptions; + } + + @Override + public Iterator<OptionValue> iterator() { + return Iterables.concat(sessionOptions, options.values()).iterator(); + } + + @Override + public OptionValue getOption(String name) { + OptionValue opt = options.get(name); + if (opt == null && sessionOptions != null) { + return sessionOptions.getOption(name); + } else { + return opt; + } + } + + @Override + public void setOption(OptionValue value) { + sessionOptions.getAdmin().validate(value); + setValidatedOption(value); + } + + @Override + public void setOption(String name, SqlLiteral literal, OptionValue.OptionType type) { + OptionValue val = sessionOptions.getAdmin().validate(name, literal); + val.type = type; + setValidatedOption(val); + } + + private void setValidatedOption(OptionValue value) { + if (value.type == OptionValue.OptionType.QUERY) { + options.put(value.name, value); + } else { + sessionOptions.setOption(value); + } + } + + @Override + public OptionManager.OptionAdmin getAdmin() { + return sessionOptions.getAdmin(); + } + + @Override + public OptionManager getSystemManager() { + return sessionOptions.getSystemManager(); + } + + @Override + public OptionList getOptionList() { + OptionList list = new OptionList(); + for (OptionValue o : options.values()) { + list.add(o); + } + return list; + } + + public OptionList getSessionOptionList() { + return sessionOptions.getOptionList(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SessionOptionManager.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SessionOptionManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SessionOptionManager.java index b5c914e..53c26c1 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SessionOptionManager.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SessionOptionManager.java @@ -17,14 +17,13 @@ */ package org.apache.drill.exec.server.options; -import java.util.Iterator; -import java.util.Map; - +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; import org.apache.drill.exec.server.options.OptionValue.OptionType; import org.eigenbase.sql.SqlLiteral; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; +import java.util.Iterator; +import java.util.Map; public class SessionOptionManager implements OptionManager{ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SessionOptionManager.class); @@ -59,30 +58,21 @@ public class SessionOptionManager implements OptionManager{ } @Override - public OptionList getSessionOptionList() { - OptionList list = new OptionList(); - for(OptionValue o : options.values()){ - list.add(o); - } - return list; + public void setOption(String name, SqlLiteral literal, OptionType type) { + OptionValue val = systemOptions.getAdmin().validate(name, literal); + val.type = type; + setValidatedOption(val); } - private void setValidatedOption(OptionValue value){ - if(value.type == OptionType.SYSTEM){ - systemOptions.setOption(value); - }else{ + private void setValidatedOption(OptionValue value) { + if (value.type == OptionType.SESSION) { options.put(value.name, value); + } else { + systemOptions.setOption(value); } } @Override - public void setOption(String name, SqlLiteral literal) { - OptionValue val = systemOptions.getAdmin().validate(name, literal); - val.type = OptionValue.OptionType.SESSION; - setValidatedOption(val); - } - - @Override public OptionAdmin getAdmin() { return systemOptions.getAdmin(); } @@ -92,4 +82,13 @@ public class SessionOptionManager implements OptionManager{ return systemOptions; } + @Override + public OptionList getOptionList() { + OptionList list = new OptionList(); + for (OptionValue o : options.values()) { + list.add(o); + } + return list; + } + } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java index e49b107..eddb818 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/SystemOptionManager.java @@ -17,28 +17,28 @@ */ package org.apache.drill.exec.server.options; -import java.io.IOException; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentMap; - +import com.google.common.collect.Maps; +import org.apache.commons.collections.IteratorUtils; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.cache.DistributedCache.CacheConfig; import org.apache.drill.exec.compile.QueryClassLoader; -import org.apache.drill.exec.planner.fragment.SimpleParallelizer; import org.apache.drill.exec.planner.physical.PlannerSettings; import org.apache.drill.exec.server.options.OptionValue.OptionType; import org.apache.drill.exec.store.sys.PStore; import org.apache.drill.exec.store.sys.PStoreConfig; import org.apache.drill.exec.store.sys.PStoreProvider; -import org.apache.drill.exec.work.foreman.Foreman; import org.eigenbase.sql.SqlLiteral; -import com.google.common.collect.Maps; +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; public class SystemOptionManager implements OptionManager{ + static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SystemOptionManager.class); + public static final CacheConfig<String, OptionValue> OPTION_CACHE = CacheConfig // .newBuilder(OptionValue.class) // .name("sys.options") // @@ -72,6 +72,12 @@ public class SystemOptionManager implements OptionManager{ ExecConstants.SMALL_QUEUE_SIZE, ExecConstants.MIN_HASH_TABLE_SIZE, ExecConstants.MAX_HASH_TABLE_SIZE, + ExecConstants.ENABLE_MEMORY_ESTIMATION, + ExecConstants.MAX_QUERY_MEMORY_PER_NODE, + ExecConstants.NON_BLOCKING_OPERATORS_MEMORY, + ExecConstants.HASH_JOIN_TABLE_FACTOR, + ExecConstants.HASH_AGG_TABLE_FACTOR, + ExecConstants.AVERAGE_FIELD_WIDTH, QueryClassLoader.JAVA_COMPILER_VALIDATOR, QueryClassLoader.JAVA_COMPILER_JANINO_MAXSIZE, QueryClassLoader.JAVA_COMPILER_DEBUG, @@ -133,21 +139,22 @@ public class SystemOptionManager implements OptionManager{ @Override public void setOption(OptionValue value) { - admin.validate(value); assert value.type == OptionType.SYSTEM; + admin.validate(value); options.put(value.name, value); } @Override - public void setOption(String name, SqlLiteral literal) { + public void setOption(String name, SqlLiteral literal, OptionType type) { + assert type == OptionValue.OptionType.SYSTEM; OptionValue v = admin.validate(name, literal); - v.type = OptionValue.OptionType.SYSTEM; + v.type = type; options.put(name, v); } @Override - public OptionList getSessionOptionList() { - throw new UnsupportedOperationException(); + public OptionList getOptionList() { + return (OptionList) IteratorUtils.toList(iterator()); } @Override @@ -160,9 +167,6 @@ public class SystemOptionManager implements OptionManager{ return admin; } - static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SystemOptionManager.class); - - private class SystemOptionAdmin implements OptionAdmin{ public SystemOptionAdmin(){ http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/TypeValidators.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/TypeValidators.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/TypeValidators.java index a59c125..2f43374 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/TypeValidators.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/options/TypeValidators.java @@ -17,14 +17,14 @@ */ package org.apache.drill.exec.server.options; -import java.math.BigDecimal; - import org.apache.drill.common.exceptions.ExpressionParsingException; import org.apache.drill.exec.server.options.OptionValue.Kind; import org.apache.drill.exec.server.options.OptionValue.OptionType; import org.eigenbase.sql.SqlLiteral; import org.eigenbase.util.NlsString; +import java.math.BigDecimal; + public class TypeValidators { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TypeValidators.class); @@ -38,13 +38,32 @@ public class TypeValidators { } @Override - public void extraValidate(OptionValue v) throws ExpressionParsingException { + public void validate(OptionValue v) throws ExpressionParsingException { + super.validate(v); if (v.num_val > max || v.num_val < 0) throw new ExpressionParsingException(String.format("Option %s must be between %d and %d.", getOptionName(), 0, max)); } } + public static class PowerOfTwoLongValidator extends PositiveLongValidator { + + public PowerOfTwoLongValidator(String name, long max, long def) { + super(name, max, def); + } + + @Override + public void validate(OptionValue v) throws ExpressionParsingException { + super.validate(v); + if (!isPowerOfTwo(v.num_val)) + throw new ExpressionParsingException(String.format("Option %s must be a power of two.", getOptionName())); + } + + private boolean isPowerOfTwo(long num) { + return (num & (num - 1)) == 0; + } + } + public static class RangeDoubleValidator extends DoubleValidator { private final double min; private final double max; @@ -56,7 +75,8 @@ public class TypeValidators { } @Override - public void extraValidate(OptionValue v) throws ExpressionParsingException { + public void validate(OptionValue v) throws ExpressionParsingException { + super.validate(v); if (v.float_val > max || v.float_val < min) throw new ExpressionParsingException(String.format("Option %s must be between %d and %d.", getOptionName(), min, max)); @@ -112,7 +132,7 @@ public class TypeValidators { } @Override - public final void validate(OptionValue v) throws ExpressionParsingException { + public void validate(OptionValue v) throws ExpressionParsingException { if (v.kind != kind) throw new ExpressionParsingException(String.format("Option %s must be of type %s but you tried to set to %s.", getOptionName(), kind.name(), v.kind.name())); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java index c2fabcb..db07ab4 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java @@ -17,21 +17,75 @@ */ package org.apache.drill.exec.server.rest; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.google.common.collect.Lists; +import org.apache.drill.common.config.DrillConfig; +import org.apache.drill.exec.proto.CoordinationProtos; +import org.apache.drill.exec.work.WorkManager; +import org.glassfish.jersey.server.mvc.Viewable; + +import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import org.glassfish.jersey.server.mvc.Viewable; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; @Path("/") public class DrillRoot { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillRoot.class); + @Inject + WorkManager work; + @GET @Produces(MediaType.TEXT_HTML) - public Viewable getHello() { - String status = "Running!"; - return new Viewable("/rest/index.ftl", status); + public Viewable getStats() { + return new Viewable("/rest/index.ftl", getStatsJSON()); } + @GET + @Path("/stats.json") + @Produces(MediaType.APPLICATION_JSON) + public List<Stat> getStatsJSON() { + List<Stat> stats = Lists.newLinkedList(); + stats.add(new Stat("Number of Drill Bits", work.getContext().getBits().size())); + int number = 0; + for (CoordinationProtos.DrillbitEndpoint bit : work.getContext().getBits()) { + String initialized = bit.isInitialized() ? " initialized" : " not initialized"; + stats.add(new Stat("Bit #" + number, bit.getAddress() + initialized)); + ++number; + } + stats.add(new Stat("Data Port Address", work.getContext().getEndpoint().getAddress() + + ":" + work.getContext().getEndpoint().getDataPort())); + stats.add(new Stat("User Port Address", work.getContext().getEndpoint().getAddress() + + ":" + work.getContext().getEndpoint().getUserPort())); + stats.add(new Stat("Control Port Address", work.getContext().getEndpoint().getAddress() + + ":" + work.getContext().getEndpoint().getControlPort())); + stats.add(new Stat("Maximum Direct Memory", DrillConfig.getMaxDirectMemory())); + + return stats; + } + + @XmlRootElement + public class Stat { + private String name; + private Object value; + + @JsonCreator + public Stat(String name, Object value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public Object getValue() { + return value; + } + + } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/StatusResources.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/StatusResources.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/StatusResources.java index 4ec4182..79150d9 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/StatusResources.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/StatusResources.java @@ -17,22 +17,116 @@ */ package org.apache.drill.exec.server.rest; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.drill.exec.server.options.OptionManager; +import org.apache.drill.exec.server.options.OptionValue; +import org.apache.drill.exec.server.options.OptionValue.Kind; +import org.apache.drill.exec.work.WorkManager; import org.glassfish.jersey.server.mvc.Viewable; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.LinkedList; +import java.util.List; -@Path("/status") +@Path("/") public class StatusResources { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(StatusResources.class); + @Inject + WorkManager work; + @GET + @Path("/status") @Produces(MediaType.TEXT_HTML) public Viewable getStatus() { String status = "Running!"; return new Viewable("/rest/status.ftl", status); } + @GET + @Path("/options.json") + @Produces(MediaType.APPLICATION_JSON) + public List getSystemOptionsJSON() { + List<OptionWrapper> options = new LinkedList<>(); + for (OptionValue option : work.getContext().getOptionManager()) { + options.add(new OptionWrapper(option.name, option.getValue(), option.type, option.kind)); + } + return options; + } + + @GET + @Path("/options") + @Produces(MediaType.TEXT_HTML) + public Viewable getSystemOptions() { + return new Viewable("/rest/options.ftl", getSystemOptionsJSON()); + } + + @POST + @Path("/option/{optionName}") + @Consumes("application/x-www-form-urlencoded") + @Produces(MediaType.TEXT_HTML) + public Viewable updateSystemOption(@FormParam("name") String name, @FormParam("value") String value, + @FormParam("kind") String kind) { + try { + work.getContext() + .getOptionManager() + .setOption(OptionValue.createOption( + OptionValue.Kind.valueOf(kind), + OptionValue.OptionType.SYSTEM, + name, + value)); + } catch (Exception e) { + logger.debug("Could not update.", e); + } + return getSystemOptions(); + } + + @XmlRootElement + public class OptionWrapper { + + private String name; + private Object value; + private OptionValue.OptionType type; + private String kind; + + @JsonCreator + public OptionWrapper(String name, Object value, OptionValue.OptionType type, Kind kind) { + this.name = name; + this.value = value; + this.type = type; + this.kind = kind.name(); + } + + public String getName() { + return name; + } + + @JsonIgnore + public String getValueAsString() { + return value.toString(); + } + + public Object getValue() { + return value; + } + + public OptionValue.OptionType getType() { + return type; + } + + public String getKind() { + return kind; + } + } + } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java index b1ed8a5..9521e65 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java @@ -350,7 +350,7 @@ public class Foreman implements Runnable, Closeable, Comparable<Object>{ } } - QueryWorkUnit work = parallelizer.getFragments(context.getOptions().getSessionOptionList(), context.getCurrentEndpoint(), + QueryWorkUnit work = parallelizer.getFragments(context.getOptions().getOptionList(), context.getCurrentEndpoint(), queryId, context.getActiveEndpoints(), context.getPlanReader(), rootFragment, planningSet); this.context.getWorkBus().setFragmentStatusListener(work.getRootFragment().getHandle().getQueryId(), fragmentManager); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/resources/rest/generic.ftl ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/generic.ftl b/exec/java-exec/src/main/resources/rest/generic.ftl index 4b26926..0543755 100644 --- a/exec/java-exec/src/main/resources/rest/generic.ftl +++ b/exec/java-exec/src/main/resources/rest/generic.ftl @@ -50,7 +50,7 @@ <span class="icon-bar"></span> <span class="icon-bar"></span> </button> - <a class="navbar-brand">Apache Drill</a> + <a class="navbar-brand" href="/">Apache Drill</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> @@ -60,6 +60,10 @@ <li><a href="/metrics">Metrics</a></li> <li><a href="/threads">Threads</a></li> </ul> + <ul class="nav navbar-nav navbar-right"> + <li><a href="/options">Options</a></li> + <li><a href="https://cwiki.apache.org/confluence/display/DRILL/Apache+Drill+Wiki">Wiki</a> + </ul> </div> </div> </div> http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/resources/rest/index.ftl ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/index.ftl b/exec/java-exec/src/main/resources/rest/index.ftl index c6e4a4e..99e9d8c 100644 --- a/exec/java-exec/src/main/resources/rest/index.ftl +++ b/exec/java-exec/src/main/resources/rest/index.ftl @@ -17,7 +17,18 @@ <a href="/queries">back</a><br/> <div class="page-header"> </div> - <p class="lead"> Read about Apache Drill <a href="http://incubator.apache.org/drill/drill_overview.html" rel="nofollow">here</a>.</p> + <div class="table-responsive"> + <table class="table table-hover"> + <tbody> + <#list model as stat> + <tr> + <td style="border:none;"><b>${stat.getName()}</b></td> + <td style="border:none; font-family: Courier;">${stat.getValue()}</td> + </tr> + </#list> + </tbody> + </table> + </div> </#macro> <@page_html/> http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/resources/rest/options.ftl ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/options.ftl b/exec/java-exec/src/main/resources/rest/options.ftl new file mode 100644 index 0000000..0092faa --- /dev/null +++ b/exec/java-exec/src/main/resources/rest/options.ftl @@ -0,0 +1,47 @@ +<#-- Licensed to the Apache Software Foundation (ASF) under one or more contributor + license agreements. See the NOTICE file distributed with this work for additional + information regarding copyright ownership. The ASF licenses this file to + You 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. --> + +<#include "*/generic.ftl"> +<#macro page_head> +</#macro> + +<#macro page_body> + <a href="/queries">back</a><br/> + <div class="page-header"> + </div> + <h4>System options</h4> + <div align="right"> + <a href="https://cwiki.apache.org/confluence/display/DRILL/Planning+and+Execution+Options">Documentation</a> + </div> + <div class="table-responsive"> + <table class="table table-hover"> + <tbody> + <#list model as option> + <tr> + <td style="border:none;">${option.getName()}</td> + <td style="border:none;"> + <form class="form-inline" role="form" action="/option/${option.getName()}" method="POST"> + <div class="form-group"> + <input type="text" class="form-control" name="value" value="${option.getValueAsString()}"> + <input type="hidden" class="form-control" name="kind" value="${option.getKind()}"> + <input type="hidden" class="form-control" name="name" value="${option.getName()}"> + </div> + <button type="submit" class="btn btn-default">Update</button> + </form> + </td> + </tr> + </#list> + </tbody> + </table> + </div> +</#macro> + +<@page_html/> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/main/resources/rest/status.ftl ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/status.ftl b/exec/java-exec/src/main/resources/rest/status.ftl index bda01ec..cafa523 100644 --- a/exec/java-exec/src/main/resources/rest/status.ftl +++ b/exec/java-exec/src/main/resources/rest/status.ftl @@ -20,6 +20,7 @@ <strong>${model}</strong> </div> </div> + <a href="/status/options"> System Options </a> </#macro> <@page_html/> http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/ba027c7f/exec/java-exec/src/test/java/org/apache/drill/PlanningBase.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/PlanningBase.java b/exec/java-exec/src/test/java/org/apache/drill/PlanningBase.java index e438ec2..f01a706 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/PlanningBase.java +++ b/exec/java-exec/src/test/java/org/apache/drill/PlanningBase.java @@ -17,15 +17,15 @@ */ package org.apache.drill; -import java.io.IOException; -import java.net.URL; - +import com.codahale.metrics.MetricRegistry; +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; +import com.google.common.io.Resources; import mockit.Mocked; import mockit.NonStrictExpectations; import net.hydromatic.optiq.SchemaPlus; import net.hydromatic.optiq.jdbc.SimpleOptiqSchema; import net.hydromatic.optiq.tools.Frameworks; - import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.util.TestTools; import org.apache.drill.exec.ExecTest; @@ -41,7 +41,7 @@ import org.apache.drill.exec.planner.sql.DrillSqlWorker; import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint; import org.apache.drill.exec.rpc.user.UserSession; import org.apache.drill.exec.server.DrillbitContext; -import org.apache.drill.exec.server.options.OptionManager; +import org.apache.drill.exec.server.options.QueryOptionManager; import org.apache.drill.exec.server.options.SessionOptionManager; import org.apache.drill.exec.server.options.SystemOptionManager; import org.apache.drill.exec.store.StoragePluginRegistry; @@ -49,10 +49,8 @@ import org.apache.drill.exec.store.sys.local.LocalPStoreProvider; import org.junit.Rule; import org.junit.rules.TestRule; -import com.codahale.metrics.MetricRegistry; -import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableList; -import com.google.common.io.Resources; +import java.io.IOException; +import java.net.URL; public class PlanningBase extends ExecTest{ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(PlanningBase.class); @@ -77,9 +75,10 @@ public class PlanningBase extends ExecTest{ final LocalPStoreProvider provider = new LocalPStoreProvider(config); provider.start(); - final SystemOptionManager opt = new SystemOptionManager(config, provider); - opt.init(); - final OptionManager sess = new SessionOptionManager(opt); + final SystemOptionManager systemOptions = new SystemOptionManager(config, provider); + systemOptions.init(); + final SessionOptionManager sessionOptions = new SessionOptionManager(systemOptions); + final QueryOptionManager queryOptions = new QueryOptionManager(sessionOptions); new NonStrictExpectations() { { @@ -90,7 +89,7 @@ public class PlanningBase extends ExecTest{ dbContext.getConfig(); result = config; dbContext.getOptionManager(); - result = opt; + result = systemOptions; dbContext.getCache(); result = cache; dbContext.getPersistentStoreProvider(); @@ -121,9 +120,9 @@ public class PlanningBase extends ExecTest{ context.getActiveEndpoints(); result = ImmutableList.of(DrillbitEndpoint.getDefaultInstance()); context.getPlannerSettings(); - result = new PlannerSettings(sess); + result = new PlannerSettings(queryOptions); context.getOptions(); - result = sess; + result = queryOptions; context.getConfig(); result = config; context.getCache();