public BDBCreator(String tableName, ArrayList<Integer> keyPositions, int secondaryIndex) { /* Creates and loads a BDB table with a secondary index on the column defined by*/ this.tableName = tableName.toLowerCase(); this.keyPositions = keyPositions; this.secIndexPos = secondaryIndex; this.tMap = Main.indexTypeMaps.get(this.tableName); setEnvironment(); dbConfig = new DatabaseConfig(); dbConfig.setAllowCreate(true); myDB = myDbEnvironment.openDatabase(null, this.tableName, dbConfig); SecondaryConfig secConfig = new SecondaryConfig(); secConfig.setAllowCreate(true); secConfig.setSortedDuplicates(true); createSecDB(secConfig); setConfig(dbConfig, secConfig); loadData(); if (secDB != null) { secDB.close(); } if (myDB != null) { myDB.close(); } closeEnvironment(); }
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 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); }
public static void main(String[] args) { Environment myEnv; Database myDatabase; try { EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setAllowCreate(true); myEnv = new Environment(new File("/Users/broso/testDB"), envConfig); // Environment open omitted for clarity DatabaseConfig myDbConfig = new DatabaseConfig(); SecondaryConfig mySecConfig = new SecondaryConfig(); myDbConfig.setAllowCreate(true); mySecConfig.setAllowCreate(true); // Duplicates are frequently required for secondary databases. mySecConfig.setSortedDuplicates(true); // Open the primary String dbName = "myPrimaryDatabase"; Database myDb = myEnv.openDatabase(null, dbName, myDbConfig); // Open the secondary. // Key creators are described in the next section. // AKeyCreator akc = new AKeyCreator(); // Get a secondary object and set the key creator on it. // mySecConfig.setKeyCreator(keyCreator); // Perform the actual open String secDbName = "mySecondaryDatabase"; SecondaryDatabase mySecDb = myEnv.openSecondaryDatabase(null, secDbName, myDb, mySecConfig); } catch (DatabaseException de) { // Exception handling goes here } }
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; }
/** @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(); }
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; }
/** 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(); }
private void setConfig(DatabaseConfig mydbConfig, SecondaryConfig mySecDBConfig) { mydbConfig.setTransactional(false); mySecDBConfig.setTransactional(false); }
public synchronized void setSecondaryConfig( Class entityClass, String keyName, SecondaryConfig config) { checkOpen(); String entityClsName = entityClass.getName(); EntityMetadata entityMeta = checkEntityClass(entityClsName); SecondaryKeyMetadata secKeyMeta = checkSecKey(entityMeta, keyName); String keyClassName = getSecKeyClass(secKeyMeta); String secName = makeSecName(entityClass.getName(), keyName); if (secIndexMap.containsKey(secName)) { throw new IllegalStateException("Cannot set config after DB is open"); } SecondaryConfig dbConfig = getSecondaryConfig(secName, entityMeta, keyClassName, secKeyMeta); if (config.getSortedDuplicates() != dbConfig.getSortedDuplicates() || config.getBtreeComparator() != dbConfig.getBtreeComparator() || config.getDuplicateComparator() != null || config.getAllowPopulate() != dbConfig.getAllowPopulate() || config.getKeyCreator() != dbConfig.getKeyCreator() || config.getMultiKeyCreator() != dbConfig.getMultiKeyCreator() || config.getForeignKeyNullifier() != dbConfig.getForeignKeyNullifier() || config.getForeignMultiKeyNullifier() != dbConfig.getForeignMultiKeyNullifier() || config.getForeignKeyDeleteAction() != dbConfig.getForeignKeyDeleteAction() || config.getForeignKeyDatabase() != null) { throw new IllegalArgumentException( "One of these properties was illegally changed: " + " SortedDuplicates, BtreeComparator, DuplicateComparator," + " AllowPopulate, KeyCreator, MultiKeyCreator," + " ForeignKeyNullifer, ForeignMultiKeyNullifier," + " ForeignKeyDeleteAction, ForeignKeyDatabase"); } secConfigMap.put(secName, config); }
/** * Opens a secondary index with a given transaction and adds it to the secIndexMap. We assume that * the index is not already open. */ private <SK, PK, E1, E2 extends E1> SecondaryIndex<SK, PK, E2> openSecondaryIndex( Transaction txn, PrimaryIndex<PK, E1> primaryIndex, Class<E2> entityClass, EntityMetadata entityMeta, Class<SK> keyClass, String keyClassName, SecondaryKeyMetadata secKeyMeta, String secName, boolean doNotCreate, PrimaryOpenState priOpenState) throws DatabaseException { assert !secIndexMap.containsKey(secName); String dbName = storePrefix + secName; SecondaryConfig config = getSecondaryConfig(secName, entityMeta, keyClassName, secKeyMeta); Database priDb = primaryIndex.getDatabase(); DatabaseConfig priConfig = priDb.getConfig(); String relatedClsName = secKeyMeta.getRelatedEntity(); if (relatedClsName != null) { PrimaryIndex relatedIndex = getRelatedIndex(relatedClsName); config.setForeignKeyDatabase(relatedIndex.getDatabase()); } if (config.getTransactional() != priConfig.getTransactional() || DbCompat.getDeferredWrite(config) != DbCompat.getDeferredWrite(priConfig) || config.getReadOnly() != priConfig.getReadOnly()) { throw new IllegalArgumentException( "One of these properties was changed to be inconsistent" + " with the associated primary database: " + " Transactional, DeferredWrite, ReadOnly"); } PersistKeyBinding keyBinding = getKeyBinding(keyClassName); /* * doNotCreate is true when StoreConfig.getSecondaryBulkLoad is true * and we are opening a secondary as a side effect of opening a * primary, i.e., getSecondaryIndex is not being called. If * doNotCreate is true and the database does not exist, we silently * ignore the DatabaseNotFoundException and return null. When * getSecondaryIndex is subsequently called, the secondary database * will be created and populated from the primary -- a bulk load. */ SecondaryDatabase db; boolean saveAllowCreate = config.getAllowCreate(); try { if (doNotCreate) { config.setAllowCreate(false); } db = env.openSecondaryDatabase(txn, dbName, priDb, config); } catch (DatabaseNotFoundException e) { if (doNotCreate) { return null; } else { throw e; } } finally { if (doNotCreate) { config.setAllowCreate(saveAllowCreate); } } SecondaryIndex<SK, PK, E2> secIndex = new SecondaryIndex(db, null, primaryIndex, keyClass, keyBinding); /* Update index and database maps. */ secIndexMap.put(secName, secIndex); if (DbCompat.getDeferredWrite(config)) { deferredWriteDatabases.put(db, null); } if (priOpenState != null) { priOpenState.addDatabase(db); priOpenState.addSecondaryName(secName); } return secIndex; }