/** Write data into the database. */ private void generateData( Environment master, int numTxns, Durability durability, boolean doCommit) { /* Write some data. */ DatabaseEntry key = new DatabaseEntry(); byte[] dataPadding = new byte[1000]; DatabaseEntry data = new DatabaseEntry(dataPadding); TransactionConfig txnConfig = new TransactionConfig(); txnConfig.setDurability(durability); for (int i = 0; i < numTxns; i++) { final Transaction txn = master.beginTransaction(null, txnConfig); // long keyPrefix = i << 10; // LongBinding.longToEntry(keyPrefix + i, key); LongBinding.longToEntry(i, key); db.put(txn, key, data); if (doCommit) { txn.commit(); } else { txn.abort(); } } }
private void attemptAbort(Transaction transaction) { try { if (transaction != null) transaction.abort(); } catch (Exception e) { logger.error("Abort failed!", e); } }
@Override public synchronized void abort() { try { closeOpenedCursors(); dbTransaction.abort(); getPersistenceManager().unregisterTransaction(this); super.abort(); } catch (DatabaseException e) { throw getPersistenceManager().convertDatabaseException(e); } }
/** {@inheritDoc} */ public void abort() { try { if (xid != null) { env.rollback(xid); } else { txn.abort(); } } catch (DatabaseException e) { throw JeEnvironment.convertException(e, false); } catch (XAException e) { throw JeEnvironment.convertException(e, false); } }
public List<WebURL> get(int max) throws DatabaseException { synchronized (mutex) { int matches = 0; List<WebURL> results = new ArrayList<WebURL>(max); Cursor cursor = null; OperationStatus result; DatabaseEntry key = new DatabaseEntry(); DatabaseEntry value = new DatabaseEntry(); Transaction txn; if (resumable) { txn = env.beginTransaction(null, null); } else { txn = null; } try { cursor = urlsDB.openCursor(txn, null); result = cursor.getFirst(key, value, null); while (matches < max && result == OperationStatus.SUCCESS) { if (value.getData().length > 0) { results.add(webURLBinding.entryToObject(value)); matches++; } result = cursor.getNext(key, value, null); } } catch (DatabaseException e) { if (txn != null) { txn.abort(); txn = null; } throw e; } finally { if (cursor != null) { cursor.close(); } if (txn != null) { txn.commit(); } } return results; } }
public void delete(int count) throws DatabaseException { synchronized (mutex) { int matches = 0; Cursor cursor = null; OperationStatus result; DatabaseEntry key = new DatabaseEntry(); DatabaseEntry value = new DatabaseEntry(); Transaction txn; if (resumable) { txn = env.beginTransaction(null, null); } else { txn = null; } try { cursor = urlsDB.openCursor(txn, null); result = cursor.getFirst(key, value, null); while (matches < count && result == OperationStatus.SUCCESS) { cursor.delete(); matches++; result = cursor.getNext(key, value, null); } } catch (DatabaseException e) { if (txn != null) { txn.abort(); txn = null; } throw e; } finally { if (cursor != null) { cursor.close(); } if (txn != null) { txn.commit(); } } } }
/* * See SR11455 for details. * * This test is checking that the maxTxnId gets recovered properly during * recovery. The SR has to do with the INFileReader not including * DupCountLN_TX and DelDupLN_TX's in its txnIdTrackingMap. When these * were not included, it was possible for a transaction to consist solely * of DupCountLN_TX/DelDupLN_TX pairs. The "deleteData" transaction below * does just this. If no checkpoint occurred following such a transaction, * then the correct current txnid would not be written to the log and * determining this value during recovery would be left up to the * INFileReader. However, without reading the DupCountLN_TX/DelDupLN_TX * records, it would not recover the correct value. * * We take the poor man's way out of creating this situation by just * manually asserting the txn id is correct post-recovery. The txnid of 12 * was determined by looking through logs before and after the fix. */ public void testSR11455() throws Throwable { createEnvAndDbs(1 << 20, true, 1); int numRecs = 1; int nDups = 3; try { /* Set up an repository of expected data. */ Map<TestData, Set<TestData>> expectedData = new HashMap<TestData, Set<TestData>>(); /* Insert all the data. */ Transaction txn = env.beginTransaction(null, null); insertData(txn, 0, numRecs - 1, expectedData, nDups, true, 1); txn.commit(); txn = env.beginTransaction(null, null); /* Delete all the even records. */ deleteData(txn, expectedData, false, false, 1); txn.abort(); closeEnv(); /* Open it again, which will run recovery. */ EnvironmentConfig recoveryConfig = TestUtils.initEnvConfig(); recoveryConfig.setTransactional(true); recoveryConfig.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER.getName(), "false"); recoveryConfig.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false"); env = new Environment(envHome, recoveryConfig); txn = env.beginTransaction(null, null); assertEquals(6, txn.getId()); txn.commit(); env.close(); } catch (Throwable t) { t.printStackTrace(); throw t; } }
@Override public synchronized boolean trim(Long instance) { if (instance == 0) { return true; } // fast track Transaction t = null; if (db.getConfig().getTransactional()) { t = env.beginTransaction(null, null); } Cursor cursor = db.openCursor(t, null); boolean dirty = false; try { while (cursor.getNext(key, data, LockMode.READ_UNCOMMITTED) == OperationStatus.SUCCESS) { Long i = keyBinding.entryToObject(key); if (i < instance && cursor.delete() != OperationStatus.SUCCESS) { logger.error("Error deleting instance " + i + " from DB!"); dirty = true; } } } finally { cursor.close(); if (!dirty) { if (t != null) { t.commit(); } } else { if (t != null) { t.abort(); } return false; } } putDecision(-1L, new Decision(0, instance, 0, null)); logger.debug("DB deltete up to instance " + instance); return true; }
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; }
private void evolveIndex(Format format, EvolveEvent event, EvolveListener listener) throws DatabaseException { Class entityClass = format.getType(); String entityClassName = format.getClassName(); EntityMetadata meta = model.getEntityMetadata(entityClassName); String keyClassName = meta.getPrimaryKey().getClassName(); keyClassName = SimpleCatalog.keyClassName(keyClassName); DatabaseConfig dbConfig = getPrimaryConfig(meta); PrimaryIndex<Object, Object> index = getPrimaryIndex(Object.class, keyClassName, entityClass, entityClassName); Database db = index.getDatabase(); EntityBinding binding = index.getEntityBinding(); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); Cursor readCursor = db.openCursor(null, CursorConfig.READ_UNCOMMITTED); try { while (readCursor.getNext(key, data, null) == OperationStatus.SUCCESS) { if (evolveNeeded(key, data, binding)) { Transaction txn = null; if (dbConfig.getTransactional()) { boolean success = false; txn = env.beginTransaction(null, null); } boolean doCommit = false; Cursor writeCursor = null; try { writeCursor = db.openCursor(txn, null); if (writeCursor.getSearchKey(key, data, LockMode.RMW) == OperationStatus.SUCCESS) { boolean written = false; if (evolveNeeded(key, data, binding)) { writeCursor.putCurrent(data); written = true; } if (listener != null) { EvolveInternal.updateEvent(event, entityClassName, 1, written ? 1 : 0); if (!listener.evolveProgress(event)) { break; } } } } finally { if (writeCursor != null) { writeCursor.close(); } if (txn != null) { if (doCommit) { txn.commit(); } else { txn.abort(); } } } } } } finally { readCursor.close(); } }