Package freenet.support

Source Code of freenet.support.MemoryLimitedJobRunner

package freenet.support;

import java.util.ArrayDeque;
import java.util.Deque;

import freenet.node.PrioRunnable;

/** Start jobs as long as there is sufficient memory (or other limited resource) available, then
* queue them. FIXME I bet there is something like this in the standard libraries?
* @author toad
*/
public class MemoryLimitedJobRunner {
   
    public long capacity;
    /** The amount of some limited resource that is in use */
    private long counter;
    /** The jobs we can't start yet. FIXME Always FIFO order? Small jobs first? Prioritised even? */
    private final Deque<MemoryLimitedJob> jobs;
    private final Executor executor;
    private int runningThreads;
    private int maxThreads;
    private boolean shutdown;
   
    public MemoryLimitedJobRunner(long capacity, int maxThreads, Executor executor) {
        this.capacity = capacity;
        this.counter = 0;
        this.jobs = new ArrayDeque<MemoryLimitedJob>();
        this.executor = executor;
        this.maxThreads = maxThreads;
       
    }
   
    /** Run the job if the counter is below some threshold, otherwise queue it. Will ignore if
     * shutting down. */
    public synchronized void queueJob(final MemoryLimitedJob job) {
        if(shutdown) return;
        if(job.initialAllocation > capacity) throw new IllegalArgumentException("Job size "+job.initialAllocation+" > capacity "+capacity);
        if(counter + job.initialAllocation <= capacity && runningThreads < maxThreads) {
            startJob(job);
        } else {
            jobs.add(job);
        }
    }

    synchronized void deallocate(long size, boolean finishedThread) {
        if(size == 0) return; // Can't do anything, legal no-op.
        if(size < 0) throw new IllegalArgumentException();
        assert(size <= counter);
        counter -= size;
        if(finishedThread) {
            runningThreads--;
            if(shutdown) notifyAll();
        }
        maybeStartJobs();
    }
   
    private synchronized void maybeStartJobs() {
        if(shutdown) return;
        while(true) {
            MemoryLimitedJob job = jobs.peekFirst();
            if(job == null) return;
            if(job.initialAllocation + counter <= capacity && runningThreads < maxThreads) {
                jobs.removeFirst();
                startJob(job);
            } else return;
        }
    }
   
    private synchronized void startJob(final MemoryLimitedJob job) {
        counter += job.initialAllocation;
        runningThreads++;
        executor.execute(new PrioRunnable() {

            @Override
            public void run() {
                MemoryLimitedChunk chunk = new MemoryLimitedChunk(MemoryLimitedJobRunner.this, job.initialAllocation);
                if(job.start(chunk))
                    chunk.release();
            }
           
            @Override
            public int getPriority() {
                return job.getPriority();
            }
           
        });
    }

    /** For tests and stats. How much of the scarce resource is used right now? */
    long used() {
        return counter;
    }

    public synchronized void setMaxThreads(int val) {
        this.maxThreads = val;
        maybeStartJobs();
    }

    public synchronized int getMaxThreads() {
        return maxThreads;
    }

    public synchronized long getCapacity() {
        return capacity;
    }

    public synchronized void setCapacity(long val) {
        capacity = val;
        maybeStartJobs();
    }
   
    public synchronized void shutdown() {
        shutdown = true;
    }
   
    public synchronized void waitForShutdown() {
        shutdown = true;
        while(runningThreads > 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                // Ignore.
            }
        }
    }

    public synchronized int getRunningThreads() {
        return runningThreads;
    }

}
TOP

Related Classes of freenet.support.MemoryLimitedJobRunner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.