package ibis.ipl.registry.central.server; import ibis.ipl.registry.central.Member; import ibis.util.ThreadPool; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Sends events to clients from the server. */ final class IterativeEventPusher implements Runnable { private static final int THREADS = 25; private class WorkQ { private List<Member> q; private int count; WorkQ(Member[] work) { // Arrays.asList list does not support remove, so do this "trick" q = new LinkedList<Member>(); q.addAll(Arrays.asList(work)); count = this.q.size(); } synchronized Member next() { if (q.isEmpty()) { return null; } return q.remove(0); } synchronized void doneJob() { count--; if (count <= 0) { notifyAll(); } } synchronized void waitUntilDone() { while (count > 0) { try { wait(); } catch (InterruptedException e) { // IGNORE } } } } private class EventPusherThread implements Runnable { WorkQ workQ; EventPusherThread(WorkQ workQ) { this.workQ = workQ; ThreadPool.createNew(this, "event pusher thread"); } public void run() { while (true) { Member work = workQ.next(); if (work == null) { // done pushing return; } logger.debug("pushing to " + work); pool.push(work, false, useTree); workQ.doneJob(); logger.debug("done pushing to " + work); } } } private static final Logger logger = LoggerFactory.getLogger(IterativeEventPusher.class); private final Pool pool; private final long timeout; private final boolean eventTriggersPush; private final boolean useTree; IterativeEventPusher(Pool pool, long timeout, boolean eventTriggersPush, boolean useTree) { this.pool = pool; this.timeout = timeout; this.eventTriggersPush = eventTriggersPush; this.useTree = useTree; ThreadPool.createNew(this, "event pusher scheduler thread"); } public void run() { while (!pool.hasEnded()) { int eventTime = pool.getEventTime(); Member[] children; if (useTree) { children = pool.getChildren(); if (logger.isInfoEnabled()) { String message = "broadcasting to " + children.length + " children:"; for (Member member : children) { message += "\n" + member; } logger.info(message); } } else { children = pool.getMembers(); } logger.info("updating " + children.length + " nodes in pool (pool size = " + pool.getSize() + ") to event-time " + eventTime + " using tree: " + useTree); WorkQ workQ = new WorkQ(children); int threads = Math.min(THREADS, children.length); for (int i = 0; i < threads; i++) { new EventPusherThread(workQ); } workQ.waitUntilDone(); logger.info("DONE updating nodes in pool to event-time " + eventTime); pool.purgeHistory(); // try { // Thread.sleep(100); // } catch (InterruptedException e) { // //IGNORE // } if (eventTriggersPush) { pool.waitForEventTime(eventTime + 1, timeout); } else { // wait for the timeout, or until the pool ends pool.waitForEventTime(Integer.MAX_VALUE, timeout); } } } }