/**
* 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.tools.query.comparison;
import com.linkedin.pinot.common.request.helper.ControllerRequestBuilder;
import com.linkedin.pinot.common.utils.NetUtil;
import com.linkedin.pinot.controller.helix.ControllerRequestURLBuilder;
import com.linkedin.pinot.tools.admin.command.AddTableCommand;
import com.linkedin.pinot.tools.admin.command.CreateSegmentCommand;
import com.linkedin.pinot.tools.admin.command.DeleteClusterCommand;
import com.linkedin.pinot.tools.admin.command.PostQueryCommand;
import com.linkedin.pinot.tools.admin.command.StartBrokerCommand;
import com.linkedin.pinot.tools.admin.command.StartControllerCommand;
import com.linkedin.pinot.tools.admin.command.StartServerCommand;
import com.linkedin.pinot.tools.admin.command.StartZookeeperCommand;
import com.linkedin.pinot.tools.admin.command.UploadSegmentCommand;
import com.linkedin.pinot.tools.perf.PerfBenchmarkDriver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.linkedin.pinot.tools.admin.command.AbstractBaseAdminCommand.sendPostRequest;
public class ClusterStarter {
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterStarter.class);
private String _controllerPort;
private String _brokerHost;
private String _brokerPort;
private String _serverPort;
private String _perfUrl;
private String _zkAddress;
private String _clusterName;
private String _localhost;
private String _tableName;
private String _tableConfigFile;
private String _timeColumnName;
private String _timeUnit;
private String _inputDataDir;
private String _segmentName;
private String _schemaFileName;
private String _segmentDirName;
private boolean _startZookeeper;
private boolean _enableStarTreeIndex;
private static final long TIMEOUT_IN_MILLISECONDS = 200 * 1000;
ClusterStarter(QueryComparisonConfig config)
throws SocketException, UnknownHostException {
_segmentName = config.getSegmentName();
_schemaFileName = config.getSchemaFileName();
_inputDataDir = config.getInputDataDir();
_segmentDirName = config.getSegmentsDir();
_localhost = NetUtil.getHostAddress();
_zkAddress = config.getZookeeperAddress();
_clusterName = config.getClusterName();
_controllerPort = config.getControllerPort();
_brokerHost = config.getBrokerHost();
_brokerPort = config.getBrokerPort();
_serverPort = config.getServerPort();
_perfUrl = config.getPerfUrl();
_startZookeeper = config.getStartZookeeper();
_tableName = config.getTableName();
_timeColumnName = config.getTimeColumnName();
_timeUnit = config.getTimeUnit();
_tableConfigFile = config.getTableConfigFile();
_enableStarTreeIndex = false;
}
public ClusterStarter setControllerPort(String controllerPort) {
_controllerPort = controllerPort;
return this;
}
public ClusterStarter setBrokerHost(String brokerHost) {
_brokerHost = brokerHost;
return this;
}
public ClusterStarter setBrokerPort(String brokerPort) {
_brokerPort = brokerPort;
return this;
}
public ClusterStarter setServerPort(String serverPort) {
_serverPort = serverPort;
return this;
}
public ClusterStarter setZkAddress(String zkAddress) {
_zkAddress = zkAddress;
return this;
}
public ClusterStarter setStartZookeeper(boolean startZookeeper) {
_startZookeeper = startZookeeper;
return this;
}
public ClusterStarter setClusterName(String clusterName) {
_clusterName = clusterName;
return this;
}
public ClusterStarter setSegmentDirName(String segmentDirName) {
_segmentDirName = segmentDirName;
return this;
}
public ClusterStarter setEnableStarTree(boolean value) {
_enableStarTreeIndex = value;
return this;
}
public ClusterStarter setTableName(String tableName) {
_tableName = tableName;
return this;
}
private void startZookeeper()
throws IOException {
if (_startZookeeper) {
StartZookeeperCommand zkStarter = new StartZookeeperCommand();
zkStarter.execute();
}
}
private void startController()
throws Exception {
// Delete existing cluster first.
DeleteClusterCommand deleteClusterCommand = new DeleteClusterCommand().setClusterName(_clusterName);
deleteClusterCommand.execute();
StartControllerCommand controllerStarter =
new StartControllerCommand().setControllerPort(_controllerPort).setZkAddress(_zkAddress)
.setClusterName(_clusterName);
controllerStarter.execute();
}
private void startBroker()
throws Exception {
StartBrokerCommand brokerStarter =
new StartBrokerCommand().setClusterName(_clusterName).setPort(Integer.valueOf(_brokerPort));
brokerStarter.execute();
}
private void startServer()
throws Exception {
StartServerCommand serverStarter =
new StartServerCommand().setPort(Integer.valueOf(_serverPort)).setClusterName(_clusterName);
serverStarter.execute();
}
private void addTable()
throws Exception {
if (_tableConfigFile != null) {
AddTableCommand addTableCommand =
new AddTableCommand().setControllerPort(_controllerPort).setFilePath(_tableConfigFile).setExecute(true);
addTableCommand.execute();
return;
}
if (_tableName == null) {
LOGGER.error("Table info not specified in configuration, please specify either config file or table name");
return;
}
String controllerAddress = "http://" + _localhost + ":" + _controllerPort;
JSONObject request = ControllerRequestBuilder
.buildCreateOfflineTableJSON(_tableName, "server", "broker", _timeColumnName, _timeUnit,
"", "", 3, "BalanceNumSegmentAssignmentStrategy");
sendPostRequest(ControllerRequestURLBuilder.baseUrl(controllerAddress).forTableCreate(), request.toString());
}
private void uploadData()
throws Exception {
UploadSegmentCommand segmentUploader =
new UploadSegmentCommand().setSegmentDir(_segmentDirName).setControllerHost(_localhost)
.setControllerPort(_controllerPort);
segmentUploader.execute();
PerfBenchmarkDriver.waitForExternalViewUpdate(_zkAddress, _clusterName, TIMEOUT_IN_MILLISECONDS);
}
private void createSegments()
throws Exception {
if (_inputDataDir != null) {
CreateSegmentCommand segmentCreator =
new CreateSegmentCommand().setDataDir(_inputDataDir).setSchemaFile(_schemaFileName)
.setTableName(_tableName).setSegmentName(_segmentName).setOutDir(_segmentDirName).setOverwrite(true)
.setEnableStarTreeIndex(_enableStarTreeIndex);
segmentCreator.execute();
}
}
public void start()
throws Exception {
startZookeeper();
startController();
startBroker();
startServer();
addTable();
createSegments();
uploadData();
}
public String query(String query)
throws Exception {
LOGGER.debug("Running query on Pinot Cluster");
PostQueryCommand queryRunner =
new PostQueryCommand().setQuery(query).setBrokerHost(_brokerHost).setBrokerPort(_brokerPort);
return queryRunner.run();
}
public int perfQuery(String query)
throws Exception {
LOGGER.debug("Running perf query on Pinot Cluster");
String encodedQuery = URLEncoder.encode(query, "UTF-8");
String brokerUrl = _perfUrl + encodedQuery;
LOGGER.info("Executing command: " + brokerUrl);
URLConnection conn = new URL(brokerUrl).openConnection();
conn.setDoOutput(true);
long startTime = System.currentTimeMillis();
InputStream input = conn.getInputStream();
long endTime = System.currentTimeMillis();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
LOGGER.debug("Actual response: " + sb.toString());
return (int) (endTime - startTime);
}
}