/* * Eoulsan development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public License version 2.1 or * later and CeCILL-C. This should be distributed with the code. * If you do not have a copy, see: * * http://www.gnu.org/licenses/lgpl-2.1.txt * http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt * * Copyright for this code is held jointly by the Genomic platform * of the Institut de Biologie de l'École normale supérieure and * the individual authors. These should be listed in @author doc * comments. * * For more information on the Eoulsan project and its aims, * or to join the Eoulsan Google group, visit the home page * at: * * http://outils.genomique.biologie.ens.fr/eoulsan * */ package fr.ens.biologie.genomique.eoulsan.util.locker; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import fr.ens.biologie.genomique.eoulsan.util.Utils; /** * This class define a server for the scheduler. * @since 1.1 * @author Laurent Jourdren */ public class TicketSchedulerServer implements TicketScheduler { private static TicketSchedulerServer serverInstance; private Ticket currentActive; private final Map<Ticket, Ticket> tickets = new HashMap<>(); private final Set<Ticket> toRemove = new HashSet<>(); private final int maxWorkingTime = 2 * 60 * 1000; private final int deadTime = 30 * 1000; private final int checkingTime = 10 * 1000; private long lastCheckingTime = 0; @Override public Set<Ticket> getTickets(final Ticket ticket) { if (ticket == null) { return new HashSet<>(this.tickets.values()); } synchronized (this.tickets) { if (this.tickets.containsKey(ticket)) { final Ticket t = this.tickets.get(ticket); t.updateLastActiveTime(); } else { ticket.updateLastActiveTime(); this.tickets.put(ticket, ticket); } check(); return new HashSet<>(this.tickets.values()); } } @Override public void endWork(final Ticket ticket) { if (ticket == null) { return; } synchronized (this.tickets) { if (ticket.equals(this.currentActive)) { this.tickets.remove(this.currentActive); this.currentActive = null; check(); } } } private void check() { final long currentTime = System.currentTimeMillis(); if (currentTime > this.lastCheckingTime + this.checkingTime) { // Check for waiting dead ticket for (Ticket t : this.tickets.values()) { if (!t.isWorking() && currentTime > t.getLastActiveTime() + this.deadTime) { this.toRemove.add(t); } } // Check for active ticket dead if (this.currentActive != null && currentTime > this.currentActive.getLastActiveTime() + this.maxWorkingTime) { this.toRemove.add(this.currentActive); this.currentActive = null; } // Check JVM PIDs final Set<Integer> pids = LockerUtils.getJVMsPIDs(); for (Ticket t : this.tickets.values()) { if (!pids.contains(t.getPid())) { if (t.equals(this.currentActive)) { this.currentActive = null; } this.toRemove.add(t); } } // Remove dead for (Ticket t : this.toRemove) { this.tickets.remove(t); } this.toRemove.clear(); this.lastCheckingTime = currentTime; } if (this.currentActive == null && this.tickets.size() > 0) { for (Ticket t : this.tickets.values()) { if (t.isWorking()) { this.currentActive = t; return; } } List<Ticket> list = new ArrayList<>(this.tickets.values()); Collections.sort(list); this.currentActive = list.get(0); this.currentActive.setWorking(true); } } // // Constructor // private TicketSchedulerServer(final Set<Ticket> tickets) { if (tickets != null) { for (Ticket t : tickets) { this.tickets.put(t, t); } check(); } } // // Server methods // public static final synchronized void newServer(final Set<Ticket> tickets, final String lockerName, final int port) { // If the server already exists do nothing if (serverInstance != null) { return; } try { // Using a static variable prevent the server object to be eligible to the // Garbage Collector serverInstance = new TicketSchedulerServer(tickets); final TicketScheduler stub = (TicketScheduler) UnicastRemoteObject.exportObject(serverInstance, 0); // Bind the remote object's stub in the registry Registry registry = LocateRegistry.getRegistry(port); if (registry == null) { registry = LocateRegistry.createRegistry(port); } registry.bind(TicketLocker.RMI_SERVICE_PREFIX + lockerName, stub); } catch (Exception e) { Utils.nop(); } } }