--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.raw.xact.RowLocking2\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.raw.xact;\r
+\r
+import org.apache.derby.iapi.services.locks.LockFactory;\r
+import org.apache.derby.iapi.services.locks.C_LockFactory;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.ContainerLock;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+import org.apache.derby.iapi.store.raw.RowLock;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+\r
+/**\r
+ A locking policy that implements row level locking with isolation degree 2.\r
+\r
+ The approach is to place all "write" container and row locks on the \r
+ transaction group lock list. Locks on this group will last until end\r
+ of transaction. All "read" container and row locks will be placed \r
+ on a group list, key'd by the ContainerId of the lock. Locks on this\r
+ list will either be released explicitly by the caller, or will be released\r
+ as a group when the unlockContainer() call is made.\r
+\r
+ Note that write operations extend from the RowLocking3 implementations.\r
+\r
+ @see org.apache.derby.iapi.store.raw.LockingPolicy\r
+*/\r
+public class RowLocking2 extends RowLockingRR\r
+{\r
+ // no locking has no state, so it's safe to hold\r
+ // it as a static\r
+ private static final LockingPolicy NO_LOCK = new NoLocking();\r
+\r
+ protected RowLocking2(LockFactory lf) \r
+ {\r
+ super(lf);\r
+ }\r
+\r
+ /**\r
+ * Obtain container level intent lock.\r
+ * <p>\r
+ * This implementation of row locking is 2 level, ie. table and row locking.\r
+ * It will interact correctly with tables opened with ContainerLocking3\r
+ * locking mode.\r
+ * <p>\r
+ * Updater's will get table level IX locks, and X row locks.\r
+ * <p>\r
+ * Reader's will get table level IS locks, and S row locks.\r
+ * <p>\r
+ * Read locks are put in a separate "group" from the transaction, so that\r
+ * when the container is closed it can release these read locks.\r
+ *\r
+ * @param t Transaction to associate lock with.\r
+ * @param container Container to lock.\r
+ * @param waitForLock Should lock request wait until granted?\r
+ * @param forUpdate Should container be locked for update, or read?\r
+ *\r
+ * @return true if the lock was obtained, false if it wasn't. \r
+ * False should only be returned if the waitForLock policy was set to\r
+ * "false," and the lock was unavailable.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean lockContainer(\r
+ Transaction t, \r
+ ContainerHandle container, \r
+ boolean waitForLock,\r
+ boolean forUpdate)\r
+ throws StandardException \r
+ {\r
+ Object qualifier = forUpdate ? ContainerLock.CIX : ContainerLock.CIS;\r
+\r
+ // for cursor stability put read locks on a separate lock chain, which\r
+ // will be released when the container is unlocked.\r
+ Object group = \r
+ forUpdate ? ((Object) t) : ((Object) container.getUniqueId());\r
+\r
+ boolean gotLock = \r
+ lf.lockObject(\r
+ t.getCompatibilitySpace(), group, container.getId(), qualifier,\r
+ waitForLock ? C_LockFactory.TIMED_WAIT : C_LockFactory.NO_WAIT);\r
+\r
+ if (gotLock) \r
+ {\r
+ // look for covering table locks\r
+ // CIS and CIX is covered by CX \r
+ // In that case move the lock to the transaction list from the\r
+ // container list, as the null locking policy will do nothing in\r
+ // unlockContainer().\r
+ //\r
+\r
+\r
+ if (lf.isLockHeld(t.getCompatibilitySpace(), t, container.getId(),\r
+ ContainerLock.CX))\r
+ {\r
+ //release any container group locks becuase CX container lock will cover everthing.\r
+ lf.unlockGroup(t.getCompatibilitySpace(), container.getUniqueId());\r
+ container.setLockingPolicy(NO_LOCK);\r
+ }else if ((!forUpdate) && \r
+ lf.isLockHeld(t.getCompatibilitySpace(), t, container.getId(), ContainerLock.CS))\r
+ {\r
+ // move locks from container group to transaction group.\r
+ lf.transfer(t.getCompatibilitySpace(), group, t);\r
+ container.setLockingPolicy(NO_LOCK);\r
+ }\r
+ }\r
+\r
+ return gotLock;\r
+ }\r
+\r
+\r
+ /**\r
+ * Obtain lock on record being read.\r
+ * <p>\r
+ * Assumes that a table level IS has been acquired. Will acquire a Shared\r
+ * or Update lock on the row, depending on the "forUpdate" parameter.\r
+ * <p>\r
+ * Read lock will be placed on separate group from transaction.\r
+ *\r
+ * @param t The transaction to associate the lock with.\r
+ * @param record The record to be locked.\r
+ * @param waitForLock Should lock request wait until granted?\r
+ * @param forUpdate Whether to open for read or write access.\r
+ *\r
+ * @return true if the lock was granted, false if waitForLock was false \r
+ * and the lock could not be granted.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean lockRecordForRead(\r
+ Transaction t, \r
+ ContainerHandle container_handle,\r
+ RecordHandle record, \r
+ boolean waitForLock,\r
+ boolean forUpdate)\r
+ throws StandardException\r
+ {\r
+ Object qualifier = forUpdate ? RowLock.RU2 : RowLock.RS2;\r
+\r
+ return( \r
+ lf.lockObject(\r
+ t.getCompatibilitySpace(), \r
+ container_handle.getUniqueId(), \r
+ record, \r
+ qualifier,\r
+ waitForLock ? \r
+ C_LockFactory.TIMED_WAIT : C_LockFactory.NO_WAIT));\r
+ }\r
+\r
+ public void unlockRecordAfterRead(\r
+ Transaction t, \r
+ ContainerHandle container_handle,\r
+ RecordHandle record, \r
+ boolean forUpdate,\r
+ boolean row_qualified)\r
+ throws StandardException\r
+ {\r
+ Object qualifier = forUpdate ? RowLock.RU2 : RowLock.RS2;\r
+\r
+ int count = \r
+ lf.unlock(\r
+ t.getCompatibilitySpace(), container_handle.getUniqueId(), \r
+ record, qualifier);\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // in the case of lock escalation the count could be 0.\r
+ if (!(count == 1 || count == 0))\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "count = " + count +\r
+ "record.getContainerId() = " + record.getContainerId());\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Unlock read locks.\r
+ * <p>\r
+ * In Cursor stability release all read locks obtained. unlockContainer()\r
+ * will be called when the container is closed.\r
+ * <p>\r
+ *\r
+ * @param t The transaction to associate the lock with.\r
+ * @param container_handle Container to unlock.\r
+ **/\r
+ public void unlockContainer(\r
+ Transaction t, \r
+ ContainerHandle container_handle)\r
+ {\r
+ // Only release read locks before end of transaction in level 2.\r
+ lf.unlockGroup(\r
+ t.getCompatibilitySpace(), container_handle.getUniqueId());\r
+ }\r
+}\r