/*
* 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.basho.riak.presto;
import com.basho.riak.presto.models.*;
import com.facebook.presto.spi.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import io.airlift.json.JsonCodecFactory;
import io.airlift.log.Logger;
import javax.inject.Inject;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import static com.google.common.base.Preconditions.*;
public class RiakSplitManager
implements ConnectorSplitManager {
private static final Logger log = Logger.get(RiakSplitManager.class);
private final String connectorId;
private final RiakClient riakClient;
private final RiakConfig riakConfig;
private final DirectConnection directConnection;
@Inject
public RiakSplitManager(RiakConnectorId connectorId, RiakClient riakClient,
RiakConfig config, DirectConnection directConnection) {
this.connectorId = checkNotNull(connectorId, "connectorId is null").toString();
this.riakClient = checkNotNull(riakClient, "client is null");
this.riakConfig = checkNotNull(config);
this.directConnection = checkNotNull(directConnection);
}
// TODO: get the right partitions right here
@Override
public ConnectorPartitionResult getPartitions(ConnectorTableHandle tableHandle, TupleDomain<ColumnHandle> tupleDomain) {
checkArgument(tableHandle instanceof RiakTableHandle, "tableHandle is not an instance of RiakTableHandle");
RiakTableHandle riakTableHandle = (RiakTableHandle) tableHandle;
log.info("==========================tupleDomain=============================");
log.info(tupleDomain.toString());
try {
String parentTable = PRSubTable.parentTableName(riakTableHandle.getTableName());
SchemaTableName parentSchemaTable = new SchemaTableName(
riakTableHandle.getSchemaName(),
parentTable);
PRTable table = riakClient.getTable(parentSchemaTable);
List<String> indexedColumns = new LinkedList<String>();
for (RiakColumn riakColumn : table.getColumns()) {
if (riakColumn.getIndex()) {
indexedColumns.add(riakColumn.getName());
}
}
// Riak connector has only one partition
List<ConnectorPartition> partitions = ImmutableList.<ConnectorPartition>of(
new RiakPartition(riakTableHandle.getSchemaName(),
riakTableHandle.getTableName(),
tupleDomain,
indexedColumns));
// Riak connector does not do any additional processing/filtering with the TupleDomain, so just return the whole TupleDomain
return new ConnectorPartitionResult(partitions, tupleDomain);
} catch (Exception e) {
log.error("interrupted: %s", e.toString());
throw new TableNotFoundException(riakTableHandle.toSchemaTableName());
}
}
// TODO: return correct splits from partitions
@Override
public ConnectorSplitSource getPartitionSplits(ConnectorTableHandle tableHandle,
List<ConnectorPartition> partitions) {
checkNotNull(partitions, "partitions is null");
checkArgument(partitions.size() == 1, "Expected one partition but got %s", partitions.size());
ConnectorPartition partition = partitions.get(0);
checkArgument(partition instanceof RiakPartition, "partition is not an instance of RiakPartition");
//RiakPartition riakPartition = (RiakPartition) partition;
RiakTableHandle riakTableHandle = (RiakTableHandle) tableHandle;
try {
String parentTable = PRSubTable.parentTableName(riakTableHandle.getTableName());
SchemaTableName parentSchemaTable = new SchemaTableName(
riakTableHandle.getSchemaName(),
parentTable);
PRTable table = riakClient.getTable(parentSchemaTable);
log.debug("> %s", table.getColumns().toString());
// add all nodes at the cluster here
List<ConnectorSplit> splits = Lists.newArrayList();
String hosts = riakClient.getHosts();
log.debug(hosts);
if (riakConfig.getLocalNode() != null) {
// TODO: make coverageSplits here
//try {
DirectConnection conn = directConnection;
//conn.connect(riak);
//conn.ping();
Coverage coverage = new Coverage(conn);
coverage.plan();
List<SplitTask> splitTasks = coverage.getSplits();
log.debug("print coverage plan==============");
log.debug(coverage.toString());
for (SplitTask split : splitTasks) {
log.info("============printing split data at " + split.getHost() + "===============");
//log.debug(((OtpErlangObject)split.getTask()).toString());
log.info(split.toString());
CoverageSplit coverageSplit = new CoverageSplit(
riakTableHandle, //maybe toplevel or subtable
table, //toplevel PRTable
split.getHost(),
split.toString(),
partition.getTupleDomain());
//log.info(new JsonCodecFactory().jsonCodec(CoverageSplit.class).toJson(coverageSplit));
splits.add(coverageSplit);
}
} else {
// TODO: in Riak connector, you only need single access point for each presto worker???
log.error("localNode must be set and working");
log.debug(hosts);
//splits.add(new CoverageSplit(connectorId, riakTableHandle.getSchemaName(),
// riakTableHandle.getTableName(), hosts,
// partition.getTupleDomain(),
// ((RiakPartition) partition).getIndexedColumns()));
}
log.debug("table %s.%s has %d splits.",
riakTableHandle.getSchemaName(), riakTableHandle.getTableName(),
splits.size());
Collections.shuffle(splits);
return new FixedSplitSource(connectorId, splits);
} catch (Exception e) {
throw new TableNotFoundException(riakTableHandle.toSchemaTableName());
}
// this can happen if table is removed during a query
}
}