001    package org.apache.ojb.odmg.locking;
002    
003    /* Copyright 2002-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import org.apache.ojb.odmg.TransactionImpl;
019    
020    import java.util.Collection;
021    
022    /**
023     * The implementation of the Repeatable Reads Locking strategy.
024     * Locks are obtained for reading and modifying the database.
025     * Locks on all modified objects are held until EOT.
026     * Locks obtained for reading data are held until EOT.
027     * Allows:
028     * Phantom Reads
029     *
030     * @author Thomas Mahler & David Dixon-Peugh
031     */
032    public class RepeatableReadStrategy extends AbstractLockStrategy
033    {
034        /**
035         * acquire a read lock on Object obj for Transaction tx.
036         * @param tx the transaction requesting the lock
037         * @param obj the Object to be locked
038         * @return true if successful, else false
039         *
040         */
041        public boolean readLock(TransactionImpl tx, Object obj)
042        {
043            LockEntry writer = getWriter(obj);
044            if (writer == null)
045            {
046                if (addReader(tx, obj))
047                    return true;
048                else
049                    return readLock(tx, obj);
050            }
051            if (writer.isOwnedBy(tx))
052            {
053                return true;    // If I'm the writer, I can read.
054            }
055            else
056                return false;
057    
058        }
059    
060        /**
061         * acquire a write lock on Object obj for Transaction tx.
062         * @param tx the transaction requesting the lock
063         * @param obj the Object to be locked
064         * @return true if successful, else false
065         *
066         */
067        public boolean writeLock(TransactionImpl tx, Object obj)
068        {
069            LockEntry writer = getWriter(obj);
070            Collection readers = getReaders(obj);
071            if (writer == null)
072            {
073                if (readers.size() == 0)
074                {
075                    if (setWriter(tx, obj))
076                        return true;
077                    else
078                        return writeLock(tx, obj);
079                }
080    
081                else if (readers.size() == 1)
082                {
083                    if (((LockEntry) readers.iterator().next()).isOwnedBy(tx))
084                        return upgradeLock(tx, obj);
085                }
086            }
087            else if (writer.isOwnedBy(tx))
088            {
089                return true;    // If I'm the writer, then I can write.
090            }
091            return false;
092        }
093    
094    
095        /**
096         * acquire a lock upgrade (from read to write) lock on Object obj for Transaction tx.
097         * @param tx the transaction requesting the lock
098         * @param obj the Object to be locked
099         * @return true if successful, else false
100         *
101         */
102        public boolean upgradeLock(TransactionImpl tx, Object obj)
103        {
104            LockEntry writer = getWriter(obj);
105            if (writer == null)
106            {
107                Collection readers = this.getReaders(obj);
108                if (readers.size() == 1)
109                {
110                    LockEntry reader = (LockEntry) readers.iterator().next();
111                    if (reader.isOwnedBy(tx))
112                    {
113                        if (upgradeLock(reader))
114                            return true;
115                        else
116                            return upgradeLock(tx, obj);
117                    }
118                }
119                else if (readers.size() == 0)
120                {
121                    if (setWriter(tx, obj))
122                        return true;
123                    else
124                        return upgradeLock(tx, obj);
125                }
126    
127    
128            }
129            else if (writer.isOwnedBy(tx))
130            {
131                return true;    // If I already have Write, then I've upgraded.
132            }
133    
134            return false;
135        }
136    
137        /**
138         * release a lock on Object obj for Transaction tx.
139         * @param tx the transaction releasing the lock
140         * @param obj the Object to be unlocked
141         * @return true if successful, else false
142         *
143         */
144        public boolean releaseLock(TransactionImpl tx, Object obj)
145        {
146            LockEntry writer = getWriter(obj);
147            if (writer != null && writer.isOwnedBy(tx))
148            {
149                removeWriter(writer);
150                return true;
151            }
152            if (hasReadLock(tx, obj))
153            {
154                removeReader(tx, obj);
155                return true;
156            }
157            return false;
158        }
159    
160        /**
161         * checks whether the specified Object obj is read-locked by Transaction tx.
162         * @param tx the transaction
163         * @param obj the Object to be checked
164         * @return true if lock exists, else false
165         */
166        public boolean checkRead(TransactionImpl tx, Object obj)
167        {
168            if (hasReadLock(tx, obj))
169            {
170                return true;
171            }
172            LockEntry writer = getWriter(obj);
173            if (writer != null && writer.isOwnedBy(tx))
174            {
175                return true;
176            }
177            else
178                return false;
179        }
180    
181        /**
182         * checks whether the specified Object obj is write-locked by Transaction tx.
183         * @param tx the transaction
184         * @param obj the Object to be checked
185         * @return true if lock exists, else false
186         */
187        public boolean checkWrite(TransactionImpl tx, Object obj)
188        {
189            LockEntry writer = getWriter(obj);
190            return (writer != null && writer.isOwnedBy(tx));
191        }
192    }