public void testTruncate() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); Transaction txn = txnBegin(); for (int i = 0; i < NUM_RECS; i += 1) { priDb.put(txn, entry(i), entry(i)); } verifyRecords(txn, priDb, NUM_RECS, false); verifyRecords(txn, secDb, NUM_RECS, true); txnCommit(txn); secDb.close(); priDb.close(); txn = txnBegin(); assertEquals(NUM_RECS, env.truncateDatabase(txn, "testDB", true)); assertEquals(NUM_RECS, env.truncateDatabase(txn, "testSecDB", true)); txnCommit(txn); secDb = initDb(); priDb = secDb.getPrimaryDatabase(); txn = txnBegin(); verifyRecords(txn, priDb, 0, false); verifyRecords(txn, secDb, 0, true); txnCommit(txn); secDb.close(); priDb.close(); }
/** * Returns a read-only keys index that maps secondary key to primary key. When accessing the keys * index, the primary key is returned rather than the entity. When only the primary key is needed * and not the entire entity, using the keys index is less expensive than using the secondary * index because the primary index does not have to be accessed. * * <p>Note the following in the unusual case that you are <em>not</em> using an <code>EntityStore * </code>: This method will open the keys database, a second database handle for the secondary * database, if it is not already open. In this case, if you are <em>not</em> using an <code> * EntityStore</code>, then you are responsible for closing the database returned by {@link * #getKeysDatabase} before closing the environment. If you <em>are</em> using an <code> * EntityStore</code>, the keys database will be closed automatically by {@link * EntityStore#close}. * * @return the keys index. */ public synchronized EntityIndex<SK, PK> keysIndex() throws DatabaseException { if (keysIndex == null) { if (keysDb == null) { DatabaseConfig config = secDb.getConfig(); config.setReadOnly(true); keysDb = db.getEnvironment().openDatabase(null, secDb.getDatabaseName(), config); } keysIndex = new KeysIndex<SK, PK>( keysDb, keyClass, keyBinding, priIndex.getKeyClass(), priIndex.getKeyBinding()); } return keysIndex; }
public void testOpenAndClose() throws DatabaseException { Database priDb = openDatabase(false, "testDB", false); /* Open two secondaries as regular databases and as secondaries. */ Database secDbDetached = openDatabase(true, "testSecDB", false); SecondaryDatabase secDb = openSecondary(priDb, true, "testSecDB", false, false); Database secDb2Detached = openDatabase(true, "testSecDB2", false); SecondaryDatabase secDb2 = openSecondary(priDb, true, "testSecDB2", false, false); assertEquals( priDb.getSecondaryDatabases(), Arrays.asList(new SecondaryDatabase[] {secDb, secDb2})); Transaction txn = txnBegin(); /* Check that primary writes to both secondaries. */ checkSecondaryUpdate(txn, priDb, 1, secDbDetached, true, secDb2Detached, true); /* New txn before closing database. */ txnCommit(txn); txn = txnBegin(); /* Close 2nd secondary. */ secDb2.close(); assertEquals(priDb.getSecondaryDatabases(), Arrays.asList(new SecondaryDatabase[] {secDb})); /* Check that primary writes to 1st secondary only. */ checkSecondaryUpdate(txn, priDb, 2, secDbDetached, true, secDb2Detached, false); /* New txn before closing database. */ txnCommit(txn); txn = txnBegin(); /* Close 1st secondary. */ secDb.close(); assertEquals(0, priDb.getSecondaryDatabases().size()); /* Check that primary writes to no secondaries. */ checkSecondaryUpdate(txn, priDb, 3, secDbDetached, false, secDb2Detached, false); /* Open the two secondaries again. */ secDb = openSecondary(priDb, true, "testSecDB", false, false); secDb2 = openSecondary(priDb, true, "testSecDB2", false, false); assertEquals( priDb.getSecondaryDatabases(), Arrays.asList(new SecondaryDatabase[] {secDb, secDb2})); /* Check that primary writes to both secondaries. */ checkSecondaryUpdate(txn, priDb, 4, secDbDetached, true, secDb2Detached, true); /* Close the primary first to disassociate secondaries. */ txnCommit(txn); priDb.close(); assertNull(secDb.getPrimaryDatabase()); assertNull(secDb2.getPrimaryDatabase()); secDb2.close(); secDb.close(); secDb2Detached.close(); secDbDetached.close(); }
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 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; }
public void testPopulate() throws DatabaseException { Database priDb = openDatabase(false, "testDB", false); Transaction txn = txnBegin(); /* Test population of newly created secondary database. */ for (int i = 0; i < NUM_RECS; i += 1) { assertSame(OperationStatus.SUCCESS, priDb.put(txn, entry(i), entry(i))); } txnCommit(txn); SecondaryDatabase secDb = openSecondary(priDb, true, "testSecDB", true, false); txn = txnBegin(); verifyRecords(txn, secDb, NUM_RECS, true); txnCommit(txn); /* * Clear secondary and perform populate again, to test the case where * an existing database is opened, and therefore a write txn will only * be created in order to populate it */ Database secDbDetached = openDatabase(true, "testSecDB", false); secDb.close(); txn = txnBegin(); for (int i = 0; i < NUM_RECS; i += 1) { assertSame(OperationStatus.SUCCESS, secDbDetached.delete(txn, entry(i + KEY_OFFSET))); } verifyRecords(txn, secDbDetached, 0, true); txnCommit(txn); secDb = openSecondary(priDb, true, "testSecDB", true, false); txn = txnBegin(); verifyRecords(txn, secDb, NUM_RECS, true); verifyRecords(txn, secDbDetached, NUM_RECS, true); txnCommit(txn); secDbDetached.close(); secDb.close(); priDb.close(); }
public void testReadOnly() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); OperationStatus status; Transaction txn = txnBegin(); for (int i = 0; i < NUM_RECS; i += 1) { status = priDb.put(txn, entry(i), entry(i)); assertSame(OperationStatus.SUCCESS, status); } /* * Secondaries can be opened without a key creator if the primary is * read only. openSecondary will specify a null key creator if the * readOnly param is false. */ Database readOnlyPriDb = openDatabase(false, "testDB", true); SecondaryDatabase readOnlySecDb = openSecondary(readOnlyPriDb, true, "testSecDB", false, true); assertNull(readOnlySecDb.getSecondaryConfig().getKeyCreator()); verifyRecords(txn, readOnlySecDb, NUM_RECS, true); txnCommit(txn); readOnlySecDb.close(); readOnlyPriDb.close(); secDb.close(); priDb.close(); }
public E get(Transaction txn, SK key, LockMode lockMode) throws DatabaseException { DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry pkeyEntry = new DatabaseEntry(); DatabaseEntry dataEntry = new DatabaseEntry(); keyBinding.objectToEntry(key, keyEntry); OperationStatus status = secDb.get(txn, keyEntry, pkeyEntry, dataEntry, lockMode); if (status == OperationStatus.SUCCESS) { return (E) entityBinding.entryToObject(pkeyEntry, dataEntry); } else { return null; } }
/** [#14966] */ public void testDirtyReadPartialGet() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); DatabaseEntry data = new DatabaseEntry(); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry secKey = new DatabaseEntry(); OperationStatus status; /* Put a record */ Transaction txn = txnBegin(); status = priDb.put(txn, entry(0), entry(0)); assertSame(OperationStatus.SUCCESS, status); txnCommit(txn); /* Regular get */ status = secDb.get(null, entry(0 + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(0), key); assertDataEquals(entry(0), data); /* Dirty read returning no data */ data.setPartial(0, 0, true); status = secDb.get(null, entry(0 + KEY_OFFSET), key, data, LockMode.READ_UNCOMMITTED); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(0), key); assertEquals(0, data.getData().length); assertEquals(0, data.getSize()); /* Dirty read returning partial data */ data.setPartial(0, 1, true); status = secDb.get(null, entry(0 + KEY_OFFSET), key, data, LockMode.READ_UNCOMMITTED); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(0), key); assertEquals(1, data.getData().length); assertEquals(1, data.getSize()); secDb.close(); priDb.close(); }
/** Test that null can be passed for the LockMode to all get methods. */ public void testNullLockMode() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); Transaction txn = txnBegin(); DatabaseEntry key = entry(0); DatabaseEntry data = entry(0); DatabaseEntry secKey = entry(KEY_OFFSET); DatabaseEntry found = new DatabaseEntry(); DatabaseEntry found2 = new DatabaseEntry(); DatabaseEntry found3 = new DatabaseEntry(); assertEquals(OperationStatus.SUCCESS, priDb.put(txn, key, data)); assertEquals(OperationStatus.SUCCESS, priDb.put(txn, entry(1), data)); assertEquals(OperationStatus.SUCCESS, priDb.put(txn, entry(2), entry(2))); /* Database operations. */ assertEquals(OperationStatus.SUCCESS, priDb.get(txn, key, found, null)); assertEquals(OperationStatus.SUCCESS, priDb.getSearchBoth(txn, key, data, null)); assertEquals(OperationStatus.SUCCESS, secDb.get(txn, secKey, found, null)); assertEquals(OperationStatus.SUCCESS, secDb.get(txn, secKey, found, found2, null)); assertEquals(OperationStatus.SUCCESS, secDb.getSearchBoth(txn, secKey, key, found, null)); /* Cursor operations. */ txnCommit(txn); txn = txnBeginCursor(); Cursor cursor = priDb.openCursor(txn, null); SecondaryCursor secCursor = secDb.openSecondaryCursor(txn, null); assertEquals(OperationStatus.SUCCESS, cursor.getSearchKey(key, found, null)); assertEquals(OperationStatus.SUCCESS, cursor.getSearchBoth(key, data, null)); assertEquals(OperationStatus.SUCCESS, cursor.getSearchKeyRange(key, found, null)); assertEquals(OperationStatus.SUCCESS, cursor.getSearchBothRange(key, data, null)); assertEquals(OperationStatus.SUCCESS, cursor.getFirst(found, found2, null)); assertEquals(OperationStatus.SUCCESS, cursor.getNext(found, found2, null)); assertEquals(OperationStatus.SUCCESS, cursor.getPrev(found, found2, null)); assertEquals(OperationStatus.NOTFOUND, cursor.getNextDup(found, found2, null)); assertEquals(OperationStatus.NOTFOUND, cursor.getPrevDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, cursor.getNextNoDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, cursor.getPrevNoDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, cursor.getLast(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchKey(secKey, found, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchKeyRange(secKey, found, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getFirst(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getNext(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getPrev(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getNextDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getPrevDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getNextNoDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getPrevNoDup(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getLast(found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchKey(secKey, found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchBoth(secKey, data, found, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchKeyRange(secKey, found, found2, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchBothRange(secKey, data, found, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getFirst(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getNext(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getPrev(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getNextDup(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getPrevDup(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getNextNoDup(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getPrevNoDup(found, found2, found3, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getLast(found, found2, found3, null)); secCursor.close(); cursor.close(); txnCommit(txn); secDb.close(); priDb.close(); env.close(); env = null; }
/** @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(); }
public void testUniqueSecondaryKey() throws DatabaseException { Database priDb = openDatabase(false, "testDB", false); SecondaryDatabase secDb = openSecondary(priDb, false, "testSecDB", false, false); DatabaseEntry key; DatabaseEntry data; DatabaseEntry pkey = new DatabaseEntry(); Transaction txn; /* Put {0, 0} */ txn = txnBegin(); key = entry(0); data = entry(0); priDb.put(txn, key, data); txnCommit(txn); assertEquals(OperationStatus.SUCCESS, secDb.get(null, entry(0 + KEY_OFFSET), pkey, data, null)); assertEquals(0, TestUtils.getTestVal(pkey.getData())); assertEquals(0, TestUtils.getTestVal(data.getData())); /* Put {1, 1} */ txn = txnBegin(); key = entry(1); data = entry(1); priDb.put(txn, key, data); txnCommit(txn); assertEquals(OperationStatus.SUCCESS, secDb.get(null, entry(1 + KEY_OFFSET), pkey, data, null)); assertEquals(1, TestUtils.getTestVal(pkey.getData())); assertEquals(1, TestUtils.getTestVal(data.getData())); /* Put {2, 0} */ txn = txnBegin(); key = entry(2); data = entry(0); try { priDb.put(txn, key, data); /* Expect exception because secondary key must be unique. */ fail(); } catch (DatabaseException e) { txnAbort(txn); /* Ensure that primary record was not inserted. */ assertEquals(OperationStatus.NOTFOUND, secDb.get(null, key, data, null)); /* Ensure that secondary record has not changed. */ assertEquals( OperationStatus.SUCCESS, secDb.get(null, entry(0 + KEY_OFFSET), pkey, data, null)); assertEquals(0, TestUtils.getTestVal(pkey.getData())); assertEquals(0, TestUtils.getTestVal(data.getData())); } /* Overwrite {1, 1} */ txn = txnBegin(); key = entry(1); data = entry(1); priDb.put(txn, key, data); txnCommit(txn); assertEquals(OperationStatus.SUCCESS, secDb.get(null, entry(1 + KEY_OFFSET), pkey, data, null)); assertEquals(1, TestUtils.getTestVal(pkey.getData())); assertEquals(1, TestUtils.getTestVal(data.getData())); /* Modify secondary key to {1, 3} */ txn = txnBegin(); key = entry(1); data = entry(3); priDb.put(txn, key, data); txnCommit(txn); assertEquals(OperationStatus.SUCCESS, secDb.get(null, entry(3 + KEY_OFFSET), pkey, data, null)); assertEquals(1, TestUtils.getTestVal(pkey.getData())); assertEquals(3, TestUtils.getTestVal(data.getData())); secDb.close(); priDb.close(); }
public void testPutAndDelete() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); DatabaseEntry data = new DatabaseEntry(); DatabaseEntry key = new DatabaseEntry(); OperationStatus status; Transaction txn = txnBegin(); /* Database.put() */ status = priDb.put(txn, entry(1), entry(2)); assertSame(OperationStatus.SUCCESS, status); status = secDb.get(txn, entry(102), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(2), data); /* Database.putNoOverwrite() */ status = priDb.putNoOverwrite(txn, entry(1), entry(1)); assertSame(OperationStatus.KEYEXIST, status); status = secDb.get(txn, entry(102), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(2), data); /* Database.put() overwrite */ status = priDb.put(txn, entry(1), entry(3)); assertSame(OperationStatus.SUCCESS, status); status = secDb.get(txn, entry(102), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); status = secDb.get(txn, entry(103), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(3), data); /* Database.delete() */ status = priDb.delete(txn, entry(1)); assertSame(OperationStatus.SUCCESS, status); status = priDb.delete(txn, entry(1)); assertSame(OperationStatus.NOTFOUND, status); status = secDb.get(txn, entry(103), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* SecondaryDatabase.delete() */ status = priDb.put(txn, entry(1), entry(1)); assertSame(OperationStatus.SUCCESS, status); status = priDb.put(txn, entry(2), entry(1)); assertSame(OperationStatus.SUCCESS, status); status = secDb.get(txn, entry(101), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(1), data); status = secDb.delete(txn, entry(101)); assertSame(OperationStatus.SUCCESS, status); status = secDb.delete(txn, entry(101)); assertSame(OperationStatus.NOTFOUND, status); status = secDb.get(txn, entry(101), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); status = priDb.get(txn, entry(1), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); status = priDb.get(txn, entry(2), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* * Database.putNoDupData() cannot be called since the primary cannot be * configured for duplicates. */ /* Primary and secondary are empty now. */ /* Get a txn for a cursor. */ txnCommit(txn); txn = txnBeginCursor(); Cursor priCursor = null; SecondaryCursor secCursor = null; try { priCursor = priDb.openCursor(txn, null); secCursor = secDb.openSecondaryCursor(txn, null); /* Cursor.putNoOverwrite() */ status = priCursor.putNoOverwrite(entry(1), entry(2)); assertSame(OperationStatus.SUCCESS, status); status = secCursor.getSearchKey(entry(102), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(2), data); /* Cursor.putCurrent() */ status = priCursor.putCurrent(entry(3)); assertSame(OperationStatus.SUCCESS, status); status = secCursor.getSearchKey(entry(102), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); status = secCursor.getSearchKey(entry(103), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(3), data); /* Cursor.delete() */ status = priCursor.delete(); assertSame(OperationStatus.SUCCESS, status); status = priCursor.delete(); assertSame(OperationStatus.KEYEMPTY, status); status = secCursor.getSearchKey(entry(103), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); status = priCursor.getSearchKey(entry(1), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* Cursor.put() */ status = priCursor.put(entry(1), entry(4)); assertSame(OperationStatus.SUCCESS, status); status = secCursor.getSearchKey(entry(104), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), key); assertDataEquals(entry(4), data); /* SecondaryCursor.delete() */ status = secCursor.delete(); assertSame(OperationStatus.SUCCESS, status); status = secCursor.delete(); assertSame(OperationStatus.KEYEMPTY, status); status = secCursor.getCurrent(new DatabaseEntry(), key, data, LockMode.DEFAULT); assertSame(OperationStatus.KEYEMPTY, status); status = secCursor.getSearchKey(entry(104), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); status = priCursor.getSearchKey(entry(1), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* * Cursor.putNoDupData() cannot be called since the primary cannot * be configured for duplicates. */ /* Primary and secondary are empty now. */ } finally { if (secCursor != null) { secCursor.close(); } if (priCursor != null) { priCursor.close(); } } txnCommit(txn); secDb.close(); priDb.close(); }
public void testGet() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); DatabaseEntry data = new DatabaseEntry(); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry secKey = new DatabaseEntry(); OperationStatus status; Transaction txn = txnBegin(); /* * For parameters that do not require initialization with a non-null * data array, we set them to null to make sure this works. [#12121] */ /* Add one record for each key with one data/duplicate. */ for (int i = 0; i < NUM_RECS; i += 1) { status = priDb.put(txn, entry(i), entry(i)); assertSame(OperationStatus.SUCCESS, status); } /* SecondaryDatabase.get() */ for (int i = 0; i < NUM_RECS; i += 1) { data.setData(null); status = secDb.get(txn, entry(i + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); } data.setData(null); status = secDb.get(txn, entry(NUM_RECS + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* SecondaryDatabase.getSearchBoth() */ for (int i = 0; i < NUM_RECS; i += 1) { data.setData(null); status = secDb.getSearchBoth(txn, entry(i + KEY_OFFSET), entry(i), data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i), data); } data.setData(null); status = secDb.getSearchBoth( txn, entry(NUM_RECS + KEY_OFFSET), entry(NUM_RECS), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* Get a cursor txn. */ txnCommit(txn); txn = txnBeginCursor(); SecondaryCursor cursor = secDb.openSecondaryCursor(txn, null); try { /* SecondaryCursor.getFirst()/getNext() */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getFirst(secKey, key, data, LockMode.DEFAULT); for (int i = 0; i < NUM_RECS; i += 1) { assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getNext(secKey, key, data, LockMode.DEFAULT); } assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getCurrent() (last) */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getCurrent(secKey, key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(NUM_RECS - 1 + KEY_OFFSET), secKey); assertDataEquals(entry(NUM_RECS - 1), key); assertDataEquals(entry(NUM_RECS - 1), data); assertPriLocked(priDb, key); /* SecondaryCursor.getLast()/getPrev() */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getLast(secKey, key, data, LockMode.DEFAULT); for (int i = NUM_RECS - 1; i >= 0; i -= 1) { assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getPrev(secKey, key, data, LockMode.DEFAULT); } assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getCurrent() (first) */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getCurrent(secKey, key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(0 + KEY_OFFSET), secKey); assertDataEquals(entry(0), key); assertDataEquals(entry(0), data); assertPriLocked(priDb, key); /* SecondaryCursor.getSearchKey() */ key.setData(null); data.setData(null); status = cursor.getSearchKey(entry(KEY_OFFSET - 1), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); for (int i = 0; i < NUM_RECS; i += 1) { key.setData(null); data.setData(null); status = cursor.getSearchKey(entry(i + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key); } key.setData(null); data.setData(null); status = cursor.getSearchKey(entry(NUM_RECS + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getSearchBoth() */ data.setData(null); status = cursor.getSearchKey(entry(KEY_OFFSET - 1), entry(0), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); for (int i = 0; i < NUM_RECS; i += 1) { data.setData(null); status = cursor.getSearchBoth(entry(i + KEY_OFFSET), entry(i), data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i), data); assertPriLocked(priDb, entry(i)); } data.setData(null); status = cursor.getSearchBoth( entry(NUM_RECS + KEY_OFFSET), entry(NUM_RECS), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getSearchKeyRange() */ key.setData(null); data.setData(null); status = cursor.getSearchKeyRange(entry(KEY_OFFSET - 1), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(0), key); assertDataEquals(entry(0), data); assertPriLocked(priDb, key); for (int i = 0; i < NUM_RECS; i += 1) { key.setData(null); data.setData(null); status = cursor.getSearchKeyRange(entry(i + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key); } key.setData(null); data.setData(null); status = cursor.getSearchKeyRange(entry(NUM_RECS + KEY_OFFSET), key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getSearchBothRange() */ data.setData(null); status = cursor.getSearchBothRange(entry(1 + KEY_OFFSET), entry(1), data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(1), data); assertPriLocked(priDb, entry(1)); for (int i = 0; i < NUM_RECS; i += 1) { data.setData(null); status = cursor.getSearchBothRange(entry(i + KEY_OFFSET), entry(i), data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i), data); assertPriLocked(priDb, entry(i)); } data.setData(null); status = cursor.getSearchBothRange( entry(NUM_RECS + KEY_OFFSET), entry(NUM_RECS), data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); /* Add one duplicate for each key. */ Cursor priCursor = priDb.openCursor(txn, null); try { for (int i = 0; i < NUM_RECS; i += 1) { status = priCursor.put(entry(i + KEY_OFFSET), entry(i)); assertSame(OperationStatus.SUCCESS, status); } } finally { priCursor.close(); } /* SecondaryCursor.getNextDup() */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getFirst(secKey, key, data, LockMode.DEFAULT); for (int i = 0; i < NUM_RECS; i += 1) { assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key, data); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getNextDup(secKey, key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i + KEY_OFFSET), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key, data); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getNextDup(secKey, key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getNext(secKey, key, data, LockMode.DEFAULT); } assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getNextNoDup() */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getFirst(secKey, key, data, LockMode.DEFAULT); for (int i = 0; i < NUM_RECS; i += 1) { assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key, data); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getNextNoDup(secKey, key, data, LockMode.DEFAULT); } assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getPrevDup() */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getLast(secKey, key, data, LockMode.DEFAULT); for (int i = NUM_RECS - 1; i >= 0; i -= 1) { assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i + KEY_OFFSET), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key, data); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getPrevDup(secKey, key, data, LockMode.DEFAULT); assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key, data); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getPrevDup(secKey, key, data, LockMode.DEFAULT); assertSame(OperationStatus.NOTFOUND, status); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getPrev(secKey, key, data, LockMode.DEFAULT); } assertSame(OperationStatus.NOTFOUND, status); /* SecondaryCursor.getPrevNoDup() */ secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getLast(secKey, key, data, LockMode.DEFAULT); for (int i = NUM_RECS - 1; i >= 0; i -= 1) { assertSame(OperationStatus.SUCCESS, status); assertDataEquals(entry(i + KEY_OFFSET), secKey); assertDataEquals(entry(i + KEY_OFFSET), key); assertDataEquals(entry(i), data); assertPriLocked(priDb, key, data); secKey.setData(null); key.setData(null); data.setData(null); status = cursor.getPrevNoDup(secKey, key, data, LockMode.DEFAULT); } assertSame(OperationStatus.NOTFOUND, status); } finally { cursor.close(); } txnCommit(txn); secDb.close(); priDb.close(); }
/** * Test that an exception is thrown when a cursor is used in the wrong state. No put or get is * allowed in the closed state, and certain gets and puts are not allowed in the uninitialized * state. */ public void testCursorState() throws DatabaseException { SecondaryDatabase secDb = initDb(); Database priDb = secDb.getPrimaryDatabase(); Transaction txn = txnBegin(); DatabaseEntry key = entry(0); DatabaseEntry data = entry(0); DatabaseEntry secKey = entry(KEY_OFFSET); DatabaseEntry found = new DatabaseEntry(); DatabaseEntry found2 = new DatabaseEntry(); assertEquals(OperationStatus.SUCCESS, priDb.put(txn, key, data)); txnCommit(txn); txn = txnBeginCursor(); Cursor cursor = priDb.openCursor(txn, null); SecondaryCursor secCursor = secDb.openSecondaryCursor(txn, null); /* Check the uninitialized state for certain operations. */ try { cursor.count(); fail(); } catch (DatabaseException expected) { } try { cursor.delete(); fail(); } catch (DatabaseException expected) { } try { cursor.putCurrent(data); fail(); } catch (DatabaseException expected) { } try { cursor.getCurrent(key, data, null); fail(); } catch (DatabaseException expected) { } try { cursor.getNextDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getPrevDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.count(); fail(); } catch (DatabaseException expected) { } try { secCursor.delete(); fail(); } catch (DatabaseException expected) { } try { secCursor.getCurrent(key, data, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getNextDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getPrevDup(found, found2, null); fail(); } catch (DatabaseException expected) { } /* Initialize, then close, then check all operations. */ assertEquals(OperationStatus.SUCCESS, cursor.getSearchKey(key, found, null)); assertEquals(OperationStatus.SUCCESS, secCursor.getSearchKey(secKey, found, null)); secCursor.close(); cursor.close(); try { cursor.close(); fail(); } catch (DatabaseException expected) { } try { cursor.count(); fail(); } catch (DatabaseException expected) { } try { cursor.delete(); fail(); } catch (DatabaseException expected) { } try { cursor.put(key, data); fail(); } catch (DatabaseException expected) { } try { cursor.putNoOverwrite(key, data); fail(); } catch (DatabaseException expected) { } try { cursor.putNoDupData(key, data); fail(); } catch (DatabaseException expected) { } try { cursor.putCurrent(data); fail(); } catch (DatabaseException expected) { } try { cursor.getCurrent(key, data, null); fail(); } catch (DatabaseException expected) { } try { cursor.getSearchKey(key, found, null); fail(); } catch (DatabaseException expected) { } try { cursor.getSearchBoth(key, data, null); fail(); } catch (DatabaseException expected) { } try { cursor.getSearchKeyRange(key, found, null); fail(); } catch (DatabaseException expected) { } try { cursor.getSearchBothRange(key, data, null); fail(); } catch (DatabaseException expected) { } try { cursor.getFirst(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getNext(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getPrev(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getNextDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getPrevDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getNextNoDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getPrevNoDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { cursor.getLast(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.close(); fail(); } catch (DatabaseException expected) { } try { secCursor.count(); fail(); } catch (DatabaseException expected) { } try { secCursor.delete(); fail(); } catch (DatabaseException expected) { } try { secCursor.getCurrent(key, data, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getSearchKey(secKey, found, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getSearchKeyRange(secKey, found, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getFirst(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getNext(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getPrev(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getNextDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getPrevDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getNextNoDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getPrevNoDup(found, found2, null); fail(); } catch (DatabaseException expected) { } try { secCursor.getLast(found, found2, null); fail(); } catch (DatabaseException expected) { } txnCommit(txn); secDb.close(); priDb.close(); env.close(); env = null; }
/** 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(); }