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

Source Code of cn.edu.zju.acm.onlinejudge.judgeservice.JudgingQueue

/*
* 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.util.concurrent.atomic.AtomicReference;

import cn.edu.zju.acm.onlinejudge.bean.Submission;

/**
* This class is a queue of all submissions being judged.
*
* All submissions are put in a single linked list. Removal operations only move the head reference forward without
* changing the internal linked list structure. Once a JudgingQueueIterator instance is created, it copies the current
* head reference. In this way, a JudgingQueueIterator instance can always traverse all nodes created subsequent to its
* construction.
*
* We expect this queue to be short. A submission is pushed into this queue when its judge starts and removed when judge
* ends. This is usually less than 1 minute. And we do not expect many judge threads using this queue.
*
* Nodes can be garbage collected when it is not reachable from the head and by any JudgingQueueIterator. So as long as
* we expect that the life of a JudgingQueueIterator stays short, like in seconds, this queue does not cost too much
* memory.
*
* This implementation is thread safe and lock-free just like ConcurrentLinkedQueue.
*
* The same submission may be push into this queue multiple times. When this happens, the linked list will contains
* multiple nodes with the same submission reference. It is safe excepting using a bit more memory. Usually this is not
* a problem.
*
*
* @author Xu, Chuan
* @version 1.0
*/
class JudgingQueue {

    /**
     * The head of this queue.
     */
    private JudgingQueue.JudgingQueueNode head = new JudgingQueue.JudgingQueueNode();

    /**
     * The tail of this queue. Always points to an empty node.
     */
    private AtomicReference<JudgingQueue.JudgingQueueNode> tail =
            new AtomicReference<JudgingQueue.JudgingQueueNode>(this.head);

    /**
     * Adds a new submission.
     *
     * @param submission
     *            the submission to add
     */
    public void push(Submission submission) {
        if (submission == null) {
            throw new NullPointerException("submission should not be null");
        }
        JudgingQueue.JudgingQueueNode node = new JudgingQueueNode();
        JudgingQueue.JudgingQueueNode last = this.tail.getAndSet(node);
        last.next = node;
        last.submission = submission;
    }

    /**
     * Remove the submission from this queue. It is done by marking the corresponding node and removed and move forward
     * the head if necessary.
     *
     * NOTE: It is done by a scan of this queue. This queue is expected to be short so that this operation can be
     * finished very quickly. We do have ways to implement this in constant time like using a hashmap or just add a
     * field in Submission class and update the to mark it as removed. The former solution is a waste when the queue
     * keeps short which is expected. The latter one hurts readability a lot. Some alternative designs similar to the
     * latter solution exists, but they all have defects. Let me know if anyone has a good idea about the design.
     */
    public void remove(Submission submission) {
        // Find the submission and mark it as removed.
        JudgingQueue.JudgingQueueNode node = this.head;
        while (node.submission != null) {
            if (node.submission == submission) {
                node.removed = true;
                break;
            }
            node = node.next;
        }

        // Find the last not-removed node.
        node = this.head;
        while (node.submission != null && node.removed) {
            node = node.next;
        }

        // Not a problem when multiple threads trying to modify this value. The head will finally be moved forward.
        this.head = node;
    }

    public JudgingQueueIterator iterator() {
        return new JudgingQueueIteratorImpl(this.head);
    }

    private static class JudgingQueueNode {
        Submission submission = null;
        JudgingQueue.JudgingQueueNode next = null;
        boolean removed = false;
    }

    private static class JudgingQueueIteratorImpl implements JudgingQueueIterator {
        JudgingQueue.JudgingQueueNode head;

        public JudgingQueueIteratorImpl(JudgingQueue.JudgingQueueNode head) {
            this.head = head;
        }

        /**
         * See JudgingQueueIterator.next
         */
        public Submission next() {
            Submission ret = this.head.submission;
            if (ret != null) {
                this.head = this.head.next;
            }
            return ret;
        }
    }
}
TOP

Related Classes of cn.edu.zju.acm.onlinejudge.judgeservice.JudgingQueue

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.
), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');