001: /*
002:
003: Derby - Class org.apache.derby.diag.LockTable
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.diag;
023:
024: // temp
025: import org.apache.derby.impl.services.locks.TableNameInfo;
026:
027: import org.apache.derby.iapi.services.locks.LockFactory;
028: import org.apache.derby.iapi.services.locks.Latch;
029: import org.apache.derby.iapi.services.locks.Lockable;
030: import org.apache.derby.iapi.services.locks.VirtualLockTable;
031: import org.apache.derby.iapi.services.sanity.SanityManager;
032:
033: import org.apache.derby.iapi.error.StandardException;
034: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
035: import org.apache.derby.iapi.sql.conn.ConnectionUtil;
036: import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;
037: import org.apache.derby.iapi.store.access.TransactionController;
038: import org.apache.derby.iapi.error.PublicAPI;
039:
040: import org.apache.derby.iapi.sql.ResultColumnDescriptor;
041: import org.apache.derby.impl.jdbc.EmbedResultSetMetaData;
042:
043: import java.util.Hashtable;
044: import java.util.Enumeration;
045: import java.sql.ResultSetMetaData;
046: import java.sql.SQLException;
047: import java.sql.Types;
048: import org.apache.derby.vti.VTITemplate;
049: import org.apache.derby.vti.VTICosting;
050: import org.apache.derby.vti.VTIEnvironment;
051:
052: /**
053: LockTable is a virtual table that shows all locks currently held in
054: the database.
055:
056: This virtual table can be invoked by calling it directly
057: <PRE> select * from SYSCS_DIAG.LOCK_TABLE </PRE>
058:
059: <P>The LockTable virtual table takes a snap shot of the lock table while
060: the system is in flux, so it is possible that some locks may be in
061: transition state while the snap shot is taken. We choose to do this rather
062: then impose extranous timing restrictions so that the use of this tool will
063: not alter the normal timing and flow of execution in the application.
064:
065: <P>The LockTable virtual table has the following columns:
066: <UL><LI>XID varchar(15) - not nullable. The transaction id, this can be joined with the
067: TransactionTable virtual table's XID.</LI>
068: <LI>TYPE varchar(5) - nullable. The type of lock, ROW, TABLE, or LATCH</LI>
069: <LI>MODE varchar(4) - not nullable. The mode of the lock, "S", "U", "X", "IS", "IX".</LI>
070: <UL><LI>S is shared lock (N/A to Latch) </LI>
071: <LI>U is update lock (N/A to Latch) </LI>
072: <LI>X is exclusive lock </LI>
073: <LI>IS is intent shared lock (N/A to Latch or Row lock) </LI>
074: <LI>IX is intent exclusive lock (N/A to Latch or Row lock) </LI>
075: </UL>
076: <LI>TABLENAME varchar(128) - not nullable. The name of the base table the lock is for </LI>
077: <LI>LOCKNAME varchar(20) - not nullable. The name of the lock </LI>
078: <LI>STATE varchar(5) - nullable. GRANT or WAIT </LI>
079: <LI>TABLETYPE varchar(9) - not nullable. 'T' for user table, 'S' for system table </LI>
080: <LI>LOCKCOUNT varchar(5) - not nullable. Internal lock count.</LI>
081: <LI>INDEXNAME varchar(128) - normally null. If non-null, a lock is held on
082: the index, this can only happen if this is not a user transaction.</LI>
083: </UL>
084:
085: */
086: public class LockTable extends VTITemplate implements VTICosting {
087:
088: /** return only latches */
089: public static final int LATCH = VirtualLockTable.LATCH;
090:
091: /** return only table and row locks */
092: public static final int TABLE_AND_ROWLOCK = VirtualLockTable.TABLE_AND_ROWLOCK;
093:
094: /** return all locks and latches */
095: public static final int ALL = VirtualLockTable.ALL;
096:
097: /*
098: ** private
099: */
100: private TransactionController tc;
101: private LanguageConnectionFactory lcf;
102: private Hashtable currentRow; // an entry in the lock table
103: private Enumeration lockTable;
104: private boolean wasNull;
105: private boolean initialized;
106: private final int flag;
107: private TableNameInfo tabInfo;
108:
109: /**
110: The normal way of instantiating a LockTable, equivalent to
111: LockTable(org.apache.derby.diag.LockTable->TABLE_AND_ROWLOCK).
112: Only shows row and table lock and not latches. Latches are generally
113: held for very short duration and are not of interest to Cloudscape
114: users. Only under abnormal circumstances will one be interested in
115: looking at latches.
116: */
117: public LockTable() {
118: flag = TABLE_AND_ROWLOCK;
119: }
120:
121: /**
122: This call is intrusive and should only be used under the supervision of
123: technical support. Create an instance of the lock table which
124: has transient latches as well as locks.
125: */
126: public LockTable(int flag) {
127: this .flag = flag;
128: }
129:
130: /**
131: @see java.sql.ResultSet#getMetaData
132: */
133: public ResultSetMetaData getMetaData() {
134: return metadata;
135: }
136:
137: /**
138: @see java.sql.ResultSet#next
139: @exception SQLException if no transaction context can be found, or other
140: Cloudscape internal errors are encountered.
141: */
142: public boolean next() throws SQLException {
143: try {
144: if (!initialized) {
145: LanguageConnectionContext lcc = ConnectionUtil
146: .getCurrentLCC();
147:
148: tc = lcc.getTransactionExecute();
149: LanguageConnectionFactory lcf = lcc
150: .getLanguageConnectionFactory();
151: LockFactory lf = lcf.getAccessFactory()
152: .getLockFactory();
153: lockTable = lf.makeVirtualLockTable();
154: initialized = true;
155: tabInfo = new TableNameInfo(lcc, true);
156: }
157:
158: currentRow = null;
159: if (lockTable != null) {
160: while (lockTable.hasMoreElements()
161: && (currentRow == null)) {
162: currentRow = dumpLock((Latch) lockTable
163: .nextElement());
164: }
165: }
166: } catch (StandardException se) {
167: throw PublicAPI.wrapStandardException(se);
168: }
169:
170: return (currentRow != null);
171: }
172:
173: /**
174: @see java.sql.ResultSet#close
175: */
176: public void close() {
177: lockTable = null;
178: }
179:
180: /**
181: All columns in TransactionTable VTI are of String type.
182: @see java.sql.ResultSet#getString
183: */
184: public String getString(int columnNumber) {
185: String val = (String) currentRow
186: .get(columnInfo[columnNumber - 1].getName());
187: wasNull = (val == null);
188:
189: return val;
190: }
191:
192: /**
193: @see java.sql.ResultSet#wasNull
194: */
195: public boolean wasNull() {
196: return wasNull;
197: }
198:
199: /** VTI costing interface */
200:
201: /**
202: @see VTICosting#getEstimatedRowCount
203: */
204: public double getEstimatedRowCount(VTIEnvironment vtiEnvironment) {
205: return VTICosting.defaultEstimatedRowCount;
206: }
207:
208: /**
209: @see VTICosting#getEstimatedCostPerInstantiation
210: */
211: public double getEstimatedCostPerInstantiation(
212: VTIEnvironment vtiEnvironment) {
213: return VTICosting.defaultEstimatedCost;
214: }
215:
216: /**
217: @return false
218: @see VTICosting#supportsMultipleInstantiations
219: */
220: public boolean supportsMultipleInstantiations(
221: VTIEnvironment vtiEnvironment) {
222: return false;
223: }
224:
225: /*
226: ** Private methods
227: */
228:
229: /**
230: Convert the lock information into a hashtable.
231: */
232: private Hashtable dumpLock(Latch lock) throws StandardException {
233: Hashtable attributes = new Hashtable(17);
234: Object lock_type = lock.getQualifier();
235:
236: // 4 things we are interested in from the lockable:
237: // containerId, segmentId, pageNum, recId
238:
239: Lockable lockable = lock.getLockable();
240:
241: // see if this lockable object wants to participate
242: if (!lockable.lockAttributes(flag, attributes))
243: return null;
244:
245: // if it does, the lockable object must have filled in the following
246: // fields
247: if (SanityManager.DEBUG) {
248: SanityManager
249: .ASSERT(
250: attributes.get(VirtualLockTable.LOCKNAME) != null,
251: "lock table can only represent locks that have a LOCKNAME");
252:
253: SanityManager
254: .ASSERT(
255: attributes.get(VirtualLockTable.LOCKTYPE) != null,
256: "lock table can only represent locks that have a LOCKTYPE");
257:
258: if (attributes.get(VirtualLockTable.CONTAINERID) == null
259: && attributes.get(VirtualLockTable.CONGLOMID) == null)
260: SanityManager
261: .THROWASSERT("lock table can only represent locks that are associated with a container or conglomerate");
262: }
263:
264: if (attributes.get(VirtualLockTable.LOCKNAME) == null
265: || attributes.get(VirtualLockTable.LOCKTYPE) == null)
266: return null; // can't deal with this for now
267:
268: // if the lock has zero count and is an instance of Lock then it
269: // is a lock that has just been released. Therefore do put it into
270: // the lock table. This occurs because the Lock object is the real
271: // live object in the LockTable. Thus when we copied the lock table
272: // it had a non-zero count, but since then it has been released
273: // (after we dropped the sync). Note if it is of type ActiveLock
274: // with zero count there is stil the chance it has been released.
275: // Less likely, but we still need to fix that at some time.
276: int lockCount = lock.getCount();
277: String state;
278: if (lockCount != 0)
279: state = "GRANT";
280: else if (!(lock instanceof org.apache.derby.impl.services.locks.ActiveLock))
281: return null;
282: else
283: state = "WAIT";
284:
285: Long conglomId = (Long) attributes
286: .get(VirtualLockTable.CONGLOMID);
287:
288: if (conglomId == null) {
289: // we need to figure this out
290: if (attributes.get(VirtualLockTable.CONTAINERID) == null)
291: return null; // can't deal with this for now
292:
293: Long value = (Long) attributes
294: .get(VirtualLockTable.CONTAINERID);
295: conglomId = new Long(tc.findConglomid(value.longValue()));
296: attributes.put(VirtualLockTable.CONGLOMID, conglomId);
297: }
298:
299: attributes.put(VirtualLockTable.LOCKOBJ, lock);
300: attributes.put(VirtualLockTable.XACTID, lock
301: .getCompatabilitySpace().toString());
302: attributes.put(VirtualLockTable.LOCKMODE, lock_type.toString());
303:
304: attributes.put(VirtualLockTable.LOCKCOUNT, Integer
305: .toString(lockCount));
306:
307: attributes.put(VirtualLockTable.STATE, state);
308:
309: String tableName = tabInfo.getTableName(conglomId);
310:
311: attributes.put(VirtualLockTable.TABLENAME, tableName);
312:
313: String indexName = tabInfo.getIndexName(conglomId);
314:
315: if (indexName != null)
316: attributes.put(VirtualLockTable.INDEXNAME, indexName);
317:
318: String tableType = tabInfo.getTableType(conglomId);
319: attributes.put(VirtualLockTable.TABLETYPE, tableType);
320: return attributes;
321:
322: }
323:
324: /*
325: ** Metadata
326: */
327: private static final ResultColumnDescriptor[] columnInfo = {
328:
329: EmbedResultSetMetaData.getResultColumnDescriptor(
330: VirtualLockTable.XACTID, Types.VARCHAR, false, 15),
331: EmbedResultSetMetaData.getResultColumnDescriptor(
332: VirtualLockTable.LOCKTYPE, Types.VARCHAR, true, 5),
333: EmbedResultSetMetaData.getResultColumnDescriptor(
334: VirtualLockTable.LOCKMODE, Types.VARCHAR, false, 4),
335: EmbedResultSetMetaData.getResultColumnDescriptor(
336: VirtualLockTable.TABLENAME, Types.VARCHAR, false,
337: 128),
338: EmbedResultSetMetaData
339: .getResultColumnDescriptor(
340: VirtualLockTable.LOCKNAME, Types.VARCHAR,
341: false, 20),
342: EmbedResultSetMetaData.getResultColumnDescriptor(
343: VirtualLockTable.STATE, Types.VARCHAR, true, 5),
344: EmbedResultSetMetaData
345: .getResultColumnDescriptor(
346: VirtualLockTable.TABLETYPE, Types.VARCHAR,
347: false, 9),
348: EmbedResultSetMetaData
349: .getResultColumnDescriptor(
350: VirtualLockTable.LOCKCOUNT, Types.VARCHAR,
351: false, 5),
352: EmbedResultSetMetaData.getResultColumnDescriptor(
353: VirtualLockTable.INDEXNAME, Types.VARCHAR, true,
354: 128) };
355:
356: private static final ResultSetMetaData metadata = new EmbedResultSetMetaData(
357: columnInfo);
358: }
|