Skip to content

Commit 51ae5a5

Browse files
committed
Add ExpressionOptimizerManager
1 parent d477ea1 commit 51ae5a5

File tree

30 files changed

+510
-44
lines changed

30 files changed

+510
-44
lines changed

presto-main/src/main/java/com/facebook/presto/SystemSessionProperties.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ public final class SystemSessionProperties
327327
public static final String INLINE_PROJECTIONS_ON_VALUES = "inline_projections_on_values";
328328
public static final String INCLUDE_VALUES_NODE_IN_CONNECTOR_OPTIMIZER = "include_values_node_in_connector_optimizer";
329329
public static final String SINGLE_NODE_EXECUTION_ENABLED = "single_node_execution_enabled";
330+
public static final String EXPRESSION_OPTIMIZER_NAME = "expression_optimizer_name";
330331

331332
// TODO: Native execution related session properties that are temporarily put here. They will be relocated in the future.
332333
public static final String NATIVE_AGGREGATION_SPILL_ALL = "native_aggregation_spill_all";
@@ -1852,7 +1853,12 @@ public SystemSessionProperties(
18521853
booleanProperty(NATIVE_EXECUTION_SCALE_WRITER_THREADS_ENABLED,
18531854
"Enable automatic scaling of writer threads",
18541855
featuresConfig.isNativeExecutionScaleWritersThreadsEnabled(),
1855-
!featuresConfig.isNativeExecutionEnabled()));
1856+
!featuresConfig.isNativeExecutionEnabled()),
1857+
stringProperty(
1858+
EXPRESSION_OPTIMIZER_NAME,
1859+
"Configure which expression optimizer to use",
1860+
featuresConfig.getExpressionOptimizerName(),
1861+
false));
18561862
}
18571863

18581864
public static boolean isSpoolingOutputBufferEnabled(Session session)
@@ -3153,4 +3159,9 @@ public static boolean isNativeExecutionScaleWritersThreadsEnabled(Session sessio
31533159
{
31543160
return session.getSystemProperty(NATIVE_EXECUTION_SCALE_WRITER_THREADS_ENABLED, Boolean.class);
31553161
}
3162+
3163+
public static String getExpressionOptimizerName(Session session)
3164+
{
3165+
return session.getSystemProperty(EXPRESSION_OPTIMIZER_NAME, String.class);
3166+
}
31563167
}

presto-main/src/main/java/com/facebook/presto/server/PluginManager.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,15 @@
4747
import com.facebook.presto.spi.security.SystemAccessControlFactory;
4848
import com.facebook.presto.spi.session.SessionPropertyConfigurationManagerFactory;
4949
import com.facebook.presto.spi.session.WorkerSessionPropertyProviderFactory;
50+
import com.facebook.presto.spi.sql.planner.ExpressionOptimizerFactory;
5051
import com.facebook.presto.spi.statistics.HistoryBasedPlanStatisticsProvider;
5152
import com.facebook.presto.spi.storage.TempStorageFactory;
5253
import com.facebook.presto.spi.tracing.TracerProvider;
5354
import com.facebook.presto.spi.ttl.ClusterTtlProviderFactory;
5455
import com.facebook.presto.spi.ttl.NodeTtlFetcherFactory;
5556
import com.facebook.presto.sql.analyzer.AnalyzerProviderManager;
5657
import com.facebook.presto.sql.analyzer.QueryPreparerProviderManager;
58+
import com.facebook.presto.sql.expressions.ExpressionOptimizerManager;
5759
import com.facebook.presto.sql.planner.sanity.PlanCheckerProviderManager;
5860
import com.facebook.presto.storage.TempStorageManager;
5961
import com.facebook.presto.tracing.TracerProviderManager;
@@ -141,6 +143,7 @@ public class PluginManager
141143
private final NodeStatusNotificationManager nodeStatusNotificationManager;
142144
private final ClientRequestFilterManager clientRequestFilterManager;
143145
private final PlanCheckerProviderManager planCheckerProviderManager;
146+
private final ExpressionOptimizerManager expressionOptimizerManager;
144147

145148
@Inject
146149
public PluginManager(
@@ -165,7 +168,8 @@ public PluginManager(
165168
TracerProviderManager tracerProviderManager,
166169
NodeStatusNotificationManager nodeStatusNotificationManager,
167170
ClientRequestFilterManager clientRequestFilterManager,
168-
PlanCheckerProviderManager planCheckerProviderManager)
171+
PlanCheckerProviderManager planCheckerProviderManager,
172+
ExpressionOptimizerManager expressionOptimizerManager)
169173
{
170174
requireNonNull(nodeInfo, "nodeInfo is null");
171175
requireNonNull(config, "config is null");
@@ -200,6 +204,7 @@ public PluginManager(
200204
this.nodeStatusNotificationManager = requireNonNull(nodeStatusNotificationManager, "nodeStatusNotificationManager is null");
201205
this.clientRequestFilterManager = requireNonNull(clientRequestFilterManager, "clientRequestFilterManager is null");
202206
this.planCheckerProviderManager = requireNonNull(planCheckerProviderManager, "planCheckerProviderManager is null");
207+
this.expressionOptimizerManager = requireNonNull(expressionOptimizerManager, "expressionManager is null");
203208
}
204209

205210
public void loadPlugins()
@@ -392,6 +397,11 @@ public void installCoordinatorPlugin(CoordinatorPlugin plugin)
392397
log.info("Registering plan checker provider factory %s", planCheckerProviderFactory.getName());
393398
planCheckerProviderManager.addPlanCheckerProviderFactory(planCheckerProviderFactory);
394399
}
400+
401+
for (ExpressionOptimizerFactory expressionOptimizerFactory : plugin.getExpressionOptimizerFactories()) {
402+
log.info("Registering expression optimizer factory %s", expressionOptimizerFactory.getName());
403+
expressionOptimizerManager.addExpressionOptimizerFactory(expressionOptimizerFactory);
404+
}
395405
}
396406

397407
private URLClassLoader buildClassLoader(String plugin)

presto-main/src/main/java/com/facebook/presto/server/PrestoServer.java

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import com.facebook.presto.server.security.PrestoAuthenticatorManager;
5555
import com.facebook.presto.server.security.ServerSecurityModule;
5656
import com.facebook.presto.sql.analyzer.FeaturesConfig;
57+
import com.facebook.presto.sql.expressions.ExpressionOptimizerManager;
5758
import com.facebook.presto.sql.parser.SqlParserOptions;
5859
import com.facebook.presto.sql.planner.sanity.PlanCheckerProviderManager;
5960
import com.facebook.presto.storage.TempStorageManager;
@@ -196,6 +197,8 @@ public void run()
196197
planCheckerProviderManager.loadPlanCheckerProviders(pluginNodeManager);
197198

198199
injector.getInstance(ClientRequestFilterManager.class).loadClientRequestFilters();
200+
injector.getInstance(ExpressionOptimizerManager.class).loadExpressionOptimizerFactories();
201+
199202
startAssociatedProcesses(injector);
200203

201204
injector.getInstance(Announcer.class).start();

presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java

+4
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
import com.facebook.presto.sql.analyzer.MetadataExtractorMBean;
195195
import com.facebook.presto.sql.analyzer.QueryExplainer;
196196
import com.facebook.presto.sql.analyzer.QueryPreparerProviderManager;
197+
import com.facebook.presto.sql.expressions.ExpressionOptimizerManager;
197198
import com.facebook.presto.sql.gen.ExpressionCompiler;
198199
import com.facebook.presto.sql.gen.JoinCompiler;
199200
import com.facebook.presto.sql.gen.JoinFilterFunctionCompiler;
@@ -359,6 +360,9 @@ else if (serverConfig.isCoordinator()) {
359360
binder.bind(SystemSessionProperties.class).in(Scopes.SINGLETON);
360361
binder.bind(SessionPropertyDefaults.class).in(Scopes.SINGLETON);
361362

363+
// expression manager
364+
binder.bind(ExpressionOptimizerManager.class).in(Scopes.SINGLETON);
365+
362366
// schema properties
363367
binder.bind(SchemaPropertyManager.class).in(Scopes.SINGLETON);
364368

presto-main/src/main/java/com/facebook/presto/server/testing/TestingPrestoServer.java

+9
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import com.facebook.presto.split.PageSourceManager;
7575
import com.facebook.presto.split.SplitManager;
7676
import com.facebook.presto.sql.analyzer.FeaturesConfig;
77+
import com.facebook.presto.sql.expressions.ExpressionOptimizerManager;
7778
import com.facebook.presto.sql.parser.SqlParser;
7879
import com.facebook.presto.sql.parser.SqlParserOptions;
7980
import com.facebook.presto.sql.planner.ConnectorPlanOptimizerManager;
@@ -171,6 +172,7 @@ public class TestingPrestoServer
171172
private final TaskManager taskManager;
172173
private final GracefulShutdownHandler gracefulShutdownHandler;
173174
private final ShutdownAction shutdownAction;
175+
private final ExpressionOptimizerManager expressionManager;
174176
private final RequestBlocker requestBlocker;
175177
private final boolean resourceManager;
176178
private final boolean catalogServer;
@@ -373,6 +375,7 @@ public TestingPrestoServer(
373375
procedureTester = injector.getInstance(ProcedureTester.class);
374376
splitManager = injector.getInstance(SplitManager.class);
375377
pageSourceManager = injector.getInstance(PageSourceManager.class);
378+
expressionManager = injector.getInstance(ExpressionOptimizerManager.class);
376379
if (coordinator) {
377380
dispatchManager = injector.getInstance(DispatchManager.class);
378381
queryManager = injector.getInstance(QueryManager.class);
@@ -390,6 +393,7 @@ public TestingPrestoServer(
390393
eventListenerManager = ((TestingEventListenerManager) injector.getInstance(EventListenerManager.class));
391394
clusterStateProvider = null;
392395
planCheckerProviderManager = injector.getInstance(PlanCheckerProviderManager.class);
396+
expressionManager.loadExpressionOptimizerFactories();
393397
}
394398
else if (resourceManager) {
395399
dispatchManager = null;
@@ -710,6 +714,11 @@ public ShutdownAction getShutdownAction()
710714
return shutdownAction;
711715
}
712716

717+
public ExpressionOptimizerManager getExpressionManager()
718+
{
719+
return expressionManager;
720+
}
721+
713722
public boolean isCoordinator()
714723
{
715724
return coordinator;

presto-main/src/main/java/com/facebook/presto/sql/analyzer/FeaturesConfig.java

+15
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import static com.facebook.presto.sql.analyzer.FeaturesConfig.AggregationPartitioningMergingStrategy.LEGACY;
4141
import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinNotNullInferenceStrategy.NONE;
4242
import static com.facebook.presto.sql.analyzer.FeaturesConfig.TaskSpillingStrategy.ORDER_BY_CREATE_TIME;
43+
import static com.facebook.presto.sql.expressions.ExpressionOptimizerManager.DEFAULT_EXPRESSION_OPTIMIZER_NAME;
4344
import static com.facebook.presto.sql.tree.CreateView.Security.DEFINER;
4445
import static com.google.common.collect.ImmutableList.toImmutableList;
4546
import static io.airlift.units.DataSize.Unit.KILOBYTE;
@@ -293,6 +294,7 @@ public class FeaturesConfig
293294
private boolean prestoSparkExecutionEnvironment;
294295
private boolean singleNodeExecutionEnabled;
295296
private boolean nativeExecutionScaleWritersThreadsEnabled;
297+
private String expressionOptimizerName = DEFAULT_EXPRESSION_OPTIMIZER_NAME;
296298

297299
public enum PartitioningPrecisionStrategy
298300
{
@@ -2915,4 +2917,17 @@ public FeaturesConfig setNativeExecutionScaleWritersThreadsEnabled(boolean nativ
29152917
this.nativeExecutionScaleWritersThreadsEnabled = nativeExecutionScaleWritersThreadsEnabled;
29162918
return this;
29172919
}
2920+
2921+
public String getExpressionOptimizerName()
2922+
{
2923+
return expressionOptimizerName;
2924+
}
2925+
2926+
@Config("expression-optimizer-name")
2927+
@ConfigDescription("Set the expression optimizer name for parsing and analyzing.")
2928+
public FeaturesConfig setExpressionOptimizerName(String expressionOptimizerName)
2929+
{
2930+
this.expressionOptimizerName = expressionOptimizerName;
2931+
return this;
2932+
}
29182933
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.facebook.presto.sql.expressions;
15+
16+
import com.facebook.presto.FullConnectorSession;
17+
import com.facebook.presto.Session;
18+
import com.facebook.presto.metadata.FunctionAndTypeManager;
19+
import com.facebook.presto.nodeManager.PluginNodeManager;
20+
import com.facebook.presto.spi.ConnectorSession;
21+
import com.facebook.presto.spi.NodeManager;
22+
import com.facebook.presto.spi.relation.ExpressionOptimizer;
23+
import com.facebook.presto.spi.sql.planner.ExpressionOptimizerContext;
24+
import com.facebook.presto.spi.sql.planner.ExpressionOptimizerFactory;
25+
import com.facebook.presto.sql.relational.FunctionResolution;
26+
import com.facebook.presto.sql.relational.RowExpressionOptimizer;
27+
import com.google.common.collect.ImmutableList;
28+
29+
import javax.inject.Inject;
30+
31+
import java.io.File;
32+
import java.io.IOException;
33+
import java.io.UncheckedIOException;
34+
import java.util.HashMap;
35+
import java.util.List;
36+
import java.util.Map;
37+
import java.util.concurrent.ConcurrentHashMap;
38+
39+
import static com.facebook.presto.SystemSessionProperties.getExpressionOptimizerName;
40+
import static com.facebook.presto.util.PropertiesUtil.loadProperties;
41+
import static com.google.common.base.Preconditions.checkArgument;
42+
import static com.google.common.base.Strings.isNullOrEmpty;
43+
import static com.google.common.io.Files.getNameWithoutExtension;
44+
import static java.util.Objects.requireNonNull;
45+
46+
public class ExpressionOptimizerManager
47+
{
48+
public static final String DEFAULT_EXPRESSION_OPTIMIZER_NAME = "default";
49+
private static final File EXPRESSION_MANAGER_CONFIGURATION_DIRECTORY = new File("etc/expression-manager/");
50+
private static final String EXPRESSION_MANAGER_FACTORY_NAME = "expression-manager-factory.name";
51+
52+
private final NodeManager nodeManager;
53+
private final FunctionAndTypeManager functionAndTypeManager;
54+
private final FunctionResolution functionResolution;
55+
private final File configurationDirectory;
56+
57+
private final Map<String, ExpressionOptimizerFactory> expressionOptimizerFactories = new ConcurrentHashMap<>();
58+
private final Map<String, ExpressionOptimizer> expressionOptimizers = new ConcurrentHashMap<>();
59+
60+
@Inject
61+
public ExpressionOptimizerManager(PluginNodeManager nodeManager, FunctionAndTypeManager functionAndTypeManager)
62+
{
63+
this(nodeManager, functionAndTypeManager, EXPRESSION_MANAGER_CONFIGURATION_DIRECTORY);
64+
}
65+
66+
public ExpressionOptimizerManager(PluginNodeManager nodeManager, FunctionAndTypeManager functionAndTypeManager, File configurationDirectory)
67+
{
68+
requireNonNull(nodeManager, "nodeManager is null");
69+
this.nodeManager = requireNonNull(nodeManager, "nodeManager is null");
70+
this.functionAndTypeManager = requireNonNull(functionAndTypeManager, "functionAndTypeManager is null");
71+
this.functionResolution = new FunctionResolution(functionAndTypeManager.getFunctionAndTypeResolver());
72+
this.configurationDirectory = requireNonNull(configurationDirectory, "configurationDirectory is null");
73+
expressionOptimizers.put(DEFAULT_EXPRESSION_OPTIMIZER_NAME, new RowExpressionOptimizer(functionAndTypeManager));
74+
}
75+
76+
public void loadExpressionOptimizerFactories()
77+
{
78+
try {
79+
for (File file : listFiles(configurationDirectory)) {
80+
if (file.isFile() && file.getName().endsWith(".properties")) {
81+
loadExpressionOptimizerFactory(file);
82+
}
83+
}
84+
}
85+
catch (IOException e) {
86+
throw new UncheckedIOException("Failed to load expression manager configuration", e);
87+
}
88+
}
89+
90+
private void loadExpressionOptimizerFactory(File configurationFile)
91+
throws IOException
92+
{
93+
String name = getNameWithoutExtension(configurationFile.getName());
94+
checkArgument(!isNullOrEmpty(name), "File name is empty, full path: %s", configurationFile.getAbsolutePath());
95+
checkArgument(!name.equals(DEFAULT_EXPRESSION_OPTIMIZER_NAME), "Cannot name an expression optimizer instance %s", DEFAULT_EXPRESSION_OPTIMIZER_NAME);
96+
97+
Map<String, String> properties = new HashMap<>(loadProperties(configurationFile));
98+
String factoryName = properties.remove(EXPRESSION_MANAGER_FACTORY_NAME);
99+
checkArgument(!isNullOrEmpty(factoryName), "%s does not contain %s", configurationFile, EXPRESSION_MANAGER_FACTORY_NAME);
100+
checkArgument(expressionOptimizerFactories.containsKey(factoryName),
101+
"ExpressionOptimizerFactory %s is not registered, registered factories: ", factoryName, expressionOptimizerFactories.keySet());
102+
103+
ExpressionOptimizer optimizer = expressionOptimizerFactories.get(factoryName).createOptimizer(
104+
properties,
105+
new ExpressionOptimizerContext(nodeManager, functionAndTypeManager, functionResolution));
106+
expressionOptimizers.put(name, optimizer);
107+
}
108+
109+
public void addExpressionOptimizerFactory(ExpressionOptimizerFactory expressionOptimizerFactory)
110+
{
111+
String name = expressionOptimizerFactory.getName();
112+
checkArgument(
113+
expressionOptimizerFactories.putIfAbsent(name, expressionOptimizerFactory) == null,
114+
"ExpressionOptimizerFactory %s is already registered", name);
115+
}
116+
117+
public ExpressionOptimizer getExpressionOptimizer(ConnectorSession connectorSession)
118+
{
119+
// TODO: Remove this check once we have a more appropriate abstraction for session properties retrieved from plugins
120+
checkArgument(connectorSession instanceof FullConnectorSession, "connectorSession is not an instance of FullConnectorSession");
121+
Session session = ((FullConnectorSession) connectorSession).getSession();
122+
String expressionOptimizerName = getExpressionOptimizerName(session);
123+
checkArgument(expressionOptimizers.containsKey(expressionOptimizerName), "ExpressionOptimizer '%s' is not registered", expressionOptimizerName);
124+
return expressionOptimizers.get(expressionOptimizerName);
125+
}
126+
127+
private static List<File> listFiles(File directory)
128+
{
129+
if (directory.isDirectory()) {
130+
File[] files = directory.listFiles();
131+
if (files != null) {
132+
return ImmutableList.copyOf(files);
133+
}
134+
}
135+
return ImmutableList.of();
136+
}
137+
}

0 commit comments

Comments
 (0)