public synchronized void closeClass(Class entityClass) throws DatabaseException { checkOpen(); String clsName = entityClass.getName(); EntityMetadata entityMeta = checkEntityClass(clsName); PrimaryIndex priIndex = priIndexMap.get(clsName); if (priIndex != null) { /* Close the secondaries first. */ DatabaseException firstException = null; for (SecondaryKeyMetadata keyMeta : entityMeta.getSecondaryKeys().values()) { String secName = makeSecName(clsName, keyMeta.getKeyName()); SecondaryIndex secIndex = secIndexMap.get(secName); if (secIndex != null) { Database db = secIndex.getDatabase(); firstException = closeDb(db, firstException); firstException = closeDb(secIndex.getKeysDatabase(), firstException); secIndexMap.remove(secName); deferredWriteDatabases.remove(db); } } /* Close the primary last. */ Database db = priIndex.getDatabase(); firstException = closeDb(db, firstException); priIndexMap.remove(clsName); deferredWriteDatabases.remove(db); /* Throw the first exception encountered. */ if (firstException != null) { throw firstException; } } }
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); }
public EvolveStats evolve(EvolveConfig config) throws DatabaseException { checkOpen(); List<Format> toEvolve = new ArrayList<Format>(); Set<String> configToEvolve = config.getClassesToEvolve(); if (configToEvolve.isEmpty()) { catalog.getEntityFormats(toEvolve); } else { for (String name : configToEvolve) { Format format = catalog.getFormat(name); if (format == null) { throw new IllegalArgumentException("Class to evolve is not persistent: " + name); } if (!format.isEntity()) { throw new IllegalArgumentException("Class to evolve is not an entity class: " + name); } toEvolve.add(format); } } EvolveEvent event = EvolveInternal.newEvent(); for (Format format : toEvolve) { if (format.getEvolveNeeded()) { evolveIndex(format, event, config.getEvolveListener()); format.setEvolveNeeded(false); catalog.flush(); } } return event.getStats(); }
public synchronized SecondaryConfig getSecondaryConfig(Class entityClass, String keyName) { checkOpen(); String entityClsName = entityClass.getName(); EntityMetadata entityMeta = checkEntityClass(entityClsName); SecondaryKeyMetadata secKeyMeta = checkSecKey(entityMeta, keyName); String keyClassName = getSecKeyClass(secKeyMeta); String secName = makeSecName(entityClass.getName(), keyName); return (SecondaryConfig) getSecondaryConfig(secName, entityMeta, keyClassName, secKeyMeta).cloneConfig(); }
public synchronized SequenceConfig getSequenceConfig(String name) { checkOpen(); SequenceConfig config = sequenceConfigMap.get(name); if (config == null) { config = new SequenceConfig(); config.setInitialValue(1); config.setRange(1, Long.MAX_VALUE); config.setCacheSize(100); config.setAutoCommitNoSync(true); config.setAllowCreate(!storeConfig.getReadOnly()); sequenceConfigMap.put(name, config); } return config; }
public synchronized void setPrimaryConfig(Class entityClass, DatabaseConfig config) { checkOpen(); String clsName = entityClass.getName(); if (priIndexMap.containsKey(clsName)) { throw new IllegalStateException("Cannot set config after DB is open"); } EntityMetadata meta = checkEntityClass(clsName); DatabaseConfig dbConfig = getPrimaryConfig(meta); if (config.getSortedDuplicates() || config.getBtreeComparator() != dbConfig.getBtreeComparator()) { throw new IllegalArgumentException( "One of these properties was illegally changed: " + " SortedDuplicates or BtreeComparator"); } priConfigMap.put(clsName, config); }
public synchronized void truncateClass(Transaction txn, Class entityClass) throws DatabaseException { checkOpen(); /* Close primary and secondary databases. */ closeClass(entityClass); String clsName = entityClass.getName(); EntityMetadata entityMeta = checkEntityClass(clsName); /* * Truncate the primary first and let any exceptions propogate * upwards. Then truncate each secondary, only throwing the first * exception. */ String dbName = storePrefix + clsName; boolean primaryExists = true; try { env.truncateDatabase(txn, dbName, false); } catch (DatabaseNotFoundException ignored) { primaryExists = false; } if (primaryExists) { DatabaseException firstException = null; for (SecondaryKeyMetadata keyMeta : entityMeta.getSecondaryKeys().values()) { try { env.truncateDatabase( txn, storePrefix + makeSecName(clsName, keyMeta.getKeyName()), false); } catch (DatabaseNotFoundException ignored) { /* Ignore secondaries that do not exist. */ } catch (DatabaseException e) { if (firstException == null) { firstException = e; } } } if (firstException != null) { throw firstException; } } }
public synchronized Sequence getSequence(String name) throws DatabaseException { checkOpen(); if (storeConfig.getReadOnly()) { throw new IllegalStateException("Store is read-only"); } Sequence seq = sequenceMap.get(name); if (seq == null) { if (sequenceDb == null) { String dbName = storePrefix + SEQUENCE_DB; DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setTransactional(storeConfig.getTransactional()); dbConfig.setAllowCreate(true); sequenceDb = env.openDatabase(null, dbName, dbConfig); } DatabaseEntry entry = new DatabaseEntry(); StringBinding.stringToEntry(name, entry); seq = sequenceDb.openSequence(null, entry, getSequenceConfig(name)); sequenceMap.put(name, seq); } return seq; }
public synchronized void close() throws DatabaseException { checkOpen(); DatabaseException firstException = null; try { if (rawAccess) { boolean allClosed = catalog.close(); assert allClosed; } else { synchronized (catalogPool) { Map<String, PersistCatalog> catalogMap = catalogPool.get(env); assert catalogMap != null; if (catalog.close()) { /* Remove when the reference count goes to zero. */ catalogMap.remove(storeName); } } } catalog = null; } catch (DatabaseException e) { if (firstException == null) { firstException = e; } } firstException = closeDb(sequenceDb, firstException); for (SecondaryIndex index : secIndexMap.values()) { firstException = closeDb(index.getDatabase(), firstException); firstException = closeDb(index.getKeysDatabase(), firstException); } for (PrimaryIndex index : priIndexMap.values()) { firstException = closeDb(index.getDatabase(), firstException); } if (firstException != null) { throw firstException; } }
public synchronized DatabaseConfig getPrimaryConfig(Class entityClass) { checkOpen(); String clsName = entityClass.getName(); EntityMetadata meta = checkEntityClass(clsName); return getPrimaryConfig(meta).cloneConfig(); }
public synchronized void setSequenceConfig(String name, SequenceConfig config) { checkOpen(); sequenceConfigMap.put(name, config); }
/** * A getSecondaryIndex with extra parameters for opening a raw store. keyClassName is used for * consistency checking and should be null for a raw store only. */ public synchronized <SK, PK, E1, E2 extends E1> SecondaryIndex<SK, PK, E2> getSecondaryIndex( PrimaryIndex<PK, E1> primaryIndex, Class<E2> entityClass, String entityClassName, Class<SK> keyClass, String keyClassName, String keyName) throws DatabaseException { assert (rawAccess && keyClassName == null) || (!rawAccess && keyClassName != null); checkOpen(); EntityMetadata entityMeta = null; SecondaryKeyMetadata secKeyMeta = null; /* Validate the subclass for a subclass index. */ if (entityClass != primaryIndex.getEntityClass()) { entityMeta = model.getEntityMetadata(entityClassName); assert entityMeta != null; secKeyMeta = checkSecKey(entityMeta, keyName); String subclassName = entityClass.getName(); String declaringClassName = secKeyMeta.getDeclaringClassName(); if (!subclassName.equals(declaringClassName)) { throw new IllegalArgumentException( "Key for subclass " + subclassName + " is declared in a different class: " + makeSecName(declaringClassName, keyName)); } } /* * Even though the primary is already open, we can't assume the * secondary is open because we don't automatically open all * secondaries when the primary is read-only. Use auto-commit (a null * transaction) since we're opening only one database. */ String secName = makeSecName(entityClassName, keyName); SecondaryIndex<SK, PK, E2> secIndex = secIndexMap.get(secName); if (secIndex == null) { if (entityMeta == null) { entityMeta = model.getEntityMetadata(entityClassName); assert entityMeta != null; } if (secKeyMeta == null) { secKeyMeta = checkSecKey(entityMeta, keyName); } /* Check metadata. */ if (keyClassName == null) { keyClassName = getSecKeyClass(secKeyMeta); } else { String expectClsName = getSecKeyClass(secKeyMeta); if (!keyClassName.equals(expectClsName)) { throw new IllegalArgumentException( "Wrong secondary key class: " + keyClassName + " Correct class is: " + expectClsName); } } secIndex = openSecondaryIndex( null, primaryIndex, entityClass, entityMeta, keyClass, keyClassName, secKeyMeta, secName, false /*doNotCreate*/, null /*priOpenState*/); } return secIndex; }
/** * A getPrimaryIndex with extra parameters for opening a raw store. primaryKeyClass and * entityClass are used for generic typing; for a raw store, these should always be Object.class * and RawObject.class. primaryKeyClassName is used for consistency checking and should be null * for a raw store only. entityClassName is used to identify the store and may not be null. */ public synchronized <PK, E> PrimaryIndex<PK, E> getPrimaryIndex( Class<PK> primaryKeyClass, String primaryKeyClassName, Class<E> entityClass, String entityClassName) throws DatabaseException { assert (rawAccess && entityClass == RawObject.class) || (!rawAccess && entityClass != RawObject.class); assert (rawAccess && primaryKeyClassName == null) || (!rawAccess && primaryKeyClassName != null); checkOpen(); PrimaryIndex<PK, E> priIndex = priIndexMap.get(entityClassName); if (priIndex == null) { /* Check metadata. */ EntityMetadata entityMeta = checkEntityClass(entityClassName); PrimaryKeyMetadata priKeyMeta = entityMeta.getPrimaryKey(); if (primaryKeyClassName == null) { primaryKeyClassName = priKeyMeta.getClassName(); } else { String expectClsName = SimpleCatalog.keyClassName(priKeyMeta.getClassName()); if (!primaryKeyClassName.equals(expectClsName)) { throw new IllegalArgumentException( "Wrong primary key class: " + primaryKeyClassName + " Correct class is: " + expectClsName); } } /* Create bindings. */ PersistEntityBinding entityBinding = new PersistEntityBinding(catalog, entityClassName, rawAccess); PersistKeyBinding keyBinding = getKeyBinding(primaryKeyClassName); /* If not read-only, get the primary key sequence. */ String seqName = priKeyMeta.getSequenceName(); if (!storeConfig.getReadOnly() && seqName != null) { entityBinding.keyAssigner = new PersistKeyAssigner(keyBinding, entityBinding, getSequence(seqName)); } /* * Use a single transaction for opening the primary DB and its * secondaries. If opening any secondary fails, abort the * transaction and undo the changes to the state of the store. * Also support undo if the store is non-transactional. */ Transaction txn = null; DatabaseConfig dbConfig = getPrimaryConfig(entityMeta); if (dbConfig.getTransactional() && env.getThreadTransaction() == null) { txn = env.beginTransaction(null, null); } PrimaryOpenState priOpenState = new PrimaryOpenState(entityClassName); boolean success = false; try { /* Open the primary database. */ String dbName = storePrefix + entityClassName; Database db = env.openDatabase(txn, dbName, dbConfig); priOpenState.addDatabase(db); /* Create index object. */ priIndex = new PrimaryIndex(db, primaryKeyClass, keyBinding, entityClass, entityBinding); /* Update index and database maps. */ priIndexMap.put(entityClassName, priIndex); if (DbCompat.getDeferredWrite(dbConfig)) { deferredWriteDatabases.put(db, null); } /* If not read-only, open all associated secondaries. */ if (!dbConfig.getReadOnly()) { openSecondaryIndexes(txn, entityMeta, priOpenState); /* * To enable foreign key contratints, also open all primary * indexes referring to this class via a relatedEntity * property in another entity. [#15358] */ Set<String> inverseClassNames = inverseRelatedEntityMap.get(entityClassName); if (inverseClassNames != null) { for (String relatedClsName : inverseClassNames) { getRelatedIndex(relatedClsName); } } } success = true; } finally { if (success) { if (txn != null) { txn.commit(); } } else { if (txn != null) { txn.abort(); } else { priOpenState.closeDatabases(); } priOpenState.undoState(); } } } return priIndex; }