/* * Workers.java * * Copyright (C) 2015 Pixelgaffer * * This work is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2 of the License, or any later * version. * * This work is distributed in the hope that it will be useful, but without * any warranty; without even the implied warranty of merchantability or * fitness for a particular purpose. See version 2 and version 3 of the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.pixelgaffer.turnierserver.backend; import java.util.HashSet; import java.util.Set; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.NonNull; /** * Diese Klasse speichert alle verfügbaren Worker ab. */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class Workers { private static final Object lock = new Workers(); /** * Diese Methode wartet bis workerIsAvailable oder eine andere Methode diesen Thread notified. */ public static void waitForAvailableWorker () throws InterruptedException { synchronized (lock) { lock.wait(); } } /** * Diese Methode registriert einen neuen Worker. */ public static boolean registerWorker (@NonNull WorkerConnection worker) { BackendMain.getLogger().info("Neuer Worker registriert: " + worker); boolean success; synchronized (workerConnections) { success = workerConnections.add(worker); } if (success) { synchronized (lock) { lock.notifyAll(); } } return success; } /** * Diese Methode deregistriert einen neuen Worker. */ public static boolean removeWorker (WorkerConnection worker) { BackendMain.getLogger().info("Workers: Entferne Worker " + worker); synchronized (workerConnections) { Jobs.workerDisconnected(worker); return workerConnections.remove(worker); } } /** * Gibt einen Worker mit mindestens einer unbeschäftigten Sandbox zurück. * Diese Methode blockiert, bis ein solcher Worker verfügbar ist. */ public static WorkerConnection getStartableWorker (String lang, boolean tournament) { while (true) { BackendMain.getLogger().debug("Searching for a startable worker for the language " + lang); synchronized (workerConnections) { for (WorkerConnection worker : workerConnections) { if (Tournament.getCurrentTournament() != null && worker.isTournament() && !tournament) continue; if (worker.canStartAi(lang)) { BackendMain.getLogger().debug( "Found a startable worker for the language " + lang + ": " + worker); return worker; } } } BackendMain.getLogger().debug("Waiting for a startable worker for the language " + lang); synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { BackendMain.getLogger().warning("Exception beim Warten auf einen verfügbaren Worker: " + e); } } } } /** * Gibt die Anzahl der unbeschäftigten Sandboxen zurück. Die * unterstürtzten Sprachen werden dabei nicht beachtet. */ public static int getStartableSandboxes (boolean tournament) { int count = 0; synchronized (workerConnections) { for (WorkerConnection worker : workerConnections) { if (Tournament.getCurrentTournament() != null && worker.isTournament() && !tournament) continue; count += worker.getStartableSandboxes(); } } return count; } /** * Gibt einen Worker zurück, der gerade keine KI kompiliert. Diese Methode * blockiert, bis ein solcher Worker verfügbar ist. */ public static WorkerConnection getCompilableWorker () { while (true) { synchronized (workerConnections) { for (WorkerConnection worker : workerConnections) if (!worker.isCompiling()) return worker; } synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { BackendMain.getLogger().warning("Exception beim Warten auf einen verfügbaren Worker: " + e); } } } } /** * Muss von jeder WorkerConnection aufgerufen werden, sobald der Worker * (wieder) verfügbar ist. */ public static void workerIsAvailable () { synchronized (lock) { lock.notifyAll(); } } /** * Beendet alle Verbindungen zu den Workern. */ public static void shutdown () { synchronized (workerConnections) { workerConnections.forEach( (con) -> con.disconnect()); workerConnections.clear(); } } private static final Set<WorkerConnection> workerConnections = new HashSet<>(); }