/** Get a locker for a read or cursor operation. */ private static Locker getReadableLocker( Environment env, Locker locker, boolean readCommittedIsolation) throws DatabaseException { EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); if (locker == null) { Transaction xaTxn = env.getThreadTransaction(); if (xaTxn != null) { return DbInternal.getLocker(xaTxn); } } if (locker == null) { /* Non-transactional user operations use ThreadLocker. */ locker = ThreadLocker.createThreadLocker(envImpl); } else { /* * Use the given locker. For read-committed, wrap the given * transactional locker in a special locker for that isolation * level. */ if (readCommittedIsolation) { locker = ReadCommittedLocker.createReadCommittedLocker(envImpl, locker); } } return locker; }
public static Locker getWritableLocker__wrappee__base( Environment env, Transaction userTxn, boolean dbIsTransactional, boolean retainNonTxnLocks, TransactionConfig autoCommitConfig) throws DatabaseException { EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env); boolean envIsTransactional = envImpl.isTransactional(); if (userTxn == null) { Transaction xaLocker = env.getThreadTransaction(); if (xaLocker != null) { return DbInternal.getLocker(xaLocker); } } if (dbIsTransactional && userTxn == null) { if (autoCommitConfig == null) { autoCommitConfig = DbInternal.getDefaultTxnConfig(env); } return new AutoTxn(envImpl, autoCommitConfig); } else if (userTxn == null) { if (retainNonTxnLocks) { return new BasicLocker(envImpl); } else { return new ThreadLocker(envImpl); } } else { if (!envIsTransactional) { throw new DatabaseException( "A Transaction cannot be used because the" + " environment was opened" + " non-transactionally"); } if (!dbIsTransactional) { throw new DatabaseException( "A Transaction cannot be used because the" + " database was opened" + " non-transactionally"); } Locker locker = DbInternal.getLocker(userTxn); if (locker.isReadCommittedIsolation() && !retainNonTxnLocks) { return new ReadCommittedLocker(envImpl, locker); } else { return locker; } } }
private static Locker getReadableLocker__wrappee__base( Environment env, Locker locker, boolean retainNonTxnLocks, boolean readCommittedIsolation) throws DatabaseException { EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env); if (locker == null) { Transaction xaTxn = env.getThreadTransaction(); if (xaTxn != null) { return DbInternal.getLocker(xaTxn); } } if (locker == null) { if (retainNonTxnLocks) { locker = new BasicLocker(envImpl); } else { locker = new ThreadLocker(envImpl); } } else { if (readCommittedIsolation && !retainNonTxnLocks) { locker = new ReadCommittedLocker(envImpl, locker); } } return locker; }
/** * Get a locker for a write operation. * * @param autoTxnIsReplicated is true if this transaction is executed on a rep group master, and * needs to be broadcast. Currently, all application-created transactions are of the type * com.sleepycat.je.txn.Txn, and are replicated if the parent environment is replicated. Auto * Txns are trickier because they may be created for a local write operation, such as log * cleaning. * @throws IllegalArgumentException via db/cursor read/write methods. */ public static Locker getWritableLocker( Environment env, Transaction userTxn, boolean isInternalDb, boolean dbIsTransactional, boolean autoTxnIsReplicated, TransactionConfig autoCommitConfig) throws DatabaseException { EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); boolean envIsTransactional = envImpl.isTransactional(); if (userTxn == null) { Transaction xaLocker = env.getThreadTransaction(); if (xaLocker != null) { return DbInternal.getLocker(xaLocker); } } if (dbIsTransactional && userTxn == null) { if (autoCommitConfig == null) { autoCommitConfig = DbInternal.getDefaultTxnConfig(env); } return Txn.createAutoTxn( envImpl, autoCommitConfig, (autoTxnIsReplicated ? ReplicationContext.MASTER : ReplicationContext.NO_REPLICATE)); } else if (userTxn == null) { /* Non-transactional user operations use ThreadLocker. */ return ThreadLocker.createThreadLocker(envImpl); } else { /* * The user provided a transaction, the environment and the * database had better be opened transactionally. */ if (!isInternalDb && !envIsTransactional) { throw new IllegalArgumentException( "A Transaction cannot be used because the" + " environment was opened non-transactionally"); } if (!dbIsTransactional) { throw new IllegalArgumentException( "A Transaction cannot be used because the" + " database was opened non-transactionally"); } /* * Use the locker for the given transaction. For read-comitted, * wrap the given transactional locker in a special locker for that * isolation level. */ Locker locker = DbInternal.getLocker(userTxn); if (locker.isReadCommittedIsolation()) { return ReadCommittedLocker.createReadCommittedLocker(envImpl, locker); } return locker; } }
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()); } } } }
/** * 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; }