package com.linkedin.thirdeye.client.cache;
import java.util.List;
import org.apache.helix.manager.zk.ZKHelixAdmin;
import org.apache.helix.manager.zk.ZNRecordSerializer;
import org.apache.helix.manager.zk.ZkClient;
import org.apache.helix.model.InstanceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.cache.CacheLoader;
import com.linkedin.pinot.client.Connection;
import com.linkedin.pinot.client.ConnectionFactory;
import com.linkedin.pinot.client.PinotClientException;
import com.linkedin.pinot.client.ResultSet;
import com.linkedin.pinot.client.ResultSetGroup;
import com.linkedin.thirdeye.client.pinot.PinotQuery;
import com.linkedin.thirdeye.client.pinot.PinotThirdEyeClientConfig;
public class ResultSetGroupCacheLoader extends CacheLoader<PinotQuery, ResultSetGroup> {
private static final Logger LOG = LoggerFactory.getLogger(ResultSetGroupCacheLoader.class);
private static int MAX_CONNECTIONS;
static {
try {
MAX_CONNECTIONS = Integer.parseInt(System.getProperty("max_pinot_connections", "25"));
} catch (Exception e) {
MAX_CONNECTIONS = 25;
}
}
private Connection[] connections;
private static final String BROKER_PREFIX = "Broker_";
public ResultSetGroupCacheLoader(PinotThirdEyeClientConfig pinotThirdEyeClientConfig) {
if (pinotThirdEyeClientConfig.getBrokerUrl() != null
&& pinotThirdEyeClientConfig.getBrokerUrl().trim().length() > 0) {
ZkClient zkClient = new ZkClient(pinotThirdEyeClientConfig.getZookeeperUrl());
zkClient.setZkSerializer(new ZNRecordSerializer());
zkClient.waitUntilConnected();
ZKHelixAdmin helixAdmin = new ZKHelixAdmin(zkClient);
List<String> thirdeyeBrokerList = helixAdmin.getInstancesInClusterWithTag(
pinotThirdEyeClientConfig.getClusterName(), pinotThirdEyeClientConfig.getTag());
String[] thirdeyeBrokers = new String[thirdeyeBrokerList.size()];
for (int i = 0; i < thirdeyeBrokerList.size(); i++) {
String instanceName = thirdeyeBrokerList.get(i);
InstanceConfig instanceConfig =
helixAdmin.getInstanceConfig(pinotThirdEyeClientConfig.getClusterName(), instanceName);
thirdeyeBrokers[i] = instanceConfig.getHostName().replaceAll(BROKER_PREFIX, "") + ":"
+ instanceConfig.getPort();
}
this.connections = new Connection[MAX_CONNECTIONS];
for (int i = 0; i < MAX_CONNECTIONS; i++) {
connections[i] = ConnectionFactory.fromHostList(thirdeyeBrokers);
}
} else {
this.connections = new Connection[MAX_CONNECTIONS];
for (int i = 0; i < MAX_CONNECTIONS; i++) {
connections[i] = ConnectionFactory.fromZookeeper(pinotThirdEyeClientConfig.getZookeeperUrl()
+ "/" + pinotThirdEyeClientConfig.getClusterName());
}
}
}
@Override
public ResultSetGroup load(PinotQuery pinotQuery) throws Exception {
try {
Connection connection = getConnection();
synchronized (connection) {
long start = System.currentTimeMillis();
ResultSetGroup resultSetGroup =
connection.execute(pinotQuery.getTableName(), pinotQuery.getPql());
if (LOG.isDebugEnabled()) {
LOG.debug("Query:{} response:{}", pinotQuery.getPql(), format(resultSetGroup));
}
long end = System.currentTimeMillis();
LOG.info("Query:{} took:{} ms", pinotQuery.getPql(), (end - start));
return resultSetGroup;
}
} catch (PinotClientException cause) {
LOG.error("Error when running pql:" + pinotQuery.getPql(), cause);
throw new PinotClientException("Error when running pql:" + pinotQuery.getPql(), cause);
}
}
private Connection getConnection() {
return connections[(int) (Thread.currentThread().getId() % MAX_CONNECTIONS)];
}
private static String format(ResultSetGroup result) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < result.getResultSetCount(); i++) {
ResultSet resultSet = result.getResultSet(i);
for (int c = 0; c < resultSet.getColumnCount(); c++) {
sb.append(resultSet.getColumnName(c)).append("=").append(resultSet.getDouble(c));
}
}
return sb.toString();
}
}