Source Code Cross Referenced for LockManager.java in  » JMX » je » com » sleepycat » je » txn » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » JMX » je » com.sleepycat.je.txn 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*-
002:         * See the file LICENSE for redistribution information.
003:         *
004:         * Copyright (c) 2002,2008 Oracle.  All rights reserved.
005:         *
006:         * $Id: LockManager.java,v 1.118.2.8 2008/02/06 12:52:30 cwl Exp $
007:         */
008:
009:        package com.sleepycat.je.txn;
010:
011:        import java.util.Collection;
012:        import java.util.HashMap;
013:        import java.util.HashSet;
014:        import java.util.Iterator;
015:        import java.util.List;
016:        import java.util.Map;
017:        import java.util.Set;
018:
019:        import com.sleepycat.je.DatabaseException;
020:        import com.sleepycat.je.DeadlockException;
021:        import com.sleepycat.je.LockStats;
022:        import com.sleepycat.je.RunRecoveryException;
023:        import com.sleepycat.je.StatsConfig;
024:        import com.sleepycat.je.config.EnvironmentParams;
025:        import com.sleepycat.je.dbi.DatabaseImpl;
026:        import com.sleepycat.je.dbi.DbConfigManager;
027:        import com.sleepycat.je.dbi.EnvConfigObserver;
028:        import com.sleepycat.je.dbi.EnvironmentImpl;
029:        import com.sleepycat.je.dbi.MemoryBudget;
030:        import com.sleepycat.je.dbi.RangeRestartException;
031:        import com.sleepycat.je.latch.Latch;
032:        import com.sleepycat.je.latch.LatchStats;
033:        import com.sleepycat.je.latch.LatchSupport;
034:
035:        /**
036:         * LockManager manages locks.
037:         *
038:         * Note that locks are counted as taking up part of the JE cache;
039:         */
040:        public abstract class LockManager implements  EnvConfigObserver {
041:
042:            /*
043:             * The total memory cost for a lock is the Lock object, plus its entry and
044:             * key in the lock hash table.
045:             *
046:             * The addition and removal of Lock objects, and the corresponding cost of
047:             * their hashmap entry and key are tracked through the LockManager.
048:             */
049:            static final long TOTAL_LOCK_OVERHEAD = MemoryBudget.LOCK_OVERHEAD
050:                    + MemoryBudget.HASHMAP_ENTRY_OVERHEAD
051:                    + MemoryBudget.LONG_OVERHEAD;
052:
053:            private static final long REMOVE_TOTAL_LOCK_OVERHEAD = 0 - TOTAL_LOCK_OVERHEAD;
054:
055:            protected int nLockTables = 1;
056:            protected Latch[] lockTableLatches;
057:            private Map[] lockTables; // keyed by nodeId
058:            private EnvironmentImpl envImpl;
059:            private MemoryBudget memoryBudget;
060:            //private Level traceLevel;
061:
062:            private long nRequests; // stats: number of time a request was made
063:            private long nWaits; // stats: number of time a request blocked
064:
065:            private static RangeRestartException rangeRestartException = new RangeRestartException();
066:            private static boolean lockTableDump = false;
067:
068:            public LockManager(EnvironmentImpl envImpl)
069:                    throws DatabaseException {
070:
071:                DbConfigManager configMgr = envImpl.getConfigManager();
072:                nLockTables = configMgr.getInt(EnvironmentParams.N_LOCK_TABLES);
073:                lockTables = new Map[nLockTables];
074:                lockTableLatches = new Latch[nLockTables];
075:                for (int i = 0; i < nLockTables; i++) {
076:                    lockTables[i] = new HashMap();
077:                    lockTableLatches[i] = LatchSupport.makeLatch("Lock Table "
078:                            + i, envImpl);
079:                }
080:                this .envImpl = envImpl;
081:                memoryBudget = envImpl.getMemoryBudget();
082:                nRequests = 0;
083:                nWaits = 0;
084:                /*
085:                    traceLevel = Tracer.parseLevel
086:                    (env, EnvironmentParams.JE_LOGGING_LEVEL_LOCKMGR);
087:                 */
088:
089:                /* Initialize mutable properties and register for notifications. */
090:                envConfigUpdate(configMgr);
091:                envImpl.addConfigObserver(this );
092:            }
093:
094:            /**
095:             * Process notifications of mutable property changes.
096:             */
097:            public void envConfigUpdate(DbConfigManager configMgr)
098:                    throws DatabaseException {
099:
100:                LockInfo
101:                        .setDeadlockStackTrace(configMgr
102:                                .getBoolean(EnvironmentParams.TXN_DEADLOCK_STACK_TRACE));
103:                setLockTableDump(configMgr
104:                        .getBoolean(EnvironmentParams.TXN_DUMPLOCKS));
105:            }
106:
107:            /**
108:             * Called when the je.txn.dumpLocks property is changed.
109:             */
110:            static void setLockTableDump(boolean enable) {
111:                lockTableDump = enable;
112:            }
113:
114:            protected int getLockTableIndex(Long nodeId) {
115:                return (((int) nodeId.longValue()) & 0x7fffffff) % nLockTables;
116:            }
117:
118:            protected int getLockTableIndex(long nodeId) {
119:                return (((int) nodeId) & 0x7fffffff) % nLockTables;
120:            }
121:
122:            /**
123:             * Attempt to acquire a lock of <i>type</i> on <i>nodeId</i>.  If the lock
124:             * acquisition would result in a deadlock, throw an exception.<br> If the
125:             * requested lock is not currently available, block until it is or until
126:             * timeout milliseconds have elapsed.<br> If a lock of <i>type</i> is
127:             * already held, return EXISTING.<br> If a WRITE lock is held and a READ
128:             * lock is requested, return PROMOTION.<br>
129:             *
130:             * If a lock request is for a lock that is not currently held, return
131:             * either NEW or DENIED depending on whether the lock is granted or
132:             * not.<br>
133:             *
134:             * @param nodeId The NodeId to lock.
135:             *
136:             * @param locker The Locker to lock this on behalf of.
137:             *
138:             * @param type The lock type requested.
139:             *
140:             * @param timeout milliseconds to time out after if lock couldn't be
141:             * obtained.  0 means block indefinitely.  Not used if nonBlockingRequest
142:             * is true.
143:             *
144:             * @param nonBlockingRequest if true, means don't block if lock can't be
145:             * acquired, and ignore the timeout parameter.
146:             *
147:             * @return a LockGrantType indicating whether the request was fulfilled
148:             * or not.  LockGrantType.NEW means the lock grant was fulfilled and
149:             * the caller did not previously hold the lock.  PROMOTION means the
150:             * lock was granted and it was a promotion from READ to WRITE.  EXISTING
151:             * means the lock was already granted (not a promotion).  DENIED means
152:             * the lock was not granted either because the timeout passed without
153:             * acquiring the lock or timeout was -1 and the lock was not immediately
154:             * available.
155:             *
156:             * @throws DeadlockException if acquiring the lock would result in
157:             * a deadlock.
158:             */
159:            public LockGrantType lock(long nodeId, Locker locker,
160:                    LockType type, long timeout, boolean nonBlockingRequest,
161:                    DatabaseImpl database) throws DeadlockException,
162:                    DatabaseException {
163:
164:                assert timeout >= 0;
165:
166:                /*
167:                 * Lock on locker before latching the lockTable to avoid having another
168:                 * notifier perform the notify before the waiter is actually waiting.
169:                 */
170:                synchronized (locker) {
171:                    Long nid = new Long(nodeId);
172:                    LockAttemptResult result = attemptLock(nid, locker, type,
173:                            nonBlockingRequest);
174:                    /* Got the lock, return. */
175:                    if (result.success
176:                            || result.lockGrant == LockGrantType.DENIED) {
177:                        return result.lockGrant;
178:                    }
179:
180:                    assert checkNoLatchesHeld(nonBlockingRequest) : LatchSupport
181:                            .countLatchesHeld()
182:                            + " latches held while trying to lock, lock table ="
183:                            + LatchSupport.latchesHeldToString();
184:
185:                    /*
186:                     * We must have gotten WAIT_* from the lock request. We know that
187:                     * this is a blocking request, because if it wasn't, Lock.lock
188:                     * would have returned DENIED. Go wait!
189:                     */
190:                    assert !nonBlockingRequest;
191:                    try {
192:                        boolean doWait = true;
193:
194:                        /*
195:                         * Before blocking, check locker timeout. We need to check here
196:                         * or lock timeouts will always take precedence and we'll never
197:                         * actually get any txn timeouts.
198:                         */
199:                        if (locker.isTimedOut()) {
200:                            if (validateOwnership(nid, locker, type, true,
201:                                    memoryBudget)) {
202:                                doWait = false;
203:                            } else {
204:                                DeadlockException DE = makeTimeoutMsg(
205:                                        "Transaction", locker, nodeId, type,
206:                                        result.lockGrant, result.useLock,
207:                                        locker.getTxnTimeOut(), locker
208:                                                .getTxnStartMillis(), System
209:                                                .currentTimeMillis(), database);
210:                                throw DE;
211:                            }
212:                        }
213:
214:                        boolean keepTime = (timeout > 0);
215:                        long startTime = (keepTime ? System.currentTimeMillis()
216:                                : 0);
217:                        while (doWait) {
218:                            locker.setWaitingFor(result.useLock);
219:                            try {
220:                                locker.wait(timeout);
221:                            } catch (InterruptedException IE) {
222:                                throw new RunRecoveryException(envImpl, IE);
223:                            }
224:
225:                            boolean lockerTimedOut = locker.isTimedOut();
226:                            long now = System.currentTimeMillis();
227:                            boolean this LockTimedOut = (keepTime && (now
228:                                    - startTime > timeout));
229:                            boolean isRestart = (result.lockGrant == LockGrantType.WAIT_RESTART);
230:
231:                            /*
232:                             * Re-check for ownership of the lock following wait.  If
233:                             * we timed out and we don't have ownership then flush this
234:                             * lock from both the waiters and owners while under the
235:                             * lock table latch.  See SR 10103.
236:                             */
237:                            if (validateOwnership(nid, locker, type,
238:                                    lockerTimedOut || this LockTimedOut
239:                                            || isRestart, memoryBudget)) {
240:                                break;
241:                            } else {
242:
243:                                /*
244:                                 * After a restart conflict the lock will not be held.
245:                                 */
246:                                if (isRestart) {
247:                                    throw rangeRestartException;
248:                                }
249:
250:                                if (this LockTimedOut) {
251:                                    locker.setOnlyAbortable();
252:                                    DeadlockException DE = makeTimeoutMsg(
253:                                            "Lock", locker, nodeId, type,
254:                                            result.lockGrant, result.useLock,
255:                                            timeout, startTime, now, database);
256:                                    throw DE;
257:                                }
258:
259:                                if (lockerTimedOut) {
260:                                    locker.setOnlyAbortable();
261:                                    DeadlockException DE = makeTimeoutMsg(
262:                                            "Transaction", locker, nodeId,
263:                                            type, result.lockGrant,
264:                                            result.useLock, locker
265:                                                    .getTxnTimeOut(), locker
266:                                                    .getTxnStartMillis(), now,
267:                                            database);
268:                                    throw DE;
269:                                }
270:                            }
271:                        }
272:                    } finally {
273:                        locker.setWaitingFor(null);
274:                        assert EnvironmentImpl.maybeForceYield();
275:                    }
276:
277:                    locker.addLock(nid, type, result.lockGrant);
278:
279:                    return result.lockGrant;
280:                }
281:            }
282:
283:            abstract protected Lock lookupLock(Long nodeId)
284:                    throws DatabaseException;
285:
286:            protected Lock lookupLockInternal(Long nodeId, int lockTableIndex)
287:                    throws DatabaseException {
288:
289:                /* Get the target lock. */
290:                Map lockTable = lockTables[lockTableIndex];
291:                Lock useLock = (Lock) lockTable.get(nodeId);
292:                return useLock;
293:            }
294:
295:            abstract protected LockAttemptResult attemptLock(Long nodeId,
296:                    Locker locker, LockType type, boolean nonBlockingRequest)
297:                    throws DatabaseException;
298:
299:            protected LockAttemptResult attemptLockInternal(Long nodeId,
300:                    Locker locker, LockType type, boolean nonBlockingRequest,
301:                    int lockTableIndex) throws DatabaseException {
302:
303:                nRequests++;
304:
305:                /* Get the target lock. */
306:                Map lockTable = lockTables[lockTableIndex];
307:                Lock useLock = (Lock) lockTable.get(nodeId);
308:                if (useLock == null) {
309:                    useLock = new Lock();
310:                    lockTable.put(nodeId, useLock);
311:                    memoryBudget.updateLockMemoryUsage(TOTAL_LOCK_OVERHEAD,
312:                            lockTableIndex);
313:                }
314:
315:                /*
316:                 * Attempt to lock.  Possible return values are NEW, PROMOTION, DENIED,
317:                 * EXISTING, WAIT_NEW, WAIT_PROMOTION, WAIT_RESTART.
318:                 */
319:                LockGrantType lockGrant = useLock.lock(type, locker,
320:                        nonBlockingRequest, memoryBudget, lockTableIndex);
321:                boolean success = false;
322:
323:                /* Was the attempt successful? */
324:                if ((lockGrant == LockGrantType.NEW)
325:                        || (lockGrant == LockGrantType.PROMOTION)) {
326:                    locker.addLock(nodeId, type, lockGrant);
327:                    success = true;
328:                } else if (lockGrant == LockGrantType.EXISTING) {
329:                    success = true;
330:                } else if (lockGrant == LockGrantType.DENIED) {
331:                    /* Locker.lock will throw LockNotGrantedException. */
332:                } else {
333:                    nWaits++;
334:                }
335:                return new LockAttemptResult(useLock, lockGrant, success);
336:            }
337:
338:            /**
339:             * Create a informative lock or txn timeout message.
340:             */
341:            protected abstract DeadlockException makeTimeoutMsg(
342:                    String lockOrTxn, Locker locker, long nodeId,
343:                    LockType type, LockGrantType grantType, Lock useLock,
344:                    long timeout, long start, long now, DatabaseImpl database)
345:                    throws DatabaseException;
346:
347:            /**
348:             * Do the real work of creating an lock or txn timeout message.
349:             */
350:            protected DeadlockException makeTimeoutMsgInternal(
351:                    String lockOrTxn, Locker locker, long nodeId,
352:                    LockType type, LockGrantType grantType, Lock useLock,
353:                    long timeout, long start, long now, DatabaseImpl database) {
354:
355:                /*
356:                 * Because we're accessing parts of the lock, need to have protected
357:                 * access to the lock table because things can be changing out from
358:                 * underneath us.  This is a big hammer to grab for so long while we
359:                 * traverse the graph, but it's only when we have a deadlock and we're
360:                 * creating a debugging message.
361:                 *
362:                 * The alternative would be to handle ConcurrentModificationExceptions
363:                 * and retry until none of them happen.
364:                 */
365:                if (lockTableDump) {
366:                    System.out
367:                            .println("++++++++++ begin lock table dump ++++++++++");
368:                    for (int i = 0; i < nLockTables; i++) {
369:                        StringBuffer sb = new StringBuffer();
370:                        dumpToStringNoLatch(sb, i);
371:                        System.out.println(sb.toString());
372:                    }
373:                    System.out
374:                            .println("++++++++++ end lock table dump ++++++++++");
375:                }
376:
377:                StringBuffer sb = new StringBuffer();
378:                sb.append(lockOrTxn);
379:                sb.append(" expired. Locker ").append(locker);
380:                sb.append(": waited for lock");
381:
382:                if (database != null) {
383:                    sb.append(" on database=").append(database.getDebugName());
384:                }
385:                sb.append(" node=").append(nodeId);
386:                sb.append(" type=").append(type);
387:                sb.append(" grant=").append(grantType);
388:                sb.append(" timeoutMillis=").append(timeout);
389:                sb.append(" startTime=").append(start);
390:                sb.append(" endTime=").append(now);
391:                Set owners = useLock.getOwnersClone();
392:                List waiters = useLock.getWaitersListClone();
393:                sb.append("\nOwners: ").append(owners);
394:                sb.append("\nWaiters: ").append(waiters).append("\n");
395:                StringBuffer deadlockInfo = findDeadlock(useLock, locker);
396:                if (deadlockInfo != null) {
397:                    sb.append(deadlockInfo);
398:                }
399:                DeadlockException ret = new DeadlockException(sb.toString());
400:                ret.setOwnerTxnIds(getTxnIds(owners));
401:                ret.setWaiterTxnIds(getTxnIds(waiters));
402:                return ret;
403:            }
404:
405:            private long[] getTxnIds(Collection c) {
406:                long[] ret = new long[c.size()];
407:                Iterator iter = c.iterator();
408:                int i = 0;
409:                while (iter.hasNext()) {
410:                    LockInfo info = (LockInfo) iter.next();
411:                    ret[i++] = info.getLocker().getId();
412:                }
413:
414:                return ret;
415:            }
416:
417:            /**
418:             * Release a lock and possibly notify any waiters that they have been
419:             * granted the lock.
420:             *
421:             * @param nodeId The node ID of the lock to release.
422:             *
423:             * @return true if the lock is released successfully, false if
424:             * the lock is not currently being held.
425:             */
426:            boolean release(long nodeId, Locker locker)
427:                    throws DatabaseException {
428:
429:                synchronized (locker) {
430:                    Set newOwners = releaseAndFindNotifyTargets(nodeId, locker);
431:
432:                    if (newOwners == null) {
433:                        return false;
434:                    }
435:
436:                    if (newOwners.size() > 0) {
437:
438:                        /*
439:                         * There is a new set of owners and/or there are restart
440:                         * waiters that should be notified.
441:                         */
442:                        Iterator iter = newOwners.iterator();
443:
444:                        while (iter.hasNext()) {
445:                            Locker lockerToNotify = (Locker) iter.next();
446:
447:                            /* Use notifyAll to support multiple threads per txn. */
448:                            synchronized (lockerToNotify) {
449:                                lockerToNotify.notifyAll();
450:                            }
451:
452:                            assert EnvironmentImpl.maybeForceYield();
453:                        }
454:                    }
455:
456:                    return true;
457:                }
458:            }
459:
460:            /**
461:             * Release the lock, and return the set of new owners to notify, if any.
462:             *
463:             * @return
464:             * null if the lock does not exist or the given locker was not the owner,
465:             * a non-empty set if owners should be notified after releasing,
466:             * an empty set if no notification is required.
467:             */
468:            protected abstract Set releaseAndFindNotifyTargets(long nodeId,
469:                    Locker locker) throws DatabaseException;
470:
471:            /**
472:             * Do the real work of releaseAndFindNotifyTargets
473:             */
474:            protected Set releaseAndFindNotifyTargetsInternal(long nodeId,
475:                    Locker locker, int lockTableIndex) throws DatabaseException {
476:
477:                Map lockTable = lockTables[lockTableIndex];
478:                Lock useLock = (Lock) lockTable.get(new Long(nodeId));
479:
480:                if (useLock == null) {
481:                    /* Lock doesn't exist. */
482:                    return null;
483:                }
484:
485:                Set lockersToNotify = useLock.release(locker, memoryBudget,
486:                        lockTableIndex);
487:                if (lockersToNotify == null) {
488:                    /* Not owner. */
489:                    return null;
490:                }
491:
492:                /* If it's not in use at all, remove it from the lock table. */
493:                if ((useLock.nWaiters() == 0) && (useLock.nOwners() == 0)) {
494:                    lockTables[lockTableIndex].remove(new Long(nodeId));
495:                    memoryBudget.updateLockMemoryUsage(
496:                            REMOVE_TOTAL_LOCK_OVERHEAD, lockTableIndex);
497:                }
498:
499:                return lockersToNotify;
500:            }
501:
502:            /**
503:             * Transfer ownership a lock from one locker to another locker. We're not
504:             * sending any notification to the waiters on the lock table, and the past
505:             * and present owner should be ready for the transfer.
506:             */
507:            abstract void transfer(long nodeId, Locker owningLocker,
508:                    Locker destLocker, boolean demoteToRead)
509:                    throws DatabaseException;
510:
511:            /**
512:             * Do the real work of transfer
513:             */
514:            protected void transferInternal(long nodeId, Locker owningLocker,
515:                    Locker destLocker, boolean demoteToRead, int lockTableIndex)
516:                    throws DatabaseException {
517:
518:                Map lockTable = lockTables[lockTableIndex];
519:                Lock useLock = (Lock) lockTable.get(new Long(nodeId));
520:
521:                assert useLock != null : "Transfer, lock " + nodeId
522:                        + " was null";
523:                if (demoteToRead) {
524:                    useLock.demote(owningLocker);
525:                }
526:                useLock.transfer(new Long(nodeId), owningLocker, destLocker,
527:                        memoryBudget, lockTableIndex);
528:                owningLocker.removeLock(nodeId);
529:            }
530:
531:            /**
532:             * Transfer ownership a lock from one locker to a set of other txns,
533:             * cloning the lock as necessary. This will always be demoted to read, as
534:             * we can't have multiple locker owners any other way.  We're not sending
535:             * any notification to the waiters on the lock table, and the past and
536:             * present owners should be ready for the transfer.
537:             */
538:            abstract void transferMultiple(long nodeId, Locker owningLocker,
539:                    Locker[] destLockers) throws DatabaseException;
540:
541:            /**
542:             * Do the real work of transferMultiple
543:             */
544:            protected void transferMultipleInternal(long nodeId,
545:                    Locker owningLocker, Locker[] destLockers,
546:                    int lockTableIndex) throws DatabaseException {
547:
548:                Map lockTable = lockTables[lockTableIndex];
549:                Lock useLock = (Lock) lockTable.get(new Long(nodeId));
550:
551:                assert useLock != null : "Transfer, lock " + nodeId
552:                        + " was null";
553:                useLock.demote(owningLocker);
554:                useLock.transferMultiple(new Long(nodeId), owningLocker,
555:                        destLockers, memoryBudget, lockTableIndex);
556:                owningLocker.removeLock(nodeId);
557:            }
558:
559:            /**
560:             * Demote a lock from write to read. Call back to the owning locker to
561:             * move this to its read collection.
562:             * @param lock The lock to release. If null, use nodeId to find lock
563:             * @param locker
564:             */
565:            abstract void demote(long nodeId, Locker locker)
566:                    throws DatabaseException;
567:
568:            /**
569:             * Do the real work of demote.
570:             */
571:            protected void demoteInternal(long nodeId, Locker locker,
572:                    int lockTableIndex) throws DatabaseException {
573:
574:                Map lockTable = lockTables[lockTableIndex];
575:                Lock useLock = (Lock) lockTable.get(new Long(nodeId));
576:                useLock.demote(locker);
577:                locker.moveWriteToReadLock(nodeId, useLock);
578:            }
579:
580:            /**
581:             * Test the status of the lock on nodeId.  If any transaction holds any
582:             * lock on it, true is returned.  If no transaction holds a lock on it,
583:             * false is returned.
584:             *
585:             * This method is only used by unit tests.
586:             *
587:             * @param nodeId The NodeId to check.
588:             * @return true if any transaction holds any lock on the nodeid. false
589:             * if no lock is held by any transaction.
590:             */
591:            abstract boolean isLocked(Long nodeId) throws DatabaseException;
592:
593:            /**
594:             * Do the real work of isLocked.
595:             */
596:            protected boolean isLockedInternal(Long nodeId, int lockTableIndex) {
597:
598:                Map lockTable = lockTables[lockTableIndex];
599:                Lock entry = (Lock) lockTable.get(nodeId);
600:                if (entry == null) {
601:                    return false;
602:                }
603:
604:                return entry.nOwners() != 0;
605:            }
606:
607:            /**
608:             * Return true if this locker owns this a lock of this type on given node.
609:             *
610:             * This method is only used by unit tests.
611:             */
612:            abstract boolean isOwner(Long nodeId, Locker locker, LockType type)
613:                    throws DatabaseException;
614:
615:            /**
616:             * Do the real work of isOwner.
617:             */
618:            protected boolean isOwnerInternal(Long nodeId, Locker locker,
619:                    LockType type, int lockTableIndex) {
620:
621:                Map lockTable = lockTables[lockTableIndex];
622:                Lock entry = (Lock) lockTable.get(nodeId);
623:                if (entry == null) {
624:                    return false;
625:                }
626:
627:                return entry.isOwner(locker, type);
628:            }
629:
630:            /**
631:             * Return true if this locker is waiting on this lock.
632:             *
633:             * This method is only used by unit tests.
634:             */
635:            abstract boolean isWaiter(Long nodeId, Locker locker)
636:                    throws DatabaseException;
637:
638:            /**
639:             * Do the real work of isWaiter.
640:             */
641:            protected boolean isWaiterInternal(Long nodeId, Locker locker,
642:                    int lockTableIndex) {
643:
644:                Map lockTable = lockTables[lockTableIndex];
645:                Lock entry = (Lock) lockTable.get(nodeId);
646:                if (entry == null) {
647:                    return false;
648:                }
649:
650:                return entry.isWaiter(locker);
651:            }
652:
653:            /**
654:             * Return the number of waiters for this lock.
655:             */
656:            abstract int nWaiters(Long nodeId) throws DatabaseException;
657:
658:            /**
659:             * Do the real work of nWaiters.
660:             */
661:            protected int nWaitersInternal(Long nodeId, int lockTableIndex) {
662:
663:                Map lockTable = lockTables[lockTableIndex];
664:                Lock entry = (Lock) lockTable.get(nodeId);
665:                if (entry == null) {
666:                    return -1;
667:                }
668:
669:                return entry.nWaiters();
670:            }
671:
672:            /**
673:             * Return the number of owners of this lock.
674:             */
675:            abstract int nOwners(Long nodeId) throws DatabaseException;
676:
677:            /**
678:             * Do the real work of nWaiters.
679:             */
680:            protected int nOwnersInternal(Long nodeId, int lockTableIndex) {
681:
682:                Map lockTable = lockTables[lockTableIndex];
683:                Lock entry = (Lock) lockTable.get(nodeId);
684:                if (entry == null) {
685:                    return -1;
686:                }
687:
688:                return entry.nOwners();
689:            }
690:
691:            /**
692:             * @return the transaction that owns the write lock for this
693:             */
694:            abstract Locker getWriteOwnerLocker(Long nodeId)
695:                    throws DatabaseException;
696:
697:            /**
698:             * Do the real work of getWriteOwnerLocker.
699:             */
700:            protected Locker getWriteOwnerLockerInternal(Long nodeId,
701:                    int lockTableIndex) throws DatabaseException {
702:
703:                Map lockTable = lockTables[lockTableIndex];
704:                Lock lock = (Lock) lockTable.get(nodeId);
705:                if (lock == null) {
706:                    return null;
707:                } else if (lock.nOwners() > 1) {
708:                    /* not a write lock */
709:                    return null;
710:                } else {
711:                    return lock.getWriteOwnerLocker();
712:                }
713:            }
714:
715:            /*
716:             * Check if we got ownership while we were waiting.  If we didn't get
717:             * ownership, and we timed out, remove this locker from the set of
718:             * waiters. Do this in a critical section to prevent any orphaning of the
719:             * lock -- we must be in a critical section between the time that we check
720:             * ownership and when we flush any waiters (SR #10103)
721:             * @return true if you are the owner.
722:             */
723:            abstract protected boolean validateOwnership(Long nodeId,
724:                    Locker locker, LockType type, boolean flushFromWaiters,
725:                    MemoryBudget mb) throws DatabaseException;
726:
727:            /*
728:             * Do the real work of validateOwnershipInternal.
729:             */
730:            protected boolean validateOwnershipInternal(Long nodeId,
731:                    Locker locker, LockType type, boolean flushFromWaiters,
732:                    MemoryBudget mb, int lockTableIndex)
733:                    throws DatabaseException {
734:
735:                if (isOwnerInternal(nodeId, locker, type, lockTableIndex)) {
736:                    return true;
737:                }
738:
739:                if (flushFromWaiters) {
740:                    Lock entry = (Lock) lockTables[lockTableIndex].get(nodeId);
741:                    if (entry != null) {
742:                        entry.flushWaiter(locker, mb, lockTableIndex);
743:                    }
744:                }
745:                return false;
746:            }
747:
748:            /**
749:             * Statistics
750:             */
751:            public LockStats lockStat(StatsConfig config)
752:                    throws DatabaseException {
753:
754:                LockStats stats = new LockStats();
755:                stats.setNRequests(nRequests);
756:                stats.setNWaits(nWaits);
757:                if (config.getClear()) {
758:                    nWaits = 0;
759:                    nRequests = 0;
760:                }
761:
762:                for (int i = 0; i < nLockTables; i++) {
763:                    LatchStats latchStats = (LatchStats) lockTableLatches[i]
764:                            .getLatchStats();
765:                    stats.accumulateLockTableLatchStats(latchStats);
766:                }
767:
768:                /* Dump info about the lock table. */
769:                if (!config.getFast()) {
770:                    dumpLockTable(stats);
771:                }
772:                return stats;
773:            }
774:
775:            /**
776:             * Dump the lock table to the lock stats.
777:             */
778:            abstract protected void dumpLockTable(LockStats stats)
779:                    throws DatabaseException;
780:
781:            /**
782:             * Do the real work of dumpLockTableInternal.
783:             */
784:            protected void dumpLockTableInternal(LockStats stats, int i) {
785:                Map lockTable = lockTables[i];
786:                stats.accumulateNTotalLocks(lockTable.size());
787:                Iterator iter = lockTable.values().iterator();
788:                while (iter.hasNext()) {
789:                    Lock lock = (Lock) iter.next();
790:                    stats.setNWaiters(stats.getNWaiters() + lock.nWaiters());
791:                    stats.setNOwners(stats.getNOwners() + lock.nOwners());
792:
793:                    /* Go through all the owners for a lock. */
794:                    Iterator ownerIter = lock.getOwnersClone().iterator();
795:                    while (ownerIter.hasNext()) {
796:                        LockInfo info = (LockInfo) ownerIter.next();
797:                        if (info.getLockType().isWriteLock()) {
798:                            stats.setNWriteLocks(stats.getNWriteLocks() + 1);
799:                        } else {
800:                            stats.setNReadLocks(stats.getNReadLocks() + 1);
801:                        }
802:                    }
803:                }
804:            }
805:
806:            /**
807:             * Debugging
808:             */
809:            public void dump() throws DatabaseException {
810:
811:                System.out.println(dumpToString());
812:            }
813:
814:            public String dumpToString() throws DatabaseException {
815:
816:                StringBuffer sb = new StringBuffer();
817:                for (int i = 0; i < nLockTables; i++) {
818:                    lockTableLatches[i].acquire();
819:                    try {
820:                        dumpToStringNoLatch(sb, i);
821:                    } finally {
822:                        lockTableLatches[i].release();
823:                    }
824:                }
825:                return sb.toString();
826:            }
827:
828:            private void dumpToStringNoLatch(StringBuffer sb, int whichTable) {
829:                Map lockTable = lockTables[whichTable];
830:                Iterator entries = lockTable.entrySet().iterator();
831:
832:                while (entries.hasNext()) {
833:                    Map.Entry entry = (Map.Entry) entries.next();
834:                    Long nid = (Long) entry.getKey();
835:                    Lock lock = (Lock) entry.getValue();
836:                    sb.append("---- Node Id: ").append(nid).append("----\n");
837:                    sb.append(lock);
838:                    sb.append('\n');
839:                }
840:            }
841:
842:            private boolean checkNoLatchesHeld(boolean nonBlockingRequest) {
843:                if (nonBlockingRequest) {
844:                    return true; // don't check if it's a non blocking request.
845:                } else {
846:                    return (LatchSupport.countLatchesHeld() == 0);
847:                }
848:            }
849:
850:            private StringBuffer findDeadlock(Lock lock, Locker rootLocker) {
851:
852:                Set ownerSet = new HashSet();
853:                ownerSet.add(rootLocker);
854:                StringBuffer ret = findDeadlock1(ownerSet, lock, rootLocker);
855:                if (ret != null) {
856:                    return ret;
857:                } else {
858:                    return null;
859:                }
860:            }
861:
862:            private StringBuffer findDeadlock1(Set ownerSet, Lock lock,
863:                    Locker rootLocker) {
864:
865:                Iterator ownerIter = lock.getOwnersClone().iterator();
866:                while (ownerIter.hasNext()) {
867:                    LockInfo info = (LockInfo) ownerIter.next();
868:                    Locker locker = info.getLocker();
869:                    Lock waitsFor = locker.getWaitingFor();
870:                    if (ownerSet.contains(locker) || locker == rootLocker) {
871:                        /* Found a cycle. */
872:                        StringBuffer ret = new StringBuffer();
873:                        ret.append("Transaction ").append(locker.toString());
874:                        ret.append(" owns ").append(
875:                                System.identityHashCode(lock));
876:                        ret.append(" ").append(info).append("\n");
877:                        ret.append("Transaction ").append(locker.toString());
878:                        ret.append(" waits for ");
879:                        if (waitsFor == null) {
880:                            ret.append(" nothing");
881:                        } else {
882:                            ret.append(" node ");
883:                            ret.append(System.identityHashCode(waitsFor));
884:                        }
885:                        ret.append("\n");
886:                        return ret;
887:                    }
888:                    if (waitsFor != null) {
889:                        ownerSet.add(locker);
890:                        StringBuffer sb = findDeadlock1(ownerSet, waitsFor,
891:                                rootLocker);
892:                        String overflowTag = "<Overflow>\n";
893:                        if (sb != null) {
894:                            String waitInfo = "Transaction " + locker
895:                                    + " waits for " + waitsFor + "\n";
896:                            /* Limit length of message. */
897:                            if (sb.length() < 100000) {
898:                                sb.insert(0, waitInfo);
899:                            } else {
900:                                if (!sb.substring(0, overflowTag.length())
901:                                        .equals(overflowTag)) {
902:                                    sb.insert(0, overflowTag);
903:                                }
904:                            }
905:                            return sb;
906:                        }
907:                        ownerSet.remove(locker); // is this necessary?
908:                    }
909:                }
910:
911:                return null;
912:            }
913:
914:            /**
915:             * This is just a struct to hold a multi-value return.
916:             */
917:            static class LockAttemptResult {
918:                boolean success;
919:                Lock useLock;
920:                LockGrantType lockGrant;
921:
922:                LockAttemptResult(Lock useLock, LockGrantType lockGrant,
923:                        boolean success) {
924:
925:                    this.useLock = useLock;
926:                    this.lockGrant = lockGrant;
927:                    this.success = success;
928:                }
929:            }
930:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.