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

prerna.engine.impl.r.RserveConnectionPool Maven / Gradle / Ivy

The newest version!
package prerna.engine.impl.r;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import prerna.util.PortAllocator;

public class RserveConnectionPool implements IRserveConnectionPool {

	// TODO >>>timb: R - since this is running locally, do we need to specify the host at all? Can we just return a port for get connection? (later)
	private static final String HOST = "127.0.0.1";

	private Map pool = new ConcurrentHashMap<>();
	
	
	//////////////////////////////////////////////////////////////////////
	// Singleton implementation of IRserveConnectionPool
	//////////////////////////////////////////////////////////////////////
    private static class LazyHolder {
        private static final RserveConnectionPool INSTANCE = new RserveConnectionPool();
    }
	
	public static RserveConnectionPool getInstance() {
		return LazyHolder.INSTANCE;
	}
	
	private RserveConnectionPool() {
		
	}
	
	
	//////////////////////////////////////////////////////////////////////
	// IRserveConnectionPool implementation
	//////////////////////////////////////////////////////////////////////
	@Override
	public RserveConnectionMeta getConnection() {
		
		// Start a new Rserve if the pool is still less than the max size
		if (pool.size() < RserveUtil.RSERVE_CONNECTION_POOL_SIZE) {
			int port = PortAllocator.getInstance().getNextAvailablePort();
			try {
				Process p = RserveUtil.startR(port);
				RserveConnectionMeta connection = new RserveConnectionMeta(HOST, port);
				connection.setProcess(p);
				pool.put(connection, 1);
				return connection;
			} catch (Exception e) {
				throw new IllegalArgumentException("Failed to get connection.", e);
			}
		} else {
			// Otherwise, grab the least connection and increment by one
			Map leastConnection = pool.entrySet().stream()
					.sorted(Map.Entry.comparingByValue())
					.limit(1)
					.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
			RserveConnectionMeta connection = leastConnection.keySet().iterator().next();
			pool.compute(connection, (k, v) -> v + 1);
			return connection;
		}
	}

	@Override
	public void releaseConnection(RserveConnectionMeta connection) {
		try {
			
			// If there is only one connection on the process, then also stop this Rserve instance
			if (pool.remove(connection, 1)) {
				try {
					RserveUtil.stopR(connection.getPort());
				} catch (Exception e) {
					throw new IllegalArgumentException("Failed to release connection.", e);
				}
			} else {
				
				// Otherwise decrement the connection by one
				pool.compute(connection, (k, v) -> v - 1);
			}
		} finally {
			connection.setRcon(null);
		}
	}

	@Override
	public void recoverConnection(RserveConnectionMeta connection) throws Exception {
		try { 
			RserveUtil.stopR(connection.getPort());
			Process p = RserveUtil.startR(connection.getPort());
			connection.setProcess(p);
		} finally {
			connection.setRcon(null);
		}
	}

	@Override
	public void shutdown() throws Exception {
		for (RserveConnectionMeta connection : pool.keySet()) {
			try {
				RserveUtil.stopR(connection.getPort());
			} catch (Exception ignore) {
				// Ignore
			} finally {
				pool.remove(connection);
			}
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy