001package com.hammurapi.store;
002
003import java.util.concurrent.TimeUnit;
004import java.util.concurrent.atomic.AtomicInteger;
005import java.util.concurrent.locks.Condition;
006import java.util.concurrent.locks.Lock;
007
008/**
009 * Lock which acts on behalf of another lock and acquires its own lock only
010 *  if the master lock is not held. This lock is used for executing one logical 
011 *  store operation in multiple threads.
012 * @author Pavel Vlasov
013 *
014 */
015public class DeputyLock implements TrackingLock {
016        
017        private Lock master;
018        private boolean masterLocked;
019        private AtomicInteger lockCounter = new AtomicInteger(0);
020        private boolean canNotBeLocked;
021        private String msg;
022
023        public DeputyLock(Lock master, boolean masterLocked, boolean canNotBeLocked, String msg) {
024                this.master = master;
025                this.masterLocked = masterLocked;
026                this.canNotBeLocked = canNotBeLocked;
027                this.msg = msg;
028        }
029        
030        private void checkLockability() {
031                if (canNotBeLocked) {
032                        throw new IllegalStateException(msg);
033                }
034        }
035
036        @Override
037        public void lock() {
038                if (!masterLocked) {
039                        checkLockability();
040                        master.lock();
041                        lockCounter.incrementAndGet();
042                }
043        }
044
045        @Override
046        public void lockInterruptibly() throws InterruptedException {
047                if (!masterLocked) {
048                        checkLockability();
049                        master.lockInterruptibly();
050                        lockCounter.incrementAndGet();
051                }
052        }
053
054        @Override
055        public boolean tryLock() {
056                if (masterLocked) {
057                        return true;
058                }
059                checkLockability();
060                if (master.tryLock()) {
061                        lockCounter.incrementAndGet();
062                        return true;
063                }
064                return false;
065        }
066
067        @Override
068        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
069                if (masterLocked) {
070                        return true;
071                }
072                checkLockability();
073                if (master.tryLock(time, unit)) {
074                        lockCounter.incrementAndGet();
075                        return true;
076                }
077                return false;
078        }
079
080        @Override
081        public void unlock() {
082                if (masterLocked) {
083                        master.unlock();
084                        lockCounter.decrementAndGet();
085                }
086        }
087        
088        public boolean isLocked() {
089                return masterLocked || lockCounter.get()>0;
090        }
091
092        @Override
093        public Condition newCondition() {
094                return master.newCondition();
095        }
096        
097//      public DeputyLock createDeputy() {
098//              return new DeputyLock(this, isLocked(), canNotBeLocked, msg);
099//      }
100
101}