private void createSecDB(SecondaryConfig secConfig) { TupleBinding<DataRow> tBinder = new GenericTupleBinder(tMap); SecondaryKeyCreator secKeyCreator = new GenericSecKeyCreator(tBinder, secIndexPos, tMap); // Get a secondary object and set the key creator on it. secConfig.setKeyCreator(secKeyCreator); String secDbName = tableName + "-secDB"; secDB = myDbEnvironment.openSecondaryDatabase(null, secDbName, myDB, secConfig); }
private static SecondaryConfig set2ndDbConfig() { SecondaryConfig sndDatabaseConfig = null; if (sndDatabaseConfig == null) { sndDatabaseConfig = new SecondaryConfig(); sndDatabaseConfig.setAllowCreate(true); sndDatabaseConfig.setTemporary(false); sndDatabaseConfig.setDeferredWrite(true); sndDatabaseConfig.setSortedDuplicates(true); sndDatabaseConfig.setKeyCreator(createKey()); } return sndDatabaseConfig; }
private SecondaryConfig getSecondaryConfig( String secName, EntityMetadata entityMeta, String keyClassName, SecondaryKeyMetadata secKeyMeta) { SecondaryConfig config = secConfigMap.get(secName); if (config == null) { /* Set common properties to match the primary DB. */ DatabaseConfig priConfig = getPrimaryConfig(entityMeta); config = new SecondaryConfig(); config.setTransactional(priConfig.getTransactional()); config.setAllowCreate(!priConfig.getReadOnly()); config.setReadOnly(priConfig.getReadOnly()); DbCompat.setDeferredWrite(config, DbCompat.getDeferredWrite(priConfig)); /* Set secondary properties based on metadata. */ config.setAllowPopulate(true); Relationship rel = secKeyMeta.getRelationship(); config.setSortedDuplicates( rel == Relationship.MANY_TO_ONE || rel == Relationship.MANY_TO_MANY); setBtreeComparator(config, secKeyMeta.getClassName()); PersistKeyCreator keyCreator = new PersistKeyCreator(catalog, entityMeta, keyClassName, secKeyMeta); if (rel == Relationship.ONE_TO_MANY || rel == Relationship.MANY_TO_MANY) { config.setMultiKeyCreator(keyCreator); } else { config.setKeyCreator(keyCreator); } DeleteAction deleteAction = secKeyMeta.getDeleteAction(); if (deleteAction != null) { ForeignKeyDeleteAction baseDeleteAction; switch (deleteAction) { case ABORT: baseDeleteAction = ForeignKeyDeleteAction.ABORT; break; case CASCADE: baseDeleteAction = ForeignKeyDeleteAction.CASCADE; break; case NULLIFY: baseDeleteAction = ForeignKeyDeleteAction.NULLIFY; break; default: throw new IllegalStateException(deleteAction.toString()); } config.setForeignKeyDeleteAction(baseDeleteAction); if (deleteAction == DeleteAction.NULLIFY) { config.setForeignMultiKeyNullifier(keyCreator); } } secConfigMap.put(secName, config); } return config; }
private SecondaryDatabase openSecondary( Database priDb, boolean allowDuplicates, String dbName, boolean allowPopulate, boolean readOnly) throws DatabaseException { List secListBefore = priDb.getSecondaryDatabases(); SecondaryConfig dbConfig = new SecondaryConfig(); dbConfig.setTransactional(isTransactional); dbConfig.setAllowCreate(true); dbConfig.setSortedDuplicates(allowDuplicates); dbConfig.setReadOnly(readOnly); dbConfig.setAllowPopulate(allowPopulate); if (!readOnly) { if (useMultiKey) { dbConfig.setMultiKeyCreator(new SimpleMultiKeyCreator(new MyKeyCreator())); } else { dbConfig.setKeyCreator(new MyKeyCreator()); } } Transaction txn = txnBegin(); SecondaryDatabase secDb; try { secDb = env.openSecondaryDatabase(txn, dbName, priDb, dbConfig); } finally { txnCommit(txn); } assertNotNull(secDb); /* Check configuration. */ assertSame(priDb, secDb.getPrimaryDatabase()); SecondaryConfig config2 = secDb.getSecondaryConfig(); assertEquals(allowPopulate, config2.getAllowPopulate()); assertEquals(dbConfig.getKeyCreator(), config2.getKeyCreator()); /* Make sure the new secondary is added to the primary's list. */ List secListAfter = priDb.getSecondaryDatabases(); assertTrue(secListAfter.remove(secDb)); assertEquals(secListBefore, secListAfter); return secDb; }
/** @deprecated use of Database.truncate */ public void testOperationsNotAllowed() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); Transaction txn = txnBegin(); /* Open secondary without a key creator. */ try { env.openSecondaryDatabase(txn, "xxx", priDb, null); fail(); } catch (NullPointerException expected) { } try { env.openSecondaryDatabase(txn, "xxx", priDb, new SecondaryConfig()); fail(); } catch (NullPointerException expected) { } /* Open secondary with both single and multi key creators. */ SecondaryConfig config = new SecondaryConfig(); config.setKeyCreator(new MyKeyCreator()); config.setMultiKeyCreator(new SimpleMultiKeyCreator(new MyKeyCreator())); try { env.openSecondaryDatabase(txn, "xxx", priDb, config); fail(); } catch (IllegalArgumentException expected) { } /* Database operations. */ DatabaseEntry key = entry(1); DatabaseEntry data = entry(2); try { secDb.getSearchBoth(txn, key, data, LockMode.DEFAULT); fail(); } catch (UnsupportedOperationException expected) { } try { secDb.put(txn, key, data); fail(); } catch (UnsupportedOperationException expected) { } try { secDb.putNoOverwrite(txn, key, data); fail(); } catch (UnsupportedOperationException expected) { } try { secDb.putNoDupData(txn, key, data); fail(); } catch (UnsupportedOperationException expected) { } try { secDb.truncate(txn, true); fail(); } catch (UnsupportedOperationException expected) { } try { secDb.join(new Cursor[0], null); fail(); } catch (UnsupportedOperationException expected) { } /* Cursor operations. */ txnCommit(txn); txn = txnBeginCursor(); SecondaryCursor cursor = null; try { cursor = secDb.openSecondaryCursor(txn, null); try { cursor.getSearchBoth(key, data, LockMode.DEFAULT); fail(); } catch (UnsupportedOperationException expected) { } try { cursor.getSearchBothRange(key, data, LockMode.DEFAULT); fail(); } catch (UnsupportedOperationException expected) { } try { cursor.putCurrent(data); fail(); } catch (UnsupportedOperationException expected) { } try { cursor.put(key, data); fail(); } catch (UnsupportedOperationException expected) { } try { cursor.putNoOverwrite(key, data); fail(); } catch (UnsupportedOperationException expected) { } try { cursor.putNoDupData(key, data); fail(); } catch (UnsupportedOperationException expected) { } } finally { if (cursor != null) { cursor.close(); } } txnCommit(txn); secDb.close(); priDb.close(); /* Primary with duplicates. */ priDb = openDatabase(true, "testDBWithDups", false); try { openSecondary(priDb, true, "testSecDB", false, false); fail(); } catch (IllegalArgumentException expected) { } priDb.close(); /* Single secondary with two primaries.*/ Database pri1 = openDatabase(false, "pri1", false); Database pri2 = openDatabase(false, "pri2", false); Database sec1 = openSecondary(pri1, false, "sec", false, false); try { openSecondary(pri2, false, "sec", false, false); fail(); } catch (IllegalArgumentException expected) { } sec1.close(); pri1.close(); pri2.close(); }
/** Insert or retrieve data. */ public void run() throws DatabaseException { /* Create a new, transactional database environment. */ EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setTransactional(true); envConfig.setAllowCreate(true); Environment exampleEnv = new Environment(envDir, envConfig); /* * Make a database within that environment. Because this will be used * as a primary database, it must not allow duplicates. The primary key * of a primary database must be unique. */ Transaction txn = exampleEnv.beginTransaction(null, null); DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setTransactional(true); dbConfig.setAllowCreate(true); Database exampleDb = exampleEnv.openDatabase(txn, "bindingsDb", dbConfig); /* * In our example, the database record is composed of an integer key * and and instance of the MyData class as data. * * A class catalog database is needed for storing class descriptions * for the serial binding used below. This avoids storing class * descriptions redundantly in each record. */ DatabaseConfig catalogConfig = new DatabaseConfig(); catalogConfig.setTransactional(true); catalogConfig.setAllowCreate(true); Database catalogDb = exampleEnv.openDatabase(txn, "catalogDb", catalogConfig); StoredClassCatalog catalog = new StoredClassCatalog(catalogDb); /* * Create a serial binding for MyData data objects. Serial * bindings can be used to store any Serializable object. */ EntryBinding<MyData> dataBinding = new SerialBinding<MyData>(catalog, MyData.class); /* * Further below we'll use a tuple binding (IntegerBinding * specifically) for integer keys. Tuples, unlike serialized * Java objects, have a well defined sort order. */ /* * Define a String tuple binding for a secondary key. The * secondary key is the msg field of the MyData object. */ EntryBinding<String> secKeyBinding = TupleBinding.getPrimitiveBinding(String.class); /* * Open a secondary database to allow accessing the primary * database by the secondary key value. */ SecondaryConfig secConfig = new SecondaryConfig(); secConfig.setTransactional(true); secConfig.setAllowCreate(true); secConfig.setSortedDuplicates(true); secConfig.setKeyCreator(new MyKeyCreator(secKeyBinding, dataBinding)); SecondaryDatabase exampleSecDb = exampleEnv.openSecondaryDatabase(txn, "bindingsSecDb", exampleDb, secConfig); txn.commit(); /* DatabaseEntry represents the key and data of each record. */ DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry dataEntry = new DatabaseEntry(); if (doInsert) { /* * Put some data in. Note that the primary database is always used * to add data. Adding or changing data in the secondary database * is not allowed; however, deleting through the secondary database * is allowed. */ for (int i = offset; i < numRecords + offset; i++) { txn = exampleEnv.beginTransaction(null, null); StringBuffer stars = new StringBuffer(); for (int j = 0; j < i; j++) { stars.append('*'); } MyData data = new MyData(i, stars.toString()); IntegerBinding.intToEntry(i, keyEntry); dataBinding.objectToEntry(data, dataEntry); OperationStatus status = exampleDb.put(txn, keyEntry, dataEntry); /* * Note that put will throw a DatabaseException when error * conditions are found such as deadlock. However, the status * return conveys a variety of information. For example, the * put might succeed, or it might not succeed if the record * exists and duplicates were not */ if (status != OperationStatus.SUCCESS) { throw new RuntimeException("Data insertion got status " + status); } txn.commit(); } } else { /* * Retrieve the data by secondary key by opening a cursor on the * secondary database. The key parameter for a secondary cursor is * always the secondary key, but the data parameter is always the * data of the primary database. You can cast the cursor to a * SecondaryCursor and use additional method signatures for * retrieving the primary key also. Or you can call * openSecondaryCursor() to avoid casting. */ txn = exampleEnv.beginTransaction(null, null); Cursor cursor = exampleSecDb.openCursor(txn, null); while (cursor.getNext(keyEntry, dataEntry, LockMode.DEFAULT) == OperationStatus.SUCCESS) { String key = secKeyBinding.entryToObject(keyEntry); MyData data = dataBinding.entryToObject(dataEntry); System.out.println("key=" + key + " data=" + data); } cursor.close(); txn.commit(); } /* * Always close secondary databases before closing their associated * primary database. */ catalogDb.close(); exampleSecDb.close(); exampleDb.close(); exampleEnv.close(); }