001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.xact.RowLocking2
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.raw.xact;
023:
024: import org.apache.derby.iapi.services.locks.LockFactory;
025: import org.apache.derby.iapi.services.locks.C_LockFactory;
026: import org.apache.derby.iapi.services.locks.Latch;
027:
028: import org.apache.derby.iapi.services.sanity.SanityManager;
029:
030: import org.apache.derby.iapi.store.raw.ContainerHandle;
031: import org.apache.derby.iapi.store.raw.ContainerLock;
032: import org.apache.derby.iapi.store.raw.LockingPolicy;
033: import org.apache.derby.iapi.store.raw.RecordHandle;
034: import org.apache.derby.iapi.store.raw.RowLock;
035: import org.apache.derby.iapi.store.raw.Transaction;
036:
037: import org.apache.derby.iapi.error.StandardException;
038:
039: /**
040: A locking policy that implements row level locking with isolation degree 2.
041:
042: The approach is to place all "write" container and row locks on the
043: transaction group lock list. Locks on this group will last until end
044: of transaction. All "read" container and row locks will be placed
045: on a group list, key'd by the ContainerId of the lock. Locks on this
046: list will either be released explicitly by the caller, or will be released
047: as a group when the unlockContainer() call is made.
048:
049: Note that write operations extend from the RowLocking3 implementations.
050:
051: @see org.apache.derby.iapi.store.raw.LockingPolicy
052: */
053: public class RowLocking2 extends RowLockingRR {
054: // no locking has no state, so it's safe to hold
055: // it as a static
056: private static final LockingPolicy NO_LOCK = new NoLocking();
057:
058: protected RowLocking2(LockFactory lf) {
059: super (lf);
060: }
061:
062: /**
063: * Obtain container level intent lock.
064: * <p>
065: * This implementation of row locking is 2 level, ie. table and row locking.
066: * It will interact correctly with tables opened with ContainerLocking3
067: * locking mode.
068: * <p>
069: * Updater's will get table level IX locks, and X row locks.
070: * <p>
071: * Reader's will get table level IS locks, and S row locks.
072: * <p>
073: * Read locks are put in a separate "group" from the transaction, so that
074: * when the container is closed it can release these read locks.
075: *
076: * @param t Transaction to associate lock with.
077: * @param container Container to lock.
078: * @param waitForLock Should lock request wait until granted?
079: * @param forUpdate Should container be locked for update, or read?
080: *
081: * @return true if the lock was obtained, false if it wasn't.
082: * False should only be returned if the waitForLock policy was set to
083: * "false," and the lock was unavailable.
084: *
085: * @exception StandardException Standard exception policy.
086: **/
087: public boolean lockContainer(Transaction t,
088: ContainerHandle container, boolean waitForLock,
089: boolean forUpdate) throws StandardException {
090: Object qualifier = forUpdate ? ContainerLock.CIX
091: : ContainerLock.CIS;
092:
093: // for cursor stability put read locks on a separate lock chain, which
094: // will be released when the container is unlocked.
095: Object group = forUpdate ? ((Object) t) : ((Object) container
096: .getUniqueId());
097:
098: boolean gotLock = lf.lockObject(t.getCompatibilitySpace(),
099: group, container.getId(), qualifier,
100: waitForLock ? C_LockFactory.TIMED_WAIT
101: : C_LockFactory.NO_WAIT);
102:
103: if (gotLock) {
104: // look for covering table locks
105: // CIS and CIX is covered by CX
106: // In that case move the lock to the transaction list from the
107: // container list, as the null locking policy will do nothing in
108: // unlockContainer().
109: //
110:
111: if (lf.isLockHeld(t.getCompatibilitySpace(), t, container
112: .getId(), ContainerLock.CX)) {
113: //release any container group locks becuase CX container lock will cover everthing.
114: lf.unlockGroup(t.getCompatibilitySpace(), container
115: .getUniqueId());
116: container.setLockingPolicy(NO_LOCK);
117: } else if ((!forUpdate)
118: && lf.isLockHeld(t.getCompatibilitySpace(), t,
119: container.getId(), ContainerLock.CS)) {
120: // move locks from container group to transaction group.
121: lf.transfer(t.getCompatibilitySpace(), group, t);
122: container.setLockingPolicy(NO_LOCK);
123: }
124: }
125:
126: return gotLock;
127: }
128:
129: /**
130: * Obtain lock on record being read.
131: * <p>
132: * Assumes that a table level IS has been acquired. Will acquire a Shared
133: * or Update lock on the row, depending on the "forUpdate" parameter.
134: * <p>
135: * Read lock will be placed on separate group from transaction.
136: *
137: * @param t The transaction to associate the lock with.
138: * @param record The record to be locked.
139: * @param waitForLock Should lock request wait until granted?
140: * @param forUpdate Whether to open for read or write access.
141: *
142: * @return true if the lock was granted, false if waitForLock was false
143: * and the lock could not be granted.
144: *
145: * @exception StandardException Standard exception policy.
146: **/
147: public boolean lockRecordForRead(Transaction t,
148: ContainerHandle container_handle, RecordHandle record,
149: boolean waitForLock, boolean forUpdate)
150: throws StandardException {
151: Object qualifier = forUpdate ? RowLock.RU2 : RowLock.RS2;
152:
153: return (lf.lockObject(t.getCompatibilitySpace(),
154: container_handle.getUniqueId(), record, qualifier,
155: waitForLock ? C_LockFactory.TIMED_WAIT
156: : C_LockFactory.NO_WAIT));
157: }
158:
159: /**
160: * Obtain lock on record being read while holding a latch.
161: * <p>
162: * Assumes that a table level IS has been acquired. Will acquire a Shared
163: * or Update lock on the row, depending on the "forUpdate" parameter.
164: * <p>
165: *
166: * @param latch The latch being held.
167: * @param record The record to be locked.
168: * @param forUpdate Whether to open for read or write access.
169: *
170: * @exception StandardException Standard exception policy.
171: **/
172: public void lockRecordForRead(Latch latch, RecordHandle record,
173: boolean forUpdate) throws StandardException {
174: // RESOLVE - Did I do the right thing with the "forUpdate" variable.
175: // RESOLVE (mikem) - looks like it needs work for update locks, and
176: // compatibility spaces.
177:
178: Object qualifier = forUpdate ? RowLock.RU2 : RowLock.RS2;
179:
180: lf.lockObject(record.getContainerId(), record, qualifier,
181: C_LockFactory.TIMED_WAIT, latch);
182: }
183:
184: public void unlockRecordAfterRead(Transaction t,
185: ContainerHandle container_handle, RecordHandle record,
186: boolean forUpdate, boolean row_qualified)
187: throws StandardException {
188: Object qualifier = forUpdate ? RowLock.RU2 : RowLock.RS2;
189:
190: int count = lf.unlock(t.getCompatibilitySpace(),
191: container_handle.getUniqueId(), record, qualifier);
192:
193: if (SanityManager.DEBUG) {
194: // in the case of lock escalation the count could be 0.
195: if (!(count == 1 || count == 0)) {
196: SanityManager.THROWASSERT("count = " + count
197: + "record.getContainerId() = "
198: + record.getContainerId());
199: }
200: }
201: }
202:
203: /**
204: * Unlock read locks.
205: * <p>
206: * In Cursor stability release all read locks obtained. unlockContainer()
207: * will be called when the container is closed.
208: * <p>
209: *
210: * @param t The transaction to associate the lock with.
211: * @param container_handle Container to unlock.
212: **/
213: public void unlockContainer(Transaction t,
214: ContainerHandle container_handle) {
215: // Only release read locks before end of transaction in level 2.
216: lf.unlockGroup(t.getCompatibilitySpace(), container_handle
217: .getUniqueId());
218: }
219: }
|