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

nz.co.gregs.dbvolution.internal.database.ClusterDetails Maven / Gradle / Ivy

/*
 * Copyright 2018 gregorygraham.
 *
 * This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. 
 * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ 
 * or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
 * 
 * You are free to:
 *     Share - copy and redistribute the material in any medium or format
 *     Adapt - remix, transform, and build upon the material
 * 
 *     The licensor cannot revoke these freedoms as long as you follow the license terms.               
 *     Under the following terms:
 *                 
 *         Attribution - 
 *             You must give appropriate credit, provide a link to the license, and indicate if changes were made. 
 *             You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
 *         NonCommercial - 
 *             You may not use the material for commercial purposes.
 *         ShareAlike - 
 *             If you remix, transform, or build upon the material, 
 *             you must distribute your contributions under the same license as the original.
 *         No additional restrictions - 
 *             You may not apply legal terms or technological measures that legally restrict others from doing anything the 
 *             license permits.
 * 
 * Check the Creative Commons website for any details, legalese, and updates.
 */
package nz.co.gregs.dbvolution.internal.database;

import nz.co.gregs.dbvolution.exceptions.NoAvailableDatabaseException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import nz.co.gregs.dbvolution.DBRow;
import nz.co.gregs.dbvolution.actions.DBAction;
import nz.co.gregs.dbvolution.databases.DBDatabase;
import nz.co.gregs.dbvolution.databases.DBDatabaseCluster;
import nz.co.gregs.dbvolution.exceptions.UnableToRemoveLastDatabaseFromClusterException;
import nz.co.gregs.dbvolution.reflection.DataModel;

/**
 *
 * @author gregorygraham
 */
public class ClusterDetails {

	private final List allDatabases = Collections.synchronizedList(new ArrayList(0));
	private final List unsynchronizedDatabases = Collections.synchronizedList(new ArrayList(0));
	private final List readyDatabases = Collections.synchronizedList(new ArrayList(0));
	private final List pausedDatabases = Collections.synchronizedList(new ArrayList(0));
	private final List quarantinedDatabases = Collections.synchronizedList(new ArrayList(0));

	private final Set requiredTables = Collections.synchronizedSet(DataModel.getRequiredTables());
	private final Map> queuedActions = Collections.synchronizedMap(new HashMap>(0));

	public ClusterDetails() throws SQLException {
	}

	public synchronized boolean add(DBDatabase database) {
		unsynchronizedDatabases.add(database);
		return allDatabases.add(database);
	}

	public DBDatabase[] getAllDatabases() {
		synchronized (allDatabases) {
			return allDatabases.toArray(new DBDatabase[]{});
		}
	}

	public synchronized DBDatabaseCluster.Status getStatusOf(DBDatabase db) {
		final boolean ready = readyDatabases.contains(db);
		final boolean paused = pausedDatabases.contains(db);
		final boolean quarantined = quarantinedDatabases.contains(db);
		final boolean unsynched = unsynchronizedDatabases.contains(db);
		if (ready) {
			return DBDatabaseCluster.Status.READY;
		}
		if (paused) {
			return DBDatabaseCluster.Status.PAUSED;
		}
		if (quarantined) {
			return DBDatabaseCluster.Status.QUARANTINED;
		}
		if (unsynched) {
			return DBDatabaseCluster.Status.UNSYNCHRONISED;
		}
		return DBDatabaseCluster.Status.UNKNOWN;
	}

	public synchronized boolean quarantineDatabase(DBDatabase database) {
		if (readyDatabases.size() < 2 && readyDatabases.contains(database)) {
			// Unable to quarantine the only remaining database
			throw new UnableToRemoveLastDatabaseFromClusterException();
		} else {
			return queuedActions.remove(database) != null
					&& allDatabases.remove(database)
					&& readyDatabases.remove(database)
					&& quarantinedDatabases.add(database);

		}
	}

	public synchronized boolean removeDatabase(DBDatabase database) {
		return queuedActions.remove(database) != null
				&& allDatabases.remove(database)
				&& readyDatabases.remove(database)
				&& quarantinedDatabases.remove(database);
	}

	public synchronized DBDatabase[] getUnsynchronizedDatabases() {
		return unsynchronizedDatabases.toArray(new DBDatabase[]{});
	}

	public synchronized void synchronizingDatabase(DBDatabase db) {
		unsynchronizedDatabases.remove(db);
	}

	public Queue getActionQueue(DBDatabase db) {
		synchronized (queuedActions) {
			Queue queue = queuedActions.get(db);
			if (queue == null) {
				queue = new LinkedBlockingQueue();
				queuedActions.put(db, queue);
			}
			return queue;
		}
	}

	public DBRow[] getRequiredTables() {
		synchronized (requiredTables) {
			return requiredTables.toArray(new DBRow[]{});
		}
	}

	public synchronized void readyDatabase(DBDatabase secondary) {
		unsynchronizedDatabases.remove(secondary);
		pausedDatabases.remove(secondary);
		readyDatabases.add(secondary);
	}

	public synchronized DBDatabase[] getReadyDatabases() {
			return readyDatabases.toArray(new DBDatabase[]{});
	}

	public synchronized void pauseDatabase(DBDatabase template) {
		boolean removed = readyDatabases.remove(template);
		pausedDatabases.add(template);
	}

	public synchronized DBDatabase getPausedDatabase() throws NoAvailableDatabaseException {
		DBDatabase template = getReadyDatabase();
		pauseDatabase(template);
		return template;
	}

	public DBDatabase getReadyDatabase() throws NoAvailableDatabaseException {
		Random rand = new Random();
		DBDatabase[] dbs = getReadyDatabases();
		int tries = 0;
		while (dbs.length < 1 && pausedDatabases.size() > 0 && tries <= 1000) {
			tries++;
			try {
				Thread.sleep(1);
			} catch (InterruptedException ex) {
				Logger.getLogger(ClusterDetails.class.getName()).log(Level.SEVERE, null, ex);
			}
			dbs = getReadyDatabases();
		}
		if (dbs.length > 0) {
			final int randNumber = rand.nextInt(dbs.length);
			DBDatabase randomElement = dbs[randNumber];
			return randomElement;
		}
		throw new NoAvailableDatabaseException();
	}

	public synchronized void addAll(DBDatabase[] databases) {
		for (DBDatabase database : databases) {
			add(database);
		}
	}

	public synchronized DBDatabase getTemplateDatabase() {
		if (readyDatabases.isEmpty() && pausedDatabases.isEmpty()) {
			throw new NoAvailableDatabaseException();
		}
		return getPausedDatabase();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy