private SecondaryDatabase openSecondaryDb( TupleSerialFactory factory, String keyName, Database primary, String file, Database foreignStore) throws Exception { TupleSerialMarshalledKeyCreator keyCreator = factory.getKeyCreator(MarshalledObject.class, keyName); SecondaryConfig secConfig = new SecondaryConfig(); DbCompat.setTypeBtree(secConfig); secConfig.setTransactional(testEnv.isTxnMode()); secConfig.setAllowCreate(true); secConfig.setKeyCreator(keyCreator); if (foreignStore != null) { secConfig.setForeignKeyDatabase(foreignStore); secConfig.setForeignKeyDeleteAction(onDelete); if (onDelete == ForeignKeyDeleteAction.NULLIFY) { secConfig.setForeignKeyNullifier(keyCreator); } } return DbCompat.testOpenSecondaryDatabase(env, null, file, null, primary, secConfig); }
private Database openDb(String file) throws Exception { DatabaseConfig config = new DatabaseConfig(); DbCompat.setTypeBtree(config); config.setTransactional(testEnv.isTxnMode()); config.setAllowCreate(true); return DbCompat.testOpenDatabase(env, null, file, null, config); }
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; }
/** * Opens an entity store for raw data access. * * @param env an open Berkeley DB environment. * @param storeName the name of the entity store within the given environment. * @param config the store configuration, or null to use default configuration properties. * @throws IllegalArgumentException if the <code>Environment</code> is read-only and the <code> * config ReadOnly</code> property is false. */ public RawStore(Environment env, String storeName, StoreConfig config) throws StoreNotFoundException, DatabaseException { try { store = new Store(env, storeName, config, true /*rawAccess*/); } catch (StoreExistsException e) { /* Should never happen, ExclusiveCreate not used. */ throw DbCompat.unexpectedException(e); } catch (IncompatibleClassException e) { /* Should never happen, evolution is not performed. */ throw DbCompat.unexpectedException(e); } }
/** Returns the record number for the last record read. */ int getCurrentRecordNumber() throws DatabaseException { if (view.btreeRecNumDb) { /* BTREE-RECNO access. */ if (otherThang == null) { otherThang = new DatabaseEntry(); } DbCompat.getCurrentRecordNumber(cursor.getCursor(), otherThang, getLockMode(false)); return DbCompat.getRecordNumber(otherThang); } else { /* QUEUE or RECNO database. */ return DbCompat.getRecordNumber(keyThang); } }
/** * Inserts an entity and returns null, or updates it if the primary key already exists and returns * the existing entity. * * <p>If a {@link PrimaryKey#sequence} is used and the primary key field of the given entity is * null or zero, this method will assign the next value from the sequence to the primary key field * of the given entity. * * @param txn the transaction used to protect this operation, null to use auto-commit, or null if * the store is non-transactional. * @param entity the entity to be inserted or updated. * @return the existing entity that was updated, or null if the entity was inserted. * @throws DatabaseException the base class for all BDB exceptions. */ public E put(Transaction txn, E entity) throws DatabaseException { DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry dataEntry = new DatabaseEntry(); assignKey(entity, keyEntry); boolean autoCommit = false; Environment env = db.getEnvironment(); if (transactional && txn == null && DbCompat.getThreadTransaction(env) == null) { txn = env.beginTransaction(null, getAutoCommitTransactionConfig()); autoCommit = true; } CursorConfig cursorConfig = null; if (concurrentDB) { cursorConfig = new CursorConfig(); DbCompat.setWriteCursor(cursorConfig, true); } boolean failed = true; Cursor cursor = db.openCursor(txn, cursorConfig); LockMode lockMode = locking ? LockMode.RMW : null; try { while (true) { OperationStatus status = cursor.getSearchKey(keyEntry, dataEntry, lockMode); if (status == OperationStatus.SUCCESS) { E existing = entityBinding.entryToObject(keyEntry, dataEntry); entityBinding.objectToData(entity, dataEntry); cursor.put(keyEntry, dataEntry); failed = false; return existing; } else { entityBinding.objectToData(entity, dataEntry); status = cursor.putNoOverwrite(keyEntry, dataEntry); if (status != OperationStatus.KEYEXIST) { failed = false; return null; } } } } finally { cursor.close(); if (autoCommit) { if (failed) { txn.abort(); } else { txn.commit(); } } } }
public long count() throws DatabaseException { if (DbCompat.DATABASE_COUNT) { return DbCompat.getDatabaseCount(db); } else { long count = 0; boolean countDups = db instanceof SecondaryDatabase; DatabaseEntry key = NO_RETURN_ENTRY; DatabaseEntry data = NO_RETURN_ENTRY; CursorConfig cursorConfig = CursorConfig.READ_UNCOMMITTED; Cursor cursor = db.openCursor(null, cursorConfig); try { OperationStatus status = cursor.getFirst(key, data, null); while (status == OperationStatus.SUCCESS) { if (countDups) { count += cursor.count(); } else { count += 1; } status = cursor.getNextNoDup(key, data, null); } } finally { cursor.close(); } return count; } }
private static EnvironmentConfig newEnvConfig() { EnvironmentConfig config = new EnvironmentConfig(); if (DbCompat.MEMORY_SUBSYSTEM) { DbCompat.setInitializeCache(config, true); } return config; }
public Environment open(String testName, boolean create) throws IOException, DatabaseException { config.setAllowCreate(create); /* OLDEST deadlock detection on DB matches the use of timeouts on JE.*/ DbCompat.setLockDetectModeOldest(config); File dir = getDirectory(testName, create); return newEnvironment(dir, config); }
private static EnvironmentConfig newEnvConfig() { EnvironmentConfig config = new EnvironmentConfig(); config.setTxnNoSync(Boolean.getBoolean(SharedTestUtils.NO_SYNC)); if (DbCompat.MEMORY_SUBSYSTEM) { DbCompat.setInitializeCache(config, true); } return config; }
/** * Opens a cursor for a given database, dup'ing an existing CDB cursor if one is open for the * current thread. */ Cursor openCursor(Database db, CursorConfig cursorConfig, boolean writeCursor, Transaction txn) throws DatabaseException { if (cdbMode) { CdbCursors cdbCursors = null; WeakHashMap cdbCursorsMap = (WeakHashMap) localCdbCursors.get(); if (cdbCursorsMap == null) { cdbCursorsMap = new WeakHashMap(); localCdbCursors.set(cdbCursorsMap); } else { cdbCursors = (CdbCursors) cdbCursorsMap.get(db); } if (cdbCursors == null) { cdbCursors = new CdbCursors(); cdbCursorsMap.put(db, cdbCursors); } /* * In CDB mode the cursorConfig specified by the user is ignored * and only the writeCursor parameter is honored. This is the only * meaningful cursor attribute for CDB, and here we count on * writeCursor flag being set correctly by the caller. */ List cursors; CursorConfig cdbConfig; if (writeCursor) { if (cdbCursors.readCursors.size() > 0) { /* * Although CDB allows opening a write cursor when a read * cursor is open, a self-deadlock will occur if a write is * attempted for a record that is read-locked; we should * avoid self-deadlocks at all costs */ throw new IllegalStateException("cannot open CDB write cursor when read cursor is open"); } cursors = cdbCursors.writeCursors; cdbConfig = new CursorConfig(); DbCompat.setWriteCursor(cdbConfig, true); } else { cursors = cdbCursors.readCursors; cdbConfig = null; } Cursor cursor; if (cursors.size() > 0) { Cursor other = ((Cursor) cursors.get(0)); cursor = other.dup(false); } else { cursor = db.openCursor(null, cdbConfig); } cursors.add(cursor); return cursor; } else { return db.openCursor(txn, cursorConfig); } }
static { EnvironmentConfig config; config = newEnvConfig(); BDB = new TestEnv("bdb", config); if (DbCompat.CDB) { config = newEnvConfig(); DbCompat.setInitializeCDB(config, true); CDB = new TestEnv("cdb", config); } else { CDB = null; } config = newEnvConfig(); config.setTransactional(true); DbCompat.setInitializeLocking(config, true); TXN = new TestEnv("txn", config); }
private CurrentTransaction(Environment env) { this.env = env; try { EnvironmentConfig config = env.getConfig(); txnMode = config.getTransactional(); lockingMode = DbCompat.getInitializeLocking(config); if (txnMode || lockingMode) { writeLockMode = LockMode.RMW; } else { writeLockMode = LockMode.DEFAULT; } cdbMode = DbCompat.getInitializeCDB(config); if (cdbMode) { localCdbCursors = new ThreadLocal(); } } catch (DatabaseException e) { throw new RuntimeExceptionWrapper(e); } }
public void objectToKey(final Object entity, final DatabaseEntry key) { try { objectToKeyInternal(entity, key); } catch (RefreshException e) { e.refresh(); try { objectToKeyInternal(entity, key); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } }
public Object entryToObject(final DatabaseEntry key, final DatabaseEntry data) { try { return entryToObjectInternal(key, null, data); } catch (RefreshException e) { e.refresh(); try { return entryToObjectInternal(key, null, data); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } }
public boolean assignPrimaryKey(Object entity, DatabaseEntry key) throws DatabaseException { try { return assignPrimaryKeyInternal(entity, key); } catch (RefreshException e) { e.refresh(); try { return assignPrimaryKeyInternal(entity, key); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } }
private synchronized DatabaseConfig getPrimaryConfig(EntityMetadata meta) { String clsName = meta.getClassName(); DatabaseConfig config = priConfigMap.get(clsName); if (config == null) { config = new DatabaseConfig(); config.setTransactional(storeConfig.getTransactional()); config.setAllowCreate(!storeConfig.getReadOnly()); config.setReadOnly(storeConfig.getReadOnly()); DbCompat.setDeferredWrite(config, storeConfig.getDeferredWrite()); setBtreeComparator(config, meta.getPrimaryKey().getClassName()); priConfigMap.put(clsName, config); } return config; }
public void testReadOnlyEmptyCatalog() throws Exception { String file = "catalog.db"; /* Create an empty database. */ DatabaseConfig config = new DatabaseConfig(); config.setAllowCreate(true); DbCompat.setTypeBtree(config); Database db = DbCompat.testOpenDatabase(env, null, file, null, config); db.close(); /* Open the empty database read-only. */ config.setAllowCreate(false); config.setReadOnly(true); db = DbCompat.testOpenDatabase(env, null, file, null, config); /* Expect exception when creating the catalog. */ try { new StoredClassCatalog(db); fail(); } catch (IllegalStateException e) { } db.close(); }
/** * This method will be used in PrimaryIndex.get, where the primary key is known to DPL. This * method will force to call readEntityWithPriKey to directly assign primary key to the * de-serialized object. */ public Object entryToObjectWithPriKey(final Object priKey, final DatabaseEntry data) { try { if (priKey == null) { throw new IllegalArgumentException("Primary key cannot be null."); } return entryToObjectInternal(null, priKey, data); } catch (RefreshException e) { e.refresh(); try { return entryToObjectInternal(null, priKey, data); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } }
@Override void copySecMultiKey(RecordInput input, Format keyFormat, Set results) throws RefreshException { int len = input.readPackedInt(); for (int i = 0; i < len; i += 1) { KeyLocation loc = input.getKeyLocation(useComponentFormat); if (loc == null) { throw new IllegalArgumentException("Secondary key values in array may not be null"); } if (loc.format != useComponentFormat) { throw DbCompat.unexpectedState(useComponentFormat.getClassName()); } int off1 = loc.input.getBufferOffset(); useComponentFormat.skipContents(loc.input); int off2 = loc.input.getBufferOffset(); DatabaseEntry entry = new DatabaseEntry(loc.input.getBufferBytes(), off1, off2 - off1); results.add(entry); } }
public void sync() throws DatabaseException { List<Database> dbs = new ArrayList<Database>(); synchronized (this) { dbs.addAll(deferredWriteDatabases.keySet()); } int nDbs = dbs.size(); if (nDbs > 0) { for (int i = 0; i < nDbs; i += 1) { Database db = dbs.get(i); boolean flushLog = (i == nDbs - 1); DbCompat.syncDeferredWrite(db, flushLog); /* Call hook for unit testing. */ if (syncHook != null) { syncHook.onSync(db, flushLog); } } } }
/** Creates a key binding for a given entity class. */ public PersistEntityBinding( final PersistCatalog catalogParam, final String entityClassName, final boolean rawAccess) { catalog = catalogParam; try { entityFormat = getOrCreateFormat(catalog, entityClassName, rawAccess); } catch (RefreshException e) { /* Must assign catalog field in constructor. */ catalog = e.refresh(); try { entityFormat = getOrCreateFormat(catalog, entityClassName, rawAccess); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } if (!entityFormat.isEntity()) { throw new IllegalArgumentException("Not an entity class: " + entityClassName); } this.rawAccess = rawAccess; }
/** Returns the record number at the given slot position. */ private int getRecordNumber(int i) { if (coll.view.btreeRecNumDb) { DataCursor cursor = null; try { cursor = new DataCursor(coll.view, false); if (moveCursor(i, cursor)) { return cursor.getCurrentRecordNumber(); } else { throw new IllegalStateException(); } } catch (DatabaseException e) { throw StoredContainer.convertException(e); } finally { closeCursor(cursor); } } else { DatabaseEntry entry = new DatabaseEntry(keys[i]); return DbCompat.getRecordNumber(entry); } }
/** * Creates a mutation for converting all values of the given field in the given class version to a * type compatible with the current declared type of the field. */ public Converter( String declaringClassName, int declaringClassVersion, String fieldName, Conversion conversion) { super(declaringClassName, declaringClassVersion, fieldName); this.conversion = conversion; /* Require explicit implementation of the equals method. */ Class cls = conversion.getClass(); try { Method m = cls.getMethod("equals", Object.class); if (m.getDeclaringClass() == Object.class) { throw new IllegalArgumentException( "Conversion class does not implement the equals method " + "explicitly (Object.equals is not sufficient): " + cls.getName()); } } catch (NoSuchMethodException e) { throw DbCompat.unexpectedException(e); } }
/** Increments the record number key at the given slot. */ private void bumpRecordNumber(int i) { DatabaseEntry entry = new DatabaseEntry(keys[i]); DbCompat.setRecordNumber(entry, DbCompat.getRecordNumber(entry) + 1); keys[i] = entry.getData(); }
public boolean isCdbMode() { return DbCompat.getInitializeCDB(config); }
void copyConfig(EnvironmentConfig copyToConfig) { DbCompat.setInitializeCache(copyToConfig, DbCompat.getInitializeCache(config)); DbCompat.setInitializeLocking(copyToConfig, DbCompat.getInitializeLocking(config)); DbCompat.setInitializeCDB(copyToConfig, DbCompat.getInitializeCDB(config)); copyToConfig.setTransactional(config.getTransactional()); }
/** * Utility method for use by bindings to translate a entry buffer to an record number integer. * * @param entry the entry buffer. * @return the record number. */ public static long entryToRecordNumber(DatabaseEntry entry) { return DbCompat.getRecordNumber(entry) & 0xFFFFFFFFL; }
/** * Utility method for use by bindings to translate a record number integer to a entry buffer. * * @param recordNumber the record number. * @param entry the entry buffer to hold the record number. */ public static void recordNumberToEntry(long recordNumber, DatabaseEntry entry) { entry.setData(new byte[4], 0, 4); DbCompat.setRecordNumber(entry, (int) recordNumber); }
/** * Returns true if a write cursor is requested by the user via the cursor config, or if this is a * writable cursor and the user has not specified a cursor config. For CDB, a special cursor must * be created for writing. See CurrentTransaction.openCursor. */ private static boolean isWriteCursor(CursorConfig config, boolean writeAllowed) { return DbCompat.getWriteCursor(config) || (config == CursorConfig.DEFAULT && writeAllowed); }