/** * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * This 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.1 of the License, or (at your option) * any later version. * * This software 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 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 software; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF * site: http://www.fsf.org. */ package org.ut.biolab.medsavant.server; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Semaphore; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * * IOjobs submitted through this class respect MAX_IO_JOBS -- there can never * be more than MAX_IO_JOBS threads with a running IOJob. If the limit is * exceeded, the other IOJobs will wait until an IO permit becomes available. * The 'doIO' method of an IOJob is executed a maximum of * DEFAULT_NUM_BLOCKS_PER_PERMIT before the permit is temporarily released to * other scheduled IO jobs. This default can be overridden with an argument to * requestIO. */ public class MedSavantIOController { private static final Log LOG = LogFactory.getLog(MedSavantIOController.class); private static final int TIME_PER_PERMIT = 10000; private static Semaphore IOSem = new Semaphore(MedSavantServerEngine.MAX_IO_JOBS, true); private static final Timer timer = new Timer(); private static final List<Permit> outStandingPermits; // INNER CLASSES private static class PermitRenewerTask extends TimerTask { @Override public synchronized void run() { for (Permit p : outStandingPermits) { p.invalidate(); } } }; private static class Permit { private boolean valid; private String jobName; private Permit(){} public static Permit getPermit(IOJob job) throws InterruptedException{ Permit p = new Permit(); p.jobName = job.getName(); synchronized (outStandingPermits) { outStandingPermits.add(p); } IOSem.acquire(); p.valid = true; //LOG.info("DEBUG: " + Thread.currentThread().getId() + ": " + p.jobName + " STARTED and ACTIVE"); return p; } public void invalidate() { this.valid = false; } public void renew() throws InterruptedException { if (!this.valid) { IOSem.release(); //LOG.info("DEBUG: " + Thread.currentThread().getId() + ": " + jobName + " INACTIVE"); IOSem.acquire(); this.valid = true; //LOG.info("DEBUG: " + Thread.currentThread().getId() + ": " + jobName + " ACTIVE"); } } public void release() { IOSem.release(); synchronized (outStandingPermits) { outStandingPermits.remove(this); } //LOG.info("DEBUG: " + Thread.currentThread().getId() + ": " + jobName + " FINISHED and INACTIVE"); } }; //INITIALIZATION AND METHODS, MedSavantIOController static { timer.schedule(new PermitRenewerTask(), TIME_PER_PERMIT, TIME_PER_PERMIT); outStandingPermits = new ArrayList<Permit>(); } public static void requestIO(IOJob job) throws IOException, InterruptedException { Permit permit = Permit.getPermit(job); try{ while (job.continueIO()) { permit.renew(); job.doIO(); } job.finish(); }finally{ permit.release(); } } }