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; } } }
/** * Opens any secondary indexes defined in the given entity metadata that are not already open. * This method is called when a new entity subclass is encountered when an instance of that class * is stored, and the EntityStore.getSubclassIndex has not been previously called for that class. * [#15247] */ synchronized void openSecondaryIndexes( Transaction txn, EntityMetadata entityMeta, PrimaryOpenState priOpenState) throws DatabaseException { String entityClassName = entityMeta.getClassName(); PrimaryIndex<Object, Object> priIndex = priIndexMap.get(entityClassName); assert priIndex != null; Class<Object> entityClass = priIndex.getEntityClass(); for (SecondaryKeyMetadata secKeyMeta : entityMeta.getSecondaryKeys().values()) { String keyName = secKeyMeta.getKeyName(); String secName = makeSecName(entityClassName, keyName); SecondaryIndex<Object, Object, Object> secIndex = secIndexMap.get(secName); if (secIndex == null) { String keyClassName = getSecKeyClass(secKeyMeta); /* RawMode: should not require class. */ Class keyClass = SimpleCatalog.keyClassForName(keyClassName); openSecondaryIndex( txn, priIndex, entityClass, entityMeta, keyClass, keyClassName, secKeyMeta, makeSecName(entityClassName, secKeyMeta.getKeyName()), storeConfig.getSecondaryBulkLoad() /*doNotCreate*/, priOpenState); } } }
private SecondaryKeyMetadata checkSecKey(EntityMetadata entityMeta, String keyName) { SecondaryKeyMetadata secKeyMeta = entityMeta.getSecondaryKeys().get(keyName); if (secKeyMeta == null) { throw new IllegalArgumentException( "Not a secondary key: " + makeSecName(entityMeta.getClassName(), keyName)); } return secKeyMeta; }
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 Store(Environment env, String storeName, StoreConfig config, boolean rawAccess) throws DatabaseException { this.env = env; this.storeName = storeName; this.rawAccess = rawAccess; if (env == null || storeName == null) { throw new NullPointerException("env and storeName parameters must not be null"); } if (config != null) { model = config.getModel(); mutations = config.getMutations(); } if (config == null) { storeConfig = StoreConfig.DEFAULT; } else { storeConfig = config.cloneConfig(); } storePrefix = NAME_PREFIX + storeName + NAME_SEPARATOR; priIndexMap = new HashMap<String, PrimaryIndex>(); secIndexMap = new HashMap<String, SecondaryIndex>(); priConfigMap = new HashMap<String, DatabaseConfig>(); secConfigMap = new HashMap<String, SecondaryConfig>(); keyBindingMap = new HashMap<String, PersistKeyBinding>(); sequenceMap = new HashMap<String, Sequence>(); sequenceConfigMap = new HashMap<String, SequenceConfig>(); deferredWriteDatabases = new IdentityHashMap<Database, Object>(); if (rawAccess) { /* Open a read-only catalog that uses the stored model. */ if (model != null) { throw new IllegalArgumentException("A model may not be specified when opening a RawStore"); } DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setReadOnly(true); dbConfig.setTransactional(storeConfig.getTransactional()); catalog = new PersistCatalog( null, env, storePrefix, storePrefix + CATALOG_DB, dbConfig, model, mutations, rawAccess, this); } else { /* Open the shared catalog that uses the current model. */ synchronized (catalogPool) { Map<String, PersistCatalog> catalogMap = catalogPool.get(env); if (catalogMap == null) { catalogMap = new HashMap<String, PersistCatalog>(); catalogPool.put(env, catalogMap); } catalog = catalogMap.get(storeName); if (catalog != null) { catalog.openExisting(); } else { Transaction txn = null; if (storeConfig.getTransactional() && env.getThreadTransaction() == null) { txn = env.beginTransaction(null, null); } boolean success = false; try { DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setAllowCreate(storeConfig.getAllowCreate()); dbConfig.setReadOnly(storeConfig.getReadOnly()); dbConfig.setTransactional(storeConfig.getTransactional()); catalog = new PersistCatalog( txn, env, storePrefix, storePrefix + CATALOG_DB, dbConfig, model, mutations, rawAccess, this); catalogMap.put(storeName, catalog); success = true; } finally { if (txn != null) { if (success) { txn.commit(); } else { txn.abort(); } } } } } } /* Get the merged mutations from the catalog. */ mutations = catalog.getMutations(); /* * If there is no model parameter, use the default or stored model * obtained from the catalog. */ model = catalog.getResolvedModel(); /* * Give the model a reference to the catalog to fully initialize the * model. Only then may we initialize the Converter mutations, which * themselves may call model methods and expect the model to be fully * initialized. */ ModelInternal.setCatalog(model, catalog); for (Converter converter : mutations.getConverters()) { converter.getConversion().initialize(model); } /* * For each existing entity with a relatedEntity reference, create an * inverse map (back pointer) from the class named in the relatedEntity * to the class containing the secondary key. This is used to open the * class containing the secondary key whenever we open the * relatedEntity class, to configure foreign key constraints. Note that * we do not need to update this map as new primary indexes are * created, because opening the new index will setup the foreign key * constraints. [#15358] */ inverseRelatedEntityMap = new HashMap<String, Set<String>>(); List<Format> entityFormats = new ArrayList<Format>(); catalog.getEntityFormats(entityFormats); for (Format entityFormat : entityFormats) { EntityMetadata entityMeta = entityFormat.getEntityMetadata(); for (SecondaryKeyMetadata secKeyMeta : entityMeta.getSecondaryKeys().values()) { String relatedClsName = secKeyMeta.getRelatedEntity(); if (relatedClsName != null) { Set<String> inverseClassNames = inverseRelatedEntityMap.get(relatedClsName); if (inverseClassNames == null) { inverseClassNames = new HashSet<String>(); inverseRelatedEntityMap.put(relatedClsName, inverseClassNames); } inverseClassNames.add(entityMeta.getClassName()); } } } }