org.bboxdb.network.client.tools.AbtractClusterFutureBuilder Maven / Gradle / Ivy
/*******************************************************************************
*
* Copyright (C) 2015-2018 the BBoxDB project
*
* 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 org.bboxdb.network.client.tools;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import org.bboxdb.commons.math.Hyperrectangle;
import org.bboxdb.distribution.membership.BBoxDBInstance;
import org.bboxdb.distribution.membership.MembershipConnectionService;
import org.bboxdb.distribution.partitioner.SpacePartitionerHelper;
import org.bboxdb.distribution.region.DistributionRegion;
import org.bboxdb.distribution.region.DistributionRegionHelper;
import org.bboxdb.misc.BBoxDBException;
import org.bboxdb.network.client.BBoxDBConnection;
import org.bboxdb.network.client.future.network.NetworkOperationFuture;
import org.bboxdb.network.client.future.network.NetworkOperationFutureMultiImpl;
import org.bboxdb.network.routing.RoutingHeader;
import org.bboxdb.network.routing.RoutingHop;
import org.bboxdb.network.routing.RoutingHopHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbtractClusterFutureBuilder {
/**
* The distribution region
*/
private final DistributionRegion distributionRegion;
/**
* The bounding box
*/
private final Hyperrectangle boundingBox;
/**
* The membership connection service
*/
private final MembershipConnectionService membershipConnectionService;
/**
* The cluster operation type
*/
private ClusterOperationType clusterOperationType;
/**
* The Logger
*/
private final static Logger logger = LoggerFactory.getLogger(AbtractClusterFutureBuilder.class);
public AbtractClusterFutureBuilder(final ClusterOperationType clusterOperationType,
final String table, final Hyperrectangle boundingBox) throws BBoxDBException {
this.clusterOperationType = clusterOperationType;
this.distributionRegion = SpacePartitionerHelper.getRootNode(table);
this.boundingBox = boundingBox;
this.membershipConnectionService = MembershipConnectionService.getInstance();
}
public Supplier> getSupplier() {
if(clusterOperationType == ClusterOperationType.READ_FROM_NODES_HA_IF_REPLICATED) {
return getReplicatedSupplier();
} else {
return getUnreplicatedSupplier();
}
}
/**
* Get the replicated supplier
* Only one read operation per replicate needs to be successful
*
* @return
*/
private Supplier> getReplicatedSupplier() {
final Supplier> supplier = () -> {
final List futures = new ArrayList<>();
final List regions = RoutingHopHelper.getRegionsForPredicate(
distributionRegion, boundingBox, DistributionRegionHelper.PREDICATE_REGIONS_FOR_READ);
if(regions.isEmpty()) {
logger.error("Got empty hop list by bbox {} read {}", boundingBox, clusterOperationType);
}
for(final DistributionRegion region : regions) {
final List futuresPerReplicate = new ArrayList<>();
for(final BBoxDBInstance instance : region.getSystems()) {
final BBoxDBConnection connection
= membershipConnectionService.getConnectionForInstance(instance);
// Node is down
if(connection == null) {
logger.debug("Skipping connection for {}", instance.getInetSocketAddress());
continue;
}
final RoutingHop hop = new RoutingHop(instance, Arrays.asList(region.getRegionId()));
final RoutingHeader routingHeader = new RoutingHeader((short) 0, Arrays.asList(hop));
final Supplier> future = buildFuture(connection, routingHeader);
futuresPerReplicate.addAll(future.get());
}
// Only one future of the list needs to be successful
final NetworkOperationFutureMultiImpl future = new NetworkOperationFutureMultiImpl(
futuresPerReplicate);
futures.add(future);
}
return futures;
};
return supplier;
}
/**
* Get the unreplicated supplier
* All operations needs to be successful
*
* @return
*/
private Supplier> getUnreplicatedSupplier() {
final Supplier> supplier = () -> {
final List futures = new ArrayList<>();
final List hops = getHops();
if(hops.isEmpty()) {
logger.error("Got empty hop list by bbox {} read {}", boundingBox, clusterOperationType);
}
for(final RoutingHop hop : hops) {
final BBoxDBInstance instance = hop.getDistributedInstance();
final BBoxDBConnection connection
= membershipConnectionService.getConnectionForInstance(instance);
final RoutingHeader routingHeader = new RoutingHeader((short) 0, Arrays.asList(hop));
final Supplier> future = buildFuture(connection, routingHeader);
futures.addAll(future.get());
}
return futures;
};
return supplier;
}
/**
* Build the future
* @param routingHeader
* @param connection
* @return
*/
protected abstract Supplier> buildFuture(
final BBoxDBConnection connection, final RoutingHeader routingHeader);
/**
* Get the hop for the operation
* @return
*/
private List getHops() {
switch(clusterOperationType) {
case READ_FROM_NODES:
return RoutingHopHelper.getRoutingHopsForRead(distributionRegion, boundingBox);
case WRITE_TO_NODES:
return RoutingHopHelper.getRoutingHopsForWrite(distributionRegion, boundingBox);
default:
throw new IllegalArgumentException("Unknown type: " + clusterOperationType);
}
}
}