Package cn.edu.zju.acm.onlinejudge.judgeservice

Source Code of cn.edu.zju.acm.onlinejudge.judgeservice.SubmissionQueue$Candidate

/*
* Copyright 2007 Xu, Chuan <xuchuan@gmail.com>
*
* This file is part of ZOJ.
*
* ZOJ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either revision 3 of the License, or (at your option) any later revision.
*
* ZOJ 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with ZOJ. if not, see
* <http://www.gnu.org/licenses/>.
*/

/**
*
*/

package cn.edu.zju.acm.onlinejudge.judgeservice;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import cn.edu.zju.acm.onlinejudge.bean.Submission;
import cn.edu.zju.acm.onlinejudge.judgeservice.submissionfilter.SubmissionFilter;
import cn.edu.zju.acm.onlinejudge.persistence.PersistenceException;

class SubmissionQueue {
    private Candidate head = new Candidate();
    private Candidate tail = this.head;
    private Map<SubmissionFilter, WeakReference<SubmissionQueueReaderImpl>> readerMap =
            new HashMap<SubmissionFilter, WeakReference<SubmissionQueueReaderImpl>>();
    private ReferenceQueue<SubmissionQueueReaderImpl> readerReferenceQueue =
            new ReferenceQueue<SubmissionQueueReaderImpl>();

    public synchronized void push(Submission submission, int priority) {
        Candidate candidate = new Candidate();
        candidate.prev = this.tail;
        this.tail.submission = submission;
        this.tail.priority = priority;
        this.tail.next = candidate;
        this.tail = candidate;
        this.notifyAll();
    }

    public SubmissionQueueReader getReader(SubmissionFilter submissionFilter) {
        synchronized (this.readerMap) {
            this.clearReferences();
            WeakReference<SubmissionQueueReaderImpl> readerReference = this.readerMap.get(submissionFilter);
            SubmissionQueueReaderImpl reader = null;
            if (readerReference != null) {
                reader = readerReference.get();
            }
            if (reader == null) {
                reader = this.new SubmissionQueueReaderImpl(submissionFilter);
                readerReference =
                        new SubmissionQueue.ReaderReference(reader, this.readerReferenceQueue, submissionFilter);
                this.readerMap.put(submissionFilter, readerReference);
            }
            return reader;
        }
    }

    private void clearReferences() {
        for (;;) {
            ReaderReference readerReference = (ReaderReference) this.readerReferenceQueue.poll();
            if (readerReference == null) {
                break;
            }
            this.readerMap.remove(readerReference.submissionFilter);
        }
    }

    private static class ReaderReference extends WeakReference<SubmissionQueueReaderImpl> {
        SubmissionFilter submissionFilter;

        public ReaderReference(SubmissionQueueReaderImpl referent,
                               ReferenceQueue<? super SubmissionQueueReaderImpl> queue,
                               SubmissionFilter submissionFilter) {
            super(referent, queue);
            this.submissionFilter = submissionFilter;
        }
    }

    private class Candidate {
        Candidate prev = null;
        Candidate next = null;
        Submission submission = null;
        int priority;

        public Submission tryClaim() {
            if (this.submission == null) {
                return null;
            }
            Submission ret = this.submission;
            synchronized (this) {
                if (this.submission == null) {
                    return null;
                }
                this.submission = null;
            }
            synchronized (SubmissionQueue.this) {
                if (this.prev != null) {
                    this.prev.next = this.next;
                }
                this.next.prev = this.prev;
                if (SubmissionQueue.this.head == this) {
                    SubmissionQueue.this.head = this.next;
                }
                // IMPORTANT: Set prev to null to make garbage collection possible. Don't set next to null so that any
                // candidate reference can travel to the main queue by following this link. This is important to support
                // multi-threaded queue readers.
                this.prev = null;
            }
            return ret;
        }
    }

    private class SubmissionQueueReaderImpl implements SubmissionQueueReader {
        private SubmissionFilter submissionFilter;
        int referenceCount = 0;
        private Candidate head = SubmissionQueue.this.head;
        private List<LinkedList<Candidate>> candidatesLists = new ArrayList<LinkedList<Candidate>>();
        private int size = 0;

        private SubmissionQueueReaderImpl(SubmissionFilter submissionFilter) {
            this.submissionFilter = submissionFilter;
            for (int i = Priority.MIN; i <= Priority.MAX; ++i) {
                this.candidatesLists.add(new LinkedList<Candidate>());
            }
        }

        public synchronized Submission poll(JudgeClientJudgeThread judgeThread) throws InterruptedException,
                PersistenceException {
            for (;;) {
                while (this.head.next != null) {
                    this.add(this.head);
                    this.head = this.head.next;
                }
                if (this.size == 0) {
                    synchronized (SubmissionQueue.this) {
                        while (this.head.next != null) {
                            this.add(this.head);
                            this.head = this.head.next;
                        }
                        if (this.size == 0) {
                            SubmissionQueue.this.wait();
                            continue;
                        }
                    }
                }
                for (int i = this.candidatesLists.size() - 1; i >= 0; --i) {
                    LinkedList<Candidate> candidatesList = this.candidatesLists.get(i);
                    while (candidatesList.size() > 0) {
                        Candidate candidate = candidatesList.removeFirst();
                        --this.size;
                        Submission ret = candidate.tryClaim();
                        if (ret != null) {
                            return ret;
                        }
                    }
                }
            }
        }

        private void add(Candidate candidate) throws PersistenceException {
            Submission submission = candidate.submission;
            if (submission == null) {
                return;
            }
            int priority = candidate.priority;
            priority += this.submissionFilter.filter(submission, priority);
            priority -= Priority.MIN;
            if (priority < 0) {
                return;
            }
            if (priority >= this.candidatesLists.size()) {
                priority = this.candidatesLists.size() - 1;
            }
            this.candidatesLists.get(priority).add(candidate);
            ++this.size;
        }
    }
}
TOP

Related Classes of cn.edu.zju.acm.onlinejudge.judgeservice.SubmissionQueue$Candidate

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.