Source Code Cross Referenced for SecondaryDatabase.java in  » JMX » je » com » sleepycat » je » 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 
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: SecondaryDatabase.java,v 1.52.2.3 2008/01/07 15:14:08 cwl Exp $
007:         */
008:
009:        package com.sleepycat.je;
010:
011:        import java.util.Collections;
012:        import java.util.HashSet;
013:        import java.util.Iterator;
014:        import java.util.Set;
015:        import java.util.logging.Level;
016:        import java.util.logging.Logger;
017:
018:        import com.sleepycat.je.dbi.DatabaseImpl;
019:        import com.sleepycat.je.dbi.GetMode;
020:        import com.sleepycat.je.dbi.PutMode;
021:        import com.sleepycat.je.dbi.CursorImpl.SearchMode;
022:        import com.sleepycat.je.txn.Locker;
023:        import com.sleepycat.je.txn.LockerFactory;
024:        import com.sleepycat.je.utilint.DatabaseUtil;
025:
026:        /**
027:         * Javadoc for this public class is generated via
028:         * the doc templates in the doc_src directory.
029:         */
030:        public class SecondaryDatabase extends Database {
031:
032:            private Database primaryDb;
033:            private SecondaryConfig secondaryConfig;
034:            private SecondaryTrigger secondaryTrigger;
035:            private ForeignKeyTrigger foreignKeyTrigger;
036:
037:            /**
038:             * Creates a secondary database but does not open or fully initialize it.
039:             */
040:            SecondaryDatabase(Environment env, SecondaryConfig secConfig,
041:                    Database primaryDatabase) throws DatabaseException {
042:
043:                super (env);
044:                DatabaseUtil.checkForNullParam(primaryDatabase,
045:                        "primaryDatabase");
046:                primaryDatabase.checkRequiredDbState(OPEN,
047:                        "Can't use as primary:");
048:                if (primaryDatabase.configuration.getSortedDuplicates()) {
049:                    throw new IllegalArgumentException(
050:                            "Duplicates must not be allowed for a primary database: "
051:                                    + primaryDatabase.getDebugName());
052:                }
053:                if (env.getEnvironmentImpl() != primaryDatabase
054:                        .getEnvironment().getEnvironmentImpl()) {
055:                    throw new IllegalArgumentException(
056:                            "Primary and secondary databases must be in the same"
057:                                    + " environment");
058:                }
059:                if (secConfig.getKeyCreator() != null
060:                        && secConfig.getMultiKeyCreator() != null) {
061:                    throw new IllegalArgumentException(
062:                            "secConfig.getKeyCreator() and getMultiKeyCreator() may not"
063:                                    + " both be non-null");
064:                }
065:                if (!primaryDatabase.configuration.getReadOnly()
066:                        && secConfig.getKeyCreator() == null
067:                        && secConfig.getMultiKeyCreator() == null) {
068:                    throw new NullPointerException(
069:                            "secConfig and getKeyCreator()/getMultiKeyCreator()"
070:                                    + " may be null only if the primary database is read-only");
071:                }
072:                if (secConfig.getForeignKeyNullifier() != null
073:                        && secConfig.getForeignMultiKeyNullifier() != null) {
074:                    throw new IllegalArgumentException(
075:                            "secConfig.getForeignKeyNullifier() and"
076:                                    + " getForeignMultiKeyNullifier() may not both be non-null");
077:                }
078:                if (secConfig.getForeignKeyDeleteAction() == ForeignKeyDeleteAction.NULLIFY
079:                        && secConfig.getForeignKeyNullifier() == null
080:                        && secConfig.getForeignMultiKeyNullifier() == null) {
081:                    throw new NullPointerException(
082:                            "ForeignKeyNullifier or ForeignMultiKeyNullifier must be"
083:                                    + " non-null when ForeignKeyDeleteAction is NULLIFY");
084:                }
085:                if (secConfig.getForeignKeyNullifier() != null
086:                        && secConfig.getMultiKeyCreator() != null) {
087:                    throw new IllegalArgumentException(
088:                            "ForeignKeyNullifier may not be used with"
089:                                    + " SecondaryMultiKeyCreator -- use"
090:                                    + " ForeignMultiKeyNullifier instead");
091:                }
092:                if (secConfig.getForeignKeyDatabase() != null) {
093:                    Database foreignDb = secConfig.getForeignKeyDatabase();
094:                    if (foreignDb.getDatabaseImpl().getSortedDuplicates()) {
095:                        throw new IllegalArgumentException(
096:                                "Duplicates must not be allowed for a foreign key "
097:                                        + " database: "
098:                                        + foreignDb.getDebugName());
099:                    }
100:                }
101:                primaryDb = primaryDatabase;
102:                secondaryTrigger = new SecondaryTrigger(this );
103:                if (secConfig.getForeignKeyDatabase() != null) {
104:                    foreignKeyTrigger = new ForeignKeyTrigger(this );
105:                }
106:            }
107:
108:            /**
109:             * Create a database, called by Environment
110:             */
111:            void initNew(Environment env, Locker locker, String databaseName,
112:                    DatabaseConfig dbConfig) throws DatabaseException {
113:
114:                super .initNew(env, locker, databaseName, dbConfig);
115:                init(locker);
116:            }
117:
118:            /**
119:             * Open a database, called by Environment
120:             */
121:            void initExisting(Environment env, Locker locker,
122:                    DatabaseImpl database, DatabaseConfig dbConfig)
123:                    throws DatabaseException {
124:
125:                /* Disallow one secondary associated with two different primaries. */
126:                Database otherPriDb = database.findPrimaryDatabase();
127:                if (otherPriDb != null
128:                        && otherPriDb.getDatabaseImpl() != primaryDb
129:                                .getDatabaseImpl()) {
130:                    throw new IllegalArgumentException(
131:                            "Secondary is already associated with a different primary: "
132:                                    + otherPriDb.getDebugName());
133:                }
134:
135:                super .initExisting(env, locker, database, dbConfig);
136:                init(locker);
137:            }
138:
139:            /**
140:             * Adds secondary to primary's list, and populates the secondary if needed.
141:             */
142:            private void init(Locker locker) throws DatabaseException {
143:
144:                trace(Level.FINEST, "SecondaryDatabase open");
145:
146:                secondaryConfig = (SecondaryConfig) configuration;
147:
148:                /* Insert foreign key triggers at the front of the list and append
149:                 * secondary triggers at the end, so that ForeignKeyDeleteAction.ABORT
150:                 * is applied before deleting the secondary keys. */
151:
152:                primaryDb.addTrigger(secondaryTrigger, false);
153:
154:                Database foreignDb = secondaryConfig.getForeignKeyDatabase();
155:                if (foreignDb != null) {
156:                    foreignDb.addTrigger(foreignKeyTrigger, true);
157:                }
158:
159:                /* Populate secondary if requested and secondary is empty. */
160:                if (secondaryConfig.getAllowPopulate()) {
161:                    Cursor secCursor = null;
162:                    Cursor priCursor = null;
163:                    try {
164:                        secCursor = new Cursor(this , locker, null);
165:                        DatabaseEntry key = new DatabaseEntry();
166:                        DatabaseEntry data = new DatabaseEntry();
167:                        OperationStatus status = secCursor.position(key, data,
168:                                LockMode.DEFAULT, true);
169:                        if (status == OperationStatus.NOTFOUND) {
170:                            /* Is empty, so populate */
171:                            priCursor = new Cursor(primaryDb, locker, null);
172:                            status = priCursor.position(key, data,
173:                                    LockMode.DEFAULT, true);
174:                            while (status == OperationStatus.SUCCESS) {
175:                                updateSecondary(locker, secCursor, key, null,
176:                                        data);
177:                                status = priCursor.retrieveNext(key, data,
178:                                        LockMode.DEFAULT, GetMode.NEXT);
179:                            }
180:                        }
181:                    } finally {
182:                        if (secCursor != null) {
183:                            secCursor.close();
184:                        }
185:                        if (priCursor != null) {
186:                            priCursor.close();
187:                        }
188:                    }
189:                }
190:            }
191:
192:            /**
193:             * Javadoc for this public method is generated via
194:             * the doc templates in the doc_src directory.
195:             */
196:            public synchronized void close() throws DatabaseException {
197:
198:                if (primaryDb != null && secondaryTrigger != null) {
199:                    primaryDb.removeTrigger(secondaryTrigger);
200:                }
201:                Database foreignDb = secondaryConfig.getForeignKeyDatabase();
202:                if (foreignDb != null && foreignKeyTrigger != null) {
203:                    foreignDb.removeTrigger(foreignKeyTrigger);
204:                }
205:                super .close();
206:            }
207:
208:            /**
209:             * Should be called by the secondaryTrigger while holding a write lock on
210:             * the trigger list.
211:             */
212:            void clearPrimary() {
213:                primaryDb = null;
214:                secondaryTrigger = null;
215:            }
216:
217:            /**
218:             * Should be called by the foreignKeyTrigger while holding a write lock on
219:             * the trigger list.
220:             */
221:            void clearForeignKeyTrigger() {
222:                foreignKeyTrigger = null;
223:            }
224:
225:            /**
226:             * Javadoc for this public method is generated via
227:             * the doc templates in the doc_src directory.
228:             */
229:            public Database getPrimaryDatabase() throws DatabaseException {
230:
231:                return primaryDb;
232:            }
233:
234:            /**
235:             * Javadoc for this public method is generated via
236:             * the doc templates in the doc_src directory.
237:             */
238:            public SecondaryConfig getSecondaryConfig()
239:                    throws DatabaseException {
240:
241:                return (SecondaryConfig) getConfig();
242:            }
243:
244:            /**
245:             * Returns the secondary config without cloning, for internal use.
246:             */
247:            public SecondaryConfig getPrivateSecondaryConfig() {
248:                return secondaryConfig;
249:            }
250:
251:            /**
252:             * Javadoc for this public method is generated via
253:             * the doc templates in the doc_src directory.
254:             */
255:            public SecondaryCursor openSecondaryCursor(Transaction txn,
256:                    CursorConfig cursorConfig) throws DatabaseException {
257:
258:                return (SecondaryCursor) openCursor(txn, cursorConfig);
259:            }
260:
261:            /**
262:             * Overrides Database method.
263:             */
264:            Cursor newDbcInstance(Transaction txn, CursorConfig cursorConfig)
265:                    throws DatabaseException {
266:
267:                return new SecondaryCursor(this , txn, cursorConfig);
268:            }
269:
270:            /**
271:             * Javadoc for this public method is generated via
272:             * the doc templates in the doc_src directory.
273:             */
274:            public OperationStatus delete(Transaction txn, DatabaseEntry key)
275:                    throws DatabaseException {
276:
277:                checkEnv();
278:                DatabaseUtil.checkForNullDbt(key, "key", true);
279:                checkRequiredDbState(OPEN,
280:                        "Can't call SecondaryDatabase.delete:");
281:                trace(Level.FINEST, "SecondaryDatabase.delete", txn, key, null,
282:                        null);
283:
284:                Locker locker = null;
285:                Cursor cursor = null;
286:
287:                OperationStatus commitStatus = OperationStatus.NOTFOUND;
288:                try {
289:                    locker = LockerFactory.getWritableLocker(envHandle, txn,
290:                            isTransactional());
291:
292:                    /* Read the primary key (the data of a secondary). */
293:                    cursor = new Cursor(this , locker, null);
294:                    DatabaseEntry pKey = new DatabaseEntry();
295:                    OperationStatus searchStatus = cursor.search(key, pKey,
296:                            LockMode.RMW, SearchMode.SET);
297:
298:                    /*
299:                     * For each duplicate secondary key, delete the primary record and
300:                     * all its associated secondary records, including the one
301:                     * referenced by this secondary cursor.
302:                     */
303:                    while (searchStatus == OperationStatus.SUCCESS) {
304:                        commitStatus = primaryDb.deleteInternal(locker, pKey,
305:                                null);
306:                        if (commitStatus != OperationStatus.SUCCESS) {
307:                            throw secondaryCorruptException();
308:                        }
309:                        searchStatus = cursor.retrieveNext(key, pKey,
310:                                LockMode.RMW, GetMode.NEXT_DUP);
311:                    }
312:                    return commitStatus;
313:                } catch (Error E) {
314:                    DbInternal.envGetEnvironmentImpl(envHandle).invalidate(E);
315:                    throw E;
316:                } finally {
317:                    if (cursor != null) {
318:                        cursor.close();
319:                    }
320:                    if (locker != null) {
321:                        locker.operationEnd(commitStatus);
322:                    }
323:                }
324:            }
325:
326:            /**
327:             * Javadoc for this public method is generated via
328:             * the doc templates in the doc_src directory.
329:             */
330:            public OperationStatus get(Transaction txn, DatabaseEntry key,
331:                    DatabaseEntry data, LockMode lockMode)
332:                    throws DatabaseException {
333:
334:                return get(txn, key, new DatabaseEntry(), data, lockMode);
335:            }
336:
337:            /**
338:             * Javadoc for this public method is generated via
339:             * the doc templates in the doc_src directory.
340:             */
341:            public OperationStatus get(Transaction txn, DatabaseEntry key,
342:                    DatabaseEntry pKey, DatabaseEntry data, LockMode lockMode)
343:                    throws DatabaseException {
344:
345:                checkEnv();
346:                DatabaseUtil.checkForNullDbt(key, "key", true);
347:                DatabaseUtil.checkForNullDbt(pKey, "pKey", false);
348:                DatabaseUtil.checkForNullDbt(data, "data", false);
349:                checkRequiredDbState(OPEN, "Can't call SecondaryDatabase.get:");
350:                trace(Level.FINEST, "SecondaryDatabase.get", txn, key, null,
351:                        lockMode);
352:
353:                CursorConfig cursorConfig = CursorConfig.DEFAULT;
354:                if (lockMode == LockMode.READ_COMMITTED) {
355:                    cursorConfig = CursorConfig.READ_COMMITTED;
356:                    lockMode = null;
357:                }
358:
359:                SecondaryCursor cursor = null;
360:                try {
361:                    cursor = new SecondaryCursor(this , txn, cursorConfig);
362:                    return cursor.search(key, pKey, data, lockMode,
363:                            SearchMode.SET);
364:                } catch (Error E) {
365:                    DbInternal.envGetEnvironmentImpl(envHandle).invalidate(E);
366:                    throw E;
367:                } finally {
368:                    if (cursor != null) {
369:                        cursor.close();
370:                    }
371:                }
372:            }
373:
374:            /**
375:             * Javadoc for this public method is generated via
376:             * the doc templates in the doc_src directory.
377:             */
378:            public OperationStatus getSearchBoth(Transaction txn,
379:                    DatabaseEntry key, DatabaseEntry data, LockMode lockMode)
380:                    throws DatabaseException {
381:
382:                throw notAllowedException();
383:            }
384:
385:            /**
386:             * Javadoc for this public method is generated via
387:             * the doc templates in the doc_src directory.
388:             */
389:            public OperationStatus getSearchBoth(Transaction txn,
390:                    DatabaseEntry key, DatabaseEntry pKey, DatabaseEntry data,
391:                    LockMode lockMode) throws DatabaseException {
392:
393:                checkEnv();
394:                DatabaseUtil.checkForNullDbt(key, "key", true);
395:                DatabaseUtil.checkForNullDbt(pKey, "pKey", true);
396:                DatabaseUtil.checkForNullDbt(data, "data", false);
397:                checkRequiredDbState(OPEN,
398:                        "Can't call SecondaryDatabase.getSearchBoth:");
399:                trace(Level.FINEST, "SecondaryDatabase.getSearchBoth", txn,
400:                        key, data, lockMode);
401:
402:                CursorConfig cursorConfig = CursorConfig.DEFAULT;
403:                if (lockMode == LockMode.READ_COMMITTED) {
404:                    cursorConfig = CursorConfig.READ_COMMITTED;
405:                    lockMode = null;
406:                }
407:
408:                SecondaryCursor cursor = null;
409:                try {
410:                    cursor = new SecondaryCursor(this , txn, cursorConfig);
411:                    return cursor.search(key, pKey, data, lockMode,
412:                            SearchMode.BOTH);
413:                } catch (Error E) {
414:                    DbInternal.envGetEnvironmentImpl(envHandle).invalidate(E);
415:                    throw E;
416:                } finally {
417:                    if (cursor != null) {
418:                        cursor.close();
419:                    }
420:                }
421:            }
422:
423:            /**
424:             * Javadoc for this public method is generated via
425:             * the doc templates in the doc_src directory.
426:             */
427:            public OperationStatus put(Transaction txn, DatabaseEntry key,
428:                    DatabaseEntry data) throws DatabaseException {
429:
430:                throw notAllowedException();
431:            }
432:
433:            /**
434:             * Javadoc for this public method is generated via
435:             * the doc templates in the doc_src directory.
436:             */
437:            public OperationStatus putNoOverwrite(Transaction txn,
438:                    DatabaseEntry key, DatabaseEntry data)
439:                    throws DatabaseException {
440:
441:                throw notAllowedException();
442:            }
443:
444:            /**
445:             * Javadoc for this public method is generated via
446:             * the doc templates in the doc_src directory.
447:             */
448:            public OperationStatus putNoDupData(Transaction txn,
449:                    DatabaseEntry key, DatabaseEntry data)
450:                    throws DatabaseException {
451:
452:                throw notAllowedException();
453:            }
454:
455:            /**
456:             * Javadoc for this public method is generated via
457:             * the doc templates in the doc_src directory.
458:             */
459:            public JoinCursor join(Cursor[] cursors, JoinConfig config)
460:                    throws DatabaseException {
461:
462:                throw notAllowedException();
463:            }
464:
465:            /**
466:             * Javadoc for this public method is generated via
467:             * the doc templates in the doc_src directory.
468:             * @deprecated
469:             */
470:            public int truncate(Transaction txn, boolean countRecords)
471:                    throws DatabaseException {
472:
473:                throw notAllowedException();
474:            }
475:
476:            /**
477:             * Updates a single secondary when a put() or delete() is performed on
478:             * the primary.
479:             *
480:             * @param locker the internal locker.
481:             *
482:             * @param cursor secondary cursor to use, or null if this method should
483:             * open and close a cursor if one is needed.
484:             *
485:             * @param priKey the primary key.
486:             *
487:             * @param oldData the primary data before the change, or null if the record
488:             * did not previously exist.
489:             *
490:             * @param newData the primary data after the change, or null if the record
491:             * has been deleted.
492:             */
493:            void updateSecondary(Locker locker, Cursor cursor,
494:                    DatabaseEntry priKey, DatabaseEntry oldData,
495:                    DatabaseEntry newData) throws DatabaseException {
496:
497:                /*
498:                 * If we're updating the primary and the secondary key cannot be
499:                 * changed, optimize for that case by doing nothing.
500:                 */
501:                if (secondaryConfig.getImmutableSecondaryKey()
502:                        && oldData != null && newData != null) {
503:                    return;
504:                }
505:
506:                SecondaryKeyCreator keyCreator = secondaryConfig
507:                        .getKeyCreator();
508:                if (keyCreator != null) {
509:                    /* Each primary record may have a single secondary key. */
510:                    assert secondaryConfig.getMultiKeyCreator() == null;
511:
512:                    /* Get old and new secondary keys. */
513:                    DatabaseEntry oldSecKey = null;
514:                    if (oldData != null) {
515:                        oldSecKey = new DatabaseEntry();
516:                        if (!keyCreator.createSecondaryKey(this , priKey,
517:                                oldData, oldSecKey)) {
518:                            oldSecKey = null;
519:                        }
520:                    }
521:                    DatabaseEntry newSecKey = null;
522:                    if (newData != null) {
523:                        newSecKey = new DatabaseEntry();
524:                        if (!keyCreator.createSecondaryKey(this , priKey,
525:                                newData, newSecKey)) {
526:                            newSecKey = null;
527:                        }
528:                    }
529:
530:                    /* Update secondary if old and new keys are unequal. */
531:                    if ((oldSecKey != null && !oldSecKey.equals(newSecKey))
532:                            || (newSecKey != null && !newSecKey
533:                                    .equals(oldSecKey))) {
534:
535:                        boolean localCursor = (cursor == null);
536:                        if (localCursor) {
537:                            cursor = new Cursor(this , locker, null);
538:                        }
539:                        try {
540:                            /* Delete the old key. */
541:                            if (oldSecKey != null) {
542:                                deleteKey(cursor, priKey, oldSecKey);
543:                            }
544:                            /* Insert the new key. */
545:                            if (newSecKey != null) {
546:                                insertKey(locker, cursor, priKey, newSecKey);
547:                            }
548:                        } finally {
549:                            if (localCursor && cursor != null) {
550:                                cursor.close();
551:                            }
552:                        }
553:                    }
554:                } else {
555:                    /* Each primary record may have multiple secondary keys. */
556:                    SecondaryMultiKeyCreator multiKeyCreator = secondaryConfig
557:                            .getMultiKeyCreator();
558:                    assert multiKeyCreator != null;
559:
560:                    /* Get old and new secondary keys. */
561:                    Set oldKeys = Collections.EMPTY_SET;
562:                    Set newKeys = Collections.EMPTY_SET;
563:                    if (oldData != null) {
564:                        oldKeys = new HashSet();
565:                        multiKeyCreator.createSecondaryKeys(this , priKey,
566:                                oldData, oldKeys);
567:                    }
568:                    if (newData != null) {
569:                        newKeys = new HashSet();
570:                        multiKeyCreator.createSecondaryKeys(this , priKey,
571:                                newData, newKeys);
572:                    }
573:
574:                    /* Update the secondary if there is a difference. */
575:                    if (!oldKeys.equals(newKeys)) {
576:
577:                        boolean localCursor = (cursor == null);
578:                        if (localCursor) {
579:                            cursor = new Cursor(this , locker, null);
580:                        }
581:                        try {
582:                            /* Delete old keys that are no longer present. */
583:                            Set oldKeysCopy = oldKeys;
584:                            if (oldKeys != Collections.EMPTY_SET) {
585:                                oldKeysCopy = new HashSet(oldKeys);
586:                                oldKeys.removeAll(newKeys);
587:                                for (Iterator i = oldKeys.iterator(); i
588:                                        .hasNext();) {
589:                                    DatabaseEntry oldKey = (DatabaseEntry) i
590:                                            .next();
591:                                    deleteKey(cursor, priKey, oldKey);
592:                                }
593:                            }
594:                            /* Insert new keys that were not present before. */
595:                            if (newKeys != Collections.EMPTY_SET) {
596:                                newKeys.removeAll(oldKeysCopy);
597:                                for (Iterator i = newKeys.iterator(); i
598:                                        .hasNext();) {
599:                                    DatabaseEntry newKey = (DatabaseEntry) i
600:                                            .next();
601:                                    insertKey(locker, cursor, priKey, newKey);
602:                                }
603:                            }
604:                        } finally {
605:                            if (localCursor && cursor != null) {
606:                                cursor.close();
607:                            }
608:                        }
609:                    }
610:                }
611:            }
612:
613:            /**
614:             * Deletes an old secondary key.
615:             */
616:            private void deleteKey(Cursor cursor, DatabaseEntry priKey,
617:                    DatabaseEntry oldSecKey) throws DatabaseException {
618:
619:                OperationStatus status = cursor.search(oldSecKey, priKey,
620:                        LockMode.RMW, SearchMode.BOTH);
621:                if (status == OperationStatus.SUCCESS) {
622:                    cursor.deleteInternal();
623:                } else {
624:                    throw new DatabaseException("Secondary " + getDebugName()
625:                            + " is corrupt: the primary record contains a key"
626:                            + " that is not present in the secondary");
627:                }
628:            }
629:
630:            /**
631:             * Inserts a new secondary key.
632:             */
633:            private void insertKey(Locker locker, Cursor cursor,
634:                    DatabaseEntry priKey, DatabaseEntry newSecKey)
635:                    throws DatabaseException {
636:
637:                /* Check for the existence of a foreign key. */
638:                Database foreignDb = secondaryConfig.getForeignKeyDatabase();
639:                if (foreignDb != null) {
640:                    Cursor foreignCursor = null;
641:                    try {
642:                        foreignCursor = new Cursor(foreignDb, locker, null);
643:                        DatabaseEntry tmpData = new DatabaseEntry();
644:                        OperationStatus status = foreignCursor.search(
645:                                newSecKey, tmpData, LockMode.DEFAULT,
646:                                SearchMode.SET);
647:                        if (status != OperationStatus.SUCCESS) {
648:                            throw new DatabaseException("Secondary "
649:                                    + getDebugName()
650:                                    + " foreign key not allowed: it is not"
651:                                    + " present in the foreign database "
652:                                    + foreignDb.getDebugName());
653:                        }
654:                    } finally {
655:                        if (foreignCursor != null) {
656:                            foreignCursor.close();
657:                        }
658:                    }
659:                }
660:
661:                /* Insert the new key. */
662:                OperationStatus status;
663:                if (configuration.getSortedDuplicates()) {
664:                    status = cursor.putInternal(newSecKey, priKey,
665:                            PutMode.NODUP);
666:                } else {
667:                    status = cursor.putInternal(newSecKey, priKey,
668:                            PutMode.NOOVERWRITE);
669:                }
670:                if (status != OperationStatus.SUCCESS) {
671:                    throw new DatabaseException(
672:                            "Could not insert secondary key in "
673:                                    + getDebugName() + ' ' + status);
674:                }
675:            }
676:
677:            /**
678:             * Called by the ForeignKeyTrigger when a record in the foreign database is
679:             * deleted.
680:             *
681:             * @param secKey is the primary key of the foreign database, which is the
682:             * secondary key (ordinary key) of this secondary database.
683:             */
684:            void onForeignKeyDelete(Locker locker, DatabaseEntry secKey)
685:                    throws DatabaseException {
686:
687:                ForeignKeyDeleteAction deleteAction = secondaryConfig
688:                        .getForeignKeyDeleteAction();
689:
690:                /* Use RMW if we're going to be deleting the secondary records. */
691:                LockMode lockMode = (deleteAction == ForeignKeyDeleteAction.ABORT) ? LockMode.DEFAULT
692:                        : LockMode.RMW;
693:
694:                /*
695:                 * Use the deleted foreign primary key to read the data of this
696:                 * database, which is the associated primary's key.
697:                 */
698:                DatabaseEntry priKey = new DatabaseEntry();
699:                Cursor cursor = null;
700:                OperationStatus status;
701:                try {
702:                    cursor = new Cursor(this , locker, null);
703:                    status = cursor.search(secKey, priKey, lockMode,
704:                            SearchMode.SET);
705:                    while (status == OperationStatus.SUCCESS) {
706:
707:                        if (deleteAction == ForeignKeyDeleteAction.ABORT) {
708:
709:                            /*
710:                             * ABORT - throw an exception to cause the user to abort
711:                             * the transaction.
712:                             */
713:                            throw new DatabaseException(
714:                                    "Secondary "
715:                                            + getDebugName()
716:                                            + " refers to a foreign key that has been deleted"
717:                                            + " (ForeignKeyDeleteAction.ABORT)");
718:
719:                        } else if (deleteAction == ForeignKeyDeleteAction.CASCADE) {
720:
721:                            /*
722:                             * CASCADE - delete the associated primary record.
723:                             */
724:                            Cursor priCursor = null;
725:                            try {
726:                                DatabaseEntry data = new DatabaseEntry();
727:                                priCursor = new Cursor(primaryDb, locker, null);
728:                                status = priCursor.search(priKey, data,
729:                                        LockMode.RMW, SearchMode.SET);
730:                                if (status == OperationStatus.SUCCESS) {
731:                                    priCursor.delete();
732:                                } else {
733:                                    throw secondaryCorruptException();
734:                                }
735:                            } finally {
736:                                if (priCursor != null) {
737:                                    priCursor.close();
738:                                }
739:                            }
740:
741:                        } else if (deleteAction == ForeignKeyDeleteAction.NULLIFY) {
742:
743:                            /*
744:                             * NULLIFY - set the secondary key to null in the
745:                             * associated primary record.
746:                             */
747:                            Cursor priCursor = null;
748:                            try {
749:                                DatabaseEntry data = new DatabaseEntry();
750:                                priCursor = new Cursor(primaryDb, locker, null);
751:                                status = priCursor.search(priKey, data,
752:                                        LockMode.RMW, SearchMode.SET);
753:                                if (status == OperationStatus.SUCCESS) {
754:                                    ForeignMultiKeyNullifier multiNullifier = secondaryConfig
755:                                            .getForeignMultiKeyNullifier();
756:                                    if (multiNullifier != null) {
757:                                        if (multiNullifier.nullifyForeignKey(
758:                                                this , priKey, data, secKey)) {
759:                                            priCursor.putCurrent(data);
760:                                        }
761:                                    } else {
762:                                        ForeignKeyNullifier nullifier = secondaryConfig
763:                                                .getForeignKeyNullifier();
764:                                        if (nullifier.nullifyForeignKey(this ,
765:                                                data)) {
766:                                            priCursor.putCurrent(data);
767:                                        }
768:                                    }
769:                                } else {
770:                                    throw secondaryCorruptException();
771:                                }
772:                            } finally {
773:                                if (priCursor != null) {
774:                                    priCursor.close();
775:                                }
776:                            }
777:                        } else {
778:                            /* Should never occur. */
779:                            throw new IllegalStateException();
780:                        }
781:
782:                        status = cursor.retrieveNext(secKey, priKey,
783:                                LockMode.DEFAULT, GetMode.NEXT_DUP);
784:                    }
785:                } finally {
786:                    if (cursor != null) {
787:                        cursor.close();
788:                    }
789:                }
790:            }
791:
792:            DatabaseException secondaryCorruptException()
793:                    throws DatabaseException {
794:
795:                throw new DatabaseException("Secondary " + getDebugName()
796:                        + " is corrupt: it refers"
797:                        + " to a missing key in the primary database");
798:            }
799:
800:            static UnsupportedOperationException notAllowedException() {
801:
802:                throw new UnsupportedOperationException(
803:                        "Operation not allowed on a secondary");
804:            }
805:
806:            /**
807:             * Send trace messages to the java.util.logger. Don't rely on the
808:             * logger alone to conditionalize whether we send this message,
809:             * we don't even want to construct the message if the level is
810:             * not enabled.
811:             */
812:            void trace(Level level, String methodName) throws DatabaseException {
813:
814:                Logger logger = envHandle.getEnvironmentImpl().getLogger();
815:                if (logger.isLoggable(level)) {
816:                    StringBuffer sb = new StringBuffer();
817:                    sb.append(methodName);
818:                    sb.append(" name=").append(getDebugName());
819:                    sb.append(" primary=").append(primaryDb.getDebugName());
820:
821:                    logger.log(level, sb.toString());
822:                }
823:            }
824:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.