/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.linkedin.pinot.core.query.scheduler;
import com.google.common.base.Preconditions;
import com.linkedin.pinot.common.query.QueryExecutor;
import java.lang.reflect.Constructor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class QuerySchedulerFactory {
private static final String FCFS_ALGORITHM = "fcfs";
private static final String DEFAULT_QUERY_SCHEDULER_ALGORITHM = FCFS_ALGORITHM;
private static final String ALGORITHM_NAME_CONFIG_KEY = "name";
private static Logger LOGGER = LoggerFactory.getLogger(QuerySchedulerFactory.class);
/**
* Static factory to instantiate query scheduler based on scheduler configuration.
* 'name' configuration in the scheduler will decide which scheduler instance to create
* Besides known instances, 'name' can be a classname
* @param schedulerConfig scheduler specific configuration
* @param queryExecutor QueryExecutor to use
* @return
*/
public static @Nonnull QueryScheduler create(@Nonnull Configuration schedulerConfig,
@Nonnull QueryExecutor queryExecutor) {
Preconditions.checkNotNull(schedulerConfig);
Preconditions.checkNotNull(queryExecutor);
String schedulerName = schedulerConfig.getString(ALGORITHM_NAME_CONFIG_KEY,
DEFAULT_QUERY_SCHEDULER_ALGORITHM).toLowerCase();
if (schedulerName.equals(FCFS_ALGORITHM)) {
LOGGER.info("Using FCFS query scheduler");
return new FCFSQueryScheduler(schedulerConfig, queryExecutor);
}
// didn't find by name so try by classname
QueryScheduler scheduler = getQuerySchedulerByClassName(schedulerName, schedulerConfig, queryExecutor);
if (scheduler != null) {
return scheduler;
}
// if we don't find the configured algorithm we warn and use the default one
// because it's better to execute with poor algorithm than completely fail.
// Failure on bad configuration will cause outage vs an inferior algorithm that
// will provide degraded service
LOGGER.warn("Scheduler {} not found. Using default FCFS query scheduler", schedulerName);
return new FCFSQueryScheduler(schedulerConfig, queryExecutor);
}
private static @Nullable QueryScheduler getQuerySchedulerByClassName(String className, Configuration schedulerConfig,
QueryExecutor queryExecutor) {
try {
Constructor<?> constructor =
Class.forName(className).getDeclaredConstructor(Configuration.class, QueryExecutor.class);
constructor.setAccessible(true);
return (QueryScheduler) constructor.newInstance(new Object[]{schedulerConfig, queryExecutor});
} catch (Exception e) {
LOGGER.error("Failed to instantiate scheduler class by name: {}", className, e);
return null;
}
}
}