Package org.exist.storage.lock

Source Code of org.exist.storage.lock.ReentrantReadWriteLock

/*
* eXist Open Source Native XML Database
* Copyright (C) 2005-2007 The eXist Project
* http://exist-db.org
*
* This program 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
* of the License, or (at your option) any later version.
* This program 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 program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* File: ReentrantLock.java
*
* Originally written by Doug Lea and released into the public domain.
* This may be used for any purposes whatsoever without acknowledgment.
* Thanks for the assistance and support of Sun Microsystems Labs,
* and everyone contributing, testing, and using this code.
*
* $Id$
*
*/
package org.exist.storage.lock;

import java.io.PrintStream;
import java.util.Stack;

import org.apache.log4j.Logger;
import org.exist.util.LockException;

/**
* A lock with the same semantics as builtin
* Java synchronized locks: Once a thread has a lock, it
* can re-obtain it any number of times without blocking.
* The lock is made available to other threads when
* as many releases as acquires have occurred.
*
* The lock has a timeout: a read lock will be released if the
* timeout is reached.
*/

public class ReentrantReadWriteLock implements Lock {

    private static final int WAIT_CHECK_PERIOD = 200;

    private class SuspendedWaiter {
        Thread thread;
        int lockMode;
        int lockCount;

        public SuspendedWaiter(Thread thread, int lockMode, int lockCount) {
            this.thread = thread;
            this.lockMode = lockMode;
            this.lockCount = lockCount;
        }
    }

    private final static Logger LOG = Logger.getLogger(ReentrantReadWriteLock.class);

    protected Object id_ = null;
  protected Thread owner_ = null;
    protected Stack<SuspendedWaiter> suspendedThreads = new Stack<SuspendedWaiter>();

    protected int holds_ = 0;
    public int mode_ = Lock.NO_LOCK;
    private Stack<Integer> modeStack = new Stack<Integer>();
    private int writeLocks = 0;
    private boolean DEBUG = false;
    private Stack<StackTraceElement[]> seStack;
    private LockListener listener = null;

    public ReentrantReadWriteLock(Object id) {
        id_ = id;
        if (DEBUG)
            {seStack = new Stack<StackTraceElement[]>();}
    }

    public String getId() {
        return id_.toString();
    }

    /* @deprecated Use other method
      * @see org.exist.storage.lock.Lock#acquire()
      */
    public boolean acquire() throws LockException {
        return acquire(Lock.READ_LOCK);
    }

    public boolean acquire(int mode) throws LockException {
        if (mode == Lock.NO_LOCK) {
            LOG.warn("acquired with no lock !");
            return true;
        }
        if (Thread.interrupted())
            {throw new LockException();}
        Thread caller = Thread.currentThread();
        synchronized (this) {
            WaitingThread waitingOnResource;
            if (caller == owner_) {
                ++holds_;
                modeStack.push(Integer.valueOf(mode));
                if (mode == Lock.WRITE_LOCK)
                    {writeLocks++;}
                if (DEBUG) {
                    final Throwable t = new Throwable();
                    seStack.push(t.getStackTrace());
                }
                mode_ = mode;
                return true;
            } else if (owner_ == null) {
                owner_ = caller;
                holds_ = 1;
                modeStack.push(Integer.valueOf(mode));
                if (mode== Lock.WRITE_LOCK)
                    {writeLocks++;}
                if (DEBUG) {
                    final Throwable t = new Throwable();
                    seStack.push(t.getStackTrace());
                }
                mode_ = mode;
                return true;
            } else if ((waitingOnResource =
                    DeadlockDetection.deadlockCheckResource(caller, owner_)) != null) {
                waitingOnResource.suspendWaiting();
                final SuspendedWaiter suspended = new SuspendedWaiter(owner_, mode_, holds_);
                suspendedThreads.push(suspended);
                owner_ = caller;
                holds_ = 1;
                modeStack.push(Integer.valueOf(mode));
                if (mode== Lock.WRITE_LOCK)
                    {writeLocks++;}
                mode_ = mode;
                listener = waitingOnResource;
                return true;
            } else {
                DeadlockDetection.addCollectionWaiter(caller, this);
                try {
                    for (;;) {
                        wait(WAIT_CHECK_PERIOD);
                        if ((waitingOnResource = DeadlockDetection.deadlockCheckResource(caller, owner_)) != null) {
                            waitingOnResource.suspendWaiting();
                            final SuspendedWaiter suspended = new SuspendedWaiter(owner_, mode_, holds_);
                            suspendedThreads.push(suspended);
                            owner_ = caller;
                            holds_ = 1;
                            modeStack.push(Integer.valueOf(mode));
                            if (mode== Lock.WRITE_LOCK)
                                {writeLocks++;}
                            mode_ = mode;
                            listener = waitingOnResource;
                            DeadlockDetection.clearCollectionWaiter(owner_);
                            return true;
                        } else if (caller == owner_) {
                            ++holds_;
                            modeStack.push(Integer.valueOf(mode));
                            if (mode == Lock.WRITE_LOCK)
                                {writeLocks++;}
                            if (DEBUG) {
                                final Throwable t = new Throwable();
                                seStack.push(t.getStackTrace());
                            }
                            mode_ = mode;
                            DeadlockDetection.clearCollectionWaiter(owner_);
                            return true;
                        } else if (owner_ == null) {
                            owner_ = caller;
                            holds_ = 1;
                            modeStack.push(Integer.valueOf(mode));
                            if (mode == Lock.WRITE_LOCK)
                                {writeLocks++;}
                            if (DEBUG) {
                                final Throwable t = new Throwable();
                                seStack.push(t.getStackTrace());
                            }
                            mode_ = mode;
                            DeadlockDetection.clearCollectionWaiter(owner_);
                            return true;
                        }
                    }
                } catch (final InterruptedException ex) {
                    notify();
                    throw new LockException("Interrupted while waiting for lock");
                }
            }
        }
    }

    public synchronized void wakeUp() {
        notify();
    }

    public boolean attempt(int mode) {
        Thread caller = Thread.currentThread();
        synchronized (this) {
            if (caller == owner_) {
                ++holds_;
                modeStack.push(Integer.valueOf(mode));
                if (mode == Lock.WRITE_LOCK)
                    {writeLocks++;}
                if (DEBUG) {
                    final Throwable t = new Throwable();
                    seStack.push(t.getStackTrace());
                }
                mode_ = mode;
                return true;
            } else if (owner_ == null) {
                owner_ = caller;
                holds_ = 1;
                modeStack.push(Integer.valueOf(mode));
                if (mode == Lock.WRITE_LOCK)
                    {writeLocks++;}
                if (DEBUG) {
                    final Throwable t = new Throwable();
                    seStack.push(t.getStackTrace());
                }
                mode_ = mode;
                return true;
            } else {
                return false;
            }
        }
    }

    /* (non-Javadoc)
     * @see org.exist.util.Lock#isLockedForWrite()
     */
    public synchronized boolean isLockedForWrite() {
        return writeLocks > 0;
    }

    public boolean isLockedForRead(Thread owner) {
        // always returns false for this lock
        return false;
    }

    public synchronized boolean hasLock() {
        return holds_ > 0;
    }

    public boolean hasLock(Thread owner) {
        return this.owner_ == owner;
    }

    public Thread getOwner() {
        return this.owner_;
    }

    /* (non-Javadoc)
     * @see org.exist.util.Lock#release(int)
     */
    public synchronized void release(int mode) {
        if (Thread.currentThread() != owner_) {
           
            if(LOG.isDebugEnabled()){
                LOG.warn("Possible lock problem: thread " + Thread.currentThread() +
                    " Released a lock on " + getId() + " it didn't hold." +
                    " Either the thread was interrupted or it never acquired the lock." +
                    " The lock was owned by: " + owner_);
            }
                  
            if (DEBUG) {
                LOG.debug("Lock was acquired by :");
                while (!seStack.isEmpty()) {
                    StackTraceElement[] se = seStack.pop();
                    LOG.debug(se);
                    se = null;
                }
            }
            return;
        }
        Integer top = modeStack.pop();
        mode_ = top.intValue();
        top = null;  
        if (mode_ != mode) {
            LOG.warn("Released lock of different type. Expected " + mode_ +
                " got " + mode, new Throwable());
        }       
        if (mode_ == Lock.WRITE_LOCK) {
            writeLocks--;
        }
        if (DEBUG) {
            seStack.pop();
        }
        if (--holds_ == 0) {
            if (!suspendedThreads.isEmpty()) {
                final SuspendedWaiter suspended = suspendedThreads.pop();
                owner_ = suspended.thread;
                mode_ = suspended.lockMode;
                holds_ = suspended.lockCount;
            } else {
                owner_ = null;
                mode_ = Lock.NO_LOCK;
                notify();
            }
        }
        if (listener != null) {
            listener.lockReleased();
            listener = null;
        }
    }

    public void release(int mode, int count) {
        throw new UnsupportedOperationException(getClass().getName() +
                " does not support releasing multiple locks");
    }

    /**
     * Return the number of unreleased acquires performed
     * by the current thread.
     * Returns zero if current thread does not hold lock.
     **/
    public synchronized long holds() {
        if (Thread.currentThread() != owner_)
            {return 0;}
        return holds_;
    }

    public synchronized LockInfo getLockInfo() {
        final String lockType = mode_ == Lock.WRITE_LOCK ? LockInfo.WRITE_LOCK : LockInfo.READ_LOCK;
        return new LockInfo(LockInfo.COLLECTION_LOCK, lockType, getId(),
            new String[] { (owner_==null)?"":owner_.getName() });
    }

    @Override
    public void debug(PrintStream out) {
        getLockInfo().debug(out);
    }
}
TOP

Related Classes of org.exist.storage.lock.ReentrantReadWriteLock

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.