All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bboxdb.network.routing.PackageRouter 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.routing;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.bboxdb.commons.concurrent.ExceptionSafeRunnable;
import org.bboxdb.distribution.membership.BBoxDBInstance;
import org.bboxdb.distribution.membership.MembershipConnectionService;
import org.bboxdb.distribution.zookeeper.ZookeeperClientFactory;
import org.bboxdb.misc.BBoxDBException;
import org.bboxdb.network.client.BBoxDBClient;
import org.bboxdb.network.client.BBoxDBConnection;
import org.bboxdb.network.client.future.EmptyResultFuture;
import org.bboxdb.network.packages.PackageEncodeException;
import org.bboxdb.network.packages.request.InsertTupleRequest;
import org.bboxdb.network.packages.response.ErrorResponse;
import org.bboxdb.network.packages.response.SuccessResponse;
import org.bboxdb.network.server.ErrorMessages;
import org.bboxdb.network.server.connection.ClientConnectionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PackageRouter {
	
	/**
	 * The thread pool
	 */
	protected final ExecutorService threadPool;
	
	/**
	 * The client connection handler
	 */
	protected final ClientConnectionHandler clientConnectionHandler;
	
	/**
	 * Routing timeout
	 */
	protected final int ROUTING_TIMEOUT_IN_SEC = 2;
	
	/**
	 * The Logger
	 */
	private final static Logger logger = LoggerFactory.getLogger(PackageRouter.class);

	public PackageRouter(final ExecutorService threadPool, 
			final ClientConnectionHandler clientConnectionHandler) {
		
		this.threadPool = threadPool;
		this.clientConnectionHandler = clientConnectionHandler;
	}

	/**
	 * Perform the routing task async
	 * @param packageSequence
	 * @param insertTupleRequest
	 * @param boundingBox
	 */
	public void performInsertPackageRoutingAsync(final short packageSequence, 
			final InsertTupleRequest insertTupleRequest) {
	
		final Runnable routeRunable = new ExceptionSafeRunnable()  {

			@Override
			protected void runThread() {
				
				boolean operationSuccess = true;

				try {
					final RoutingHeader routingHeader = insertTupleRequest.getRoutingHeader();
					
					assert (routingHeader.isRoutedPackage()) : "Tuple is not a routed package";
					
					if(! routingHeader.reachedFinalInstance()) {
						routingHeader.dispatchToNextHop();				
						operationSuccess = sendInsertPackage(insertTupleRequest);
					}
					
				}  catch(InterruptedException e) {
					logger.error("Exception while routing package", e);
					Thread.currentThread().interrupt();
					operationSuccess = false;
				} catch (PackageEncodeException e) {
					logger.error("Exception while routing package", e);
					operationSuccess = false;
				} 
				
				if(operationSuccess) {
					final SuccessResponse responsePackage = new SuccessResponse(packageSequence);
					clientConnectionHandler.writeResultPackageNE(responsePackage);
				} else {
					final ErrorResponse responsePackage = new ErrorResponse(packageSequence, ErrorMessages.ERROR_ROUTING_FAILED);
					clientConnectionHandler.writeResultPackageNE(responsePackage);
				}
			}
		};
		
		// Submit the runnable to our pool
		if(threadPool.isShutdown()) {
			logger.warn("Thread pool is shutting down, don't route package: {}", packageSequence);
			final ErrorResponse responsePackage = new ErrorResponse(packageSequence, ErrorMessages.ERROR_QUERY_SHUTDOWN);
			clientConnectionHandler.writeResultPackageNE(responsePackage);
		} else {
			threadPool.submit(routeRunable);
		}
	}

	/**
	 * @param insertTupleRequest
	 * @return
	 * @throws InterruptedException
	 * @throws PackageEncodeException 
	 * @throws TimeoutException 
	 * @throws ExecutionException
	 */
	protected boolean sendInsertPackage(final InsertTupleRequest insertTupleRequest) 
			throws InterruptedException, PackageEncodeException {
		
		final RoutingHeader routingHeader = insertTupleRequest.getRoutingHeader();
		final RoutingHop routingHop = routingHeader.getRoutingHop();
		final BBoxDBInstance receiverInstance = routingHop.getDistributedInstance();
				
		final BBoxDBConnection connection = MembershipConnectionService
				.getInstance()
				.getConnectionForInstance(receiverInstance);
		
		if(connection == null) {
			logger.error("Unable to get a connection to system: {}", receiverInstance);
			return false;
		} 
				
		final BBoxDBClient bboxDBClient = connection.getBboxDBClient();
		final EmptyResultFuture insertFuture = bboxDBClient.insertTuple(
				insertTupleRequest.getTable().getFullname(), 
				insertTupleRequest.getTuple(), 
				routingHeader);
		
		try {
			insertFuture.waitForCompletion(ROUTING_TIMEOUT_IN_SEC, TimeUnit.SECONDS);
		} catch (TimeoutException e) {
			logger.warn("Routing timeout, retry routing: {}", connection);
			return false;
		}
		
		final boolean operationSuccess = (! insertFuture.isFailed());
		return operationSuccess;
	}
	
	
	/**
	 * Ensure that the package is routed to the correct system
	 * @param localHop
	 * @return 
	 * @throws BBoxDBException
	 */
	public static boolean checkLocalSystemNameMatches(final RoutingHop localHop) 
			throws BBoxDBException {
		
		final BBoxDBInstance localInstanceName = ZookeeperClientFactory.getLocalInstanceName();
		final BBoxDBInstance routingInstanceName = localHop.getDistributedInstance();
		
		return (localInstanceName.socketAddressEquals(routingInstanceName));
	}

	/**
	 * Ensure that the package is routed to the correct system
	 * @param localHop
	 * @throws BBoxDBException
	 */
	public static void checkLocalSystemNameMatchesAndThrowException(final RoutingHop localHop) 
			throws BBoxDBException {
		
		final BBoxDBInstance localInstanceName = ZookeeperClientFactory.getLocalInstanceName();
		final BBoxDBInstance routingInstanceName = localHop.getDistributedInstance();
		
		if(! checkLocalSystemNameMatches(localHop)) {
			throw new BBoxDBException("Routing hop " + routingInstanceName 
					+ " does not match local host " + localInstanceName);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy