net.gleamynode.oil.impl.wal.QueueIteratorImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.gleamynode.oil.impl.wal.QueueIteratorImpl.java

Source

/*
 *   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
/*
 * @(#) $Id: QueueIteratorImpl.java 38 2004-11-14 15:20:22Z trustin $
 */
package net.gleamynode.oil.impl.wal;

import org.apache.commons.lang.Validate;

import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
import EDU.oswego.cs.dl.util.concurrent.Sync;

import net.gleamynode.oil.Queue;
import net.gleamynode.oil.QueueIterator;
import net.gleamynode.oil.QueueReference;

/**
 * @author Trustin Lee (trustin@gmail.com)
 * @version $Rev: 38 $, $Date: 2004-11-15 00:20:22 +0900 (, 15 11 2004) $
 */
class QueueIteratorImpl implements QueueIterator {
    private final WalDatabase grandparent;
    private final QueueImpl parent;
    private final ReadWriteLock lock = new ReentrantWriterPreferenceReadWriteLock();
    private final QueueExtentList extentList;
    private QueueExtent extent;
    private int nextExtentIdx;
    private int offset;

    QueueIteratorImpl(QueueImpl parent, QueueExtentList extentList) {
        this.parent = parent;
        this.grandparent = parent.getParent();
        this.extentList = extentList;
    }

    /**
     * Iterator            .
     *
     * @return  key - value   
     * @throws net.gleamynode.oil.OilException
     *                 
     */
    public boolean next() {
        boolean result;
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().readLock());
        SyncUtil.acquire(lock.writeLock());

        try {
            QueueExtent e = extent;
            outerLoop: for (;;) {
                if (e == null) {
                    boolean found = false;

                    while ((e = extentList.getByIndex(nextExtentIdx)) != null) {
                        nextExtentIdx++;

                        if (e.size() > 0) {
                            offset = 0;
                            found = true;
                            break;
                        }
                    }

                    if (!found) {
                        this.extent = null;
                        result = false;

                        break outerLoop;
                    }
                } else {
                    offset++;
                }

                for (int i = offset; i < e.getEndOffset(); i++) {
                    if (e.get(i) != null) {
                        offset = i;
                        this.extent = e;
                        result = true;

                        break outerLoop;
                    }
                }

                e = null;
            }
        } finally {
            lock.writeLock().release();
            parent.getLock().readLock().release();
            grandparent.releaseSharedLock();
        }

        return result;
    }

    private void tryToRemoveCurrentExtent() {
        // purge it if it is not the last one
        if (extent.tryToDiscard()) {
            extent = null;
        }
    }

    public Object getValue() {
        Object result;
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().readLock());
        SyncUtil.acquire(lock.readLock());

        try {
            result = getCurrentExtent().get(offset);
        } finally {
            lock.readLock().release();
            parent.getLock().readLock().release();
            grandparent.releaseSharedLock();
        }

        return result;
    }

    public QueueReference getReference() {
        QueueReference result;
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().readLock());
        SyncUtil.acquire(lock.readLock());

        try {
            QueueExtent e = getCurrentExtent();

            if (e.get(offset) == null) {
                result = null;
            } else {
                result = new QueueReferenceImpl(e.getId(), e.getChecksum(), offset);
            }
        } finally {
            lock.readLock().release();
            parent.getLock().readLock().release();
            grandparent.releaseSharedLock();
        }

        return result;
    }

    public Object setValue(Object item) {
        Validate.notNull(item);

        Object result;
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().writeLock());
        SyncUtil.acquire(lock.writeLock());

        try {
            result = getCurrentExtent().set(offset, item, true);
        } finally {
            lock.writeLock().release();
            parent.getLock().writeLock().release();
            grandparent.releaseSharedLock();
        }

        return result;
    }

    public void update() {
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().writeLock());
        SyncUtil.acquire(lock.writeLock());

        try {
            QueueExtent e = getCurrentExtent();
            Object value = e.get(offset);

            if (value == null) {
                throw new IllegalStateException();
            } else {
                e.set(offset, value, true);
            }
        } finally {
            lock.writeLock().release();
            parent.getLock().writeLock().release();
            grandparent.releaseSharedLock();
        }
    }

    public QueueReference moveTo(Queue queue) {
        Validate.notNull(queue);

        if (!(queue instanceof QueueImpl)) {
            throw new IllegalArgumentException();
        }

        if (this == queue) {
            throw new IllegalArgumentException();
        }

        QueueReference result;
        QueueImpl q = (QueueImpl) queue;

        if (grandparent != q.getParent()) {
            throw new IllegalArgumentException();
        }

        Sync lockA = parent.getLock().writeLock();
        Sync lockB = q.getLock().writeLock();

        // sort locks to avoid deadlocks.
        if (System.identityHashCode(lockA) > System.identityHashCode(lockB)) {
            Sync tmp = lockA;
            lockA = lockB;
            lockB = tmp;
        }

        grandparent.acquireSharedLock();
        SyncUtil.acquire(lockA);
        SyncUtil.acquire(lockB);
        SyncUtil.acquire(lock.writeLock());

        try {
            QueueExtent extent = getCurrentExtent();
            result = extent.moveTo(offset, q);

            if (result != null) {
                tryToRemoveCurrentExtent();
            }
        } finally {
            lock.writeLock().release();
            lockB.release();
            lockA.release();
            grandparent.releaseSharedLock();
        }

        return result;
    }

    public boolean isRemoved() {
        boolean result;
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().readLock());
        SyncUtil.acquire(lock.readLock());

        QueueExtent e = extent;
        result = (e == null) || (e.get(offset) == null);
        lock.readLock().release();
        parent.getLock().readLock().release();
        grandparent.releaseSharedLock();

        return result;
    }

    public Object remove() {
        Object result;
        grandparent.acquireSharedLock();
        SyncUtil.acquire(parent.getLock().writeLock());
        SyncUtil.acquire(lock.writeLock());

        try {
            QueueExtent e = getCurrentExtent();
            result = e.remove(offset);

            if (result != null) {
                tryToRemoveCurrentExtent();
            }
        } finally {
            lock.writeLock().release();
            parent.getLock().writeLock().release();
            grandparent.releaseSharedLock();
        }

        return result;
    }

    private QueueExtent getCurrentExtent() {
        QueueExtent e = extent;

        if (e == null) {
            throw new IllegalStateException();
        }

        return e;
    }
}