Author: adriancole
Date: 2009-03-04 21:09:04 -0500 (Wed, 04 Mar 2009)
New Revision: 7854
Added:
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java
Modified:
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java
Log:
added test cases and cleaned code
Modified: core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java
===================================================================
---
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java 2009-03-05
00:23:55 UTC (rev 7853)
+++
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStore.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -1,11 +1,17 @@
package org.horizon.loader.bdbje;
-import com.sleepycat.bind.EntryBinding;
-import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.collections.CurrentTransaction;
import com.sleepycat.collections.StoredMap;
-import com.sleepycat.je.*;
+import com.sleepycat.je.Cursor;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.je.JEVersion;
+import com.sleepycat.je.OperationStatus;
+import com.sleepycat.je.Transaction;
import com.sleepycat.util.ExceptionUnwrapper;
import org.horizon.Cache;
import org.horizon.loader.AbstractCacheStore;
@@ -17,7 +23,6 @@
import org.horizon.logging.LogFactory;
import org.horizon.marshall.Marshaller;
import org.horizon.util.ReflectionUtil;
-import org.horizon.util.concurrent.WithinThreadExecutor;
import java.io.File;
import java.io.ObjectInput;
@@ -28,8 +33,6 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
/**
* An Oracle SleepyCat JE implementation of a {@link org.horizon.loader.CacheStore}.
<p/>This implementation uses two
@@ -62,34 +65,37 @@
private BdbjeCacheStoreConfig cfg;
private Cache cache;
- private Marshaller m;
private Environment env;
- private String cacheDbName;
- private String catalogDbName;
private StoredClassCatalog catalog;
private Database cacheDb;
private StoredMap<Object, StoredEntry> cacheMap;
private PreparableTransactionRunner transactionRunner;
private Map<javax.transaction.Transaction, Transaction> txnMap;
- private ExecutorService purgerService;
private CurrentTransaction currentTransaction;
+ private BdbjeResourceFactory factory;
/**
- * {@inheritDoc} This implementation expects config to be an instance of {@link
BdbjeCacheStoreConfig}
+ * {@inheritDoc} This implementation expects config to be an instance of {@link
BdbjeCacheStoreConfig} <p /> note
+ * that the <code>m</code> is not currently used as SleepyCat has its own
efficient solution.
*
* @see BdbjeCacheStoreConfig
*/
public void init(CacheLoaderConfig config, Cache cache, Marshaller m) {
+ BdbjeCacheStoreConfig cfg = (BdbjeCacheStoreConfig) config;
+ init(cfg, new BdbjeResourceFactory(cfg), cache);
+ }
+
+ public void init(BdbjeCacheStoreConfig cfg, BdbjeResourceFactory factory, Cache cache)
{
if (trace) log.trace("initializing BdbjeCacheStore");
printLicense();
- this.cfg = (BdbjeCacheStoreConfig) config;
+ super.init(cfg, cache, null);
+ this.cfg = cfg;
+ this.factory = factory;
this.cache = cache;
- this.m = m;
}
-
/**
* {@inheritDoc}
*
@@ -101,39 +107,49 @@
/**
* {@inheritDoc} Validates configuration, configures and opens the {@link
Environment}, then {@link
- * org.horizon.loader.bdbje.BdbjeCacheStore#openDatabases() opens the databases}.
When this is finished,
- * transactional services are instantiated.
+ * org.horizon.loader.bdbje.BdbjeCacheStore#openSleepyCatResources() opens the
databases}. When this is finished,
+ * transactional and purging services are instantiated.
*/
public void start() throws CacheLoaderException {
if (trace) log.trace("starting BdbjeCacheStore");
- checkNotOpen();
- if (cache == null) {
- throw new IllegalStateException(
- "A non-null Cache property (CacheSPI object) is required");
- }
+ openSleepyCatResources();
+ openTransactionServices();
+ super.start();
- String configStr = cfg.getLocation();
+ log.debug("started cache store {1}", this);
+ }
- if (cfg.isPurgeSynchronously()) {
- purgerService = new WithinThreadExecutor();
- } else {
- purgerService = Executors.newSingleThreadExecutor();
- }
+ private void openTransactionServices() {
+ txnMap = new ConcurrentHashMap<javax.transaction.Transaction,
Transaction>();
+ currentTransaction = factory.createCurrentTransaction(env);
+ transactionRunner = factory.createPreparableTransactionRunner(env);
+ }
- // JBCACHE-1448 db name parsing fix courtesy of Ciro Cavani
- /* Parse config string. */
- int offset = configStr.indexOf('#');
- if (offset >= 0 && offset < configStr.length() - 1) {
- cacheDbName = configStr.substring(offset + 1);
- configStr = configStr.substring(0, offset);
- } else {
- cacheDbName = cache.getName();
- if (cacheDbName == null) cacheDbName = "CacheInstance-" +
System.identityHashCode(cache);
+ /**
+ * Opens the SleepyCat environment and all databases. A {@link StoredMap} instance is
provided which persists the
+ * CacheStore.
+ */
+ private void openSleepyCatResources() throws CacheLoaderException {
+ if (trace) log.trace("creating je environment with home dir {0}",
cfg.getLocation());
+
+ if (cfg.getCacheDbName() == null) cfg.setCacheDbName(cache.getName());
+ if (cfg.getCatalogDbName() == null) cfg.setCatalogDbName(cfg.getCacheDbName() +
"_class_catalog");
+
+ File location = verifyOrCreateEnvironmentDirectory(new File(cfg.getLocation()));
+ try {
+ env = factory.createEnvironment(location);
+ cacheDb = factory.createDatabase(env, cfg.getCacheDbName());
+ Database catalogDb = factory.createDatabase(env, cfg.getCatalogDbName());
+ catalog = factory.createStoredClassCatalog(catalogDb);
+ cacheMap = factory.createStoredMapViewOfDatabase(cacheDb, catalog);
+ } catch (DatabaseException e) {
+ throw convertToCacheLoaderException("could not open sleepycat je
resource", e);
}
+ }
- // datafile location
- File location = new File(configStr);
+ // not private so that this can be unit tested
+ File verifyOrCreateEnvironmentDirectory(File location) throws CacheLoaderException {
if (!location.exists()) {
boolean created = location.mkdirs();
if (!created) throw new CacheLoaderException("Unable to create cache loader
location " + location);
@@ -142,120 +158,61 @@
if (!location.isDirectory()) {
throw new CacheLoaderException("Cache loader location [" + location +
"] is not a directory!");
}
-
- catalogDbName = cacheDbName + "_class_catalog";
-
- try {
- /* Open the environment, creating it if it doesn't exist. */
- EnvironmentConfig envConfig = new EnvironmentConfig();
- envConfig.setAllowCreate(true);
- envConfig.setTransactional(true);
- /* lock timeout is in microseconds */
- envConfig.setLockTimeout(cfg.getLockAcquistionTimeout() * 1000);
- if (log.isDebugEnabled()) {
- envConfig.setConfigParam("je.txn.deadlockStackTrace",
"true");
- envConfig.setConfigParam("je.txn.dumpLocks", "true");
- }
- if (trace) log.trace("creating je environment with home dir {0}",
location);
- env = new Environment(location, envConfig);
- log.debug("created je environment {0} for cache store {1}", env,
this);
- /* Open cache and catalog databases. */
- openDatabases();
- }
- catch (DatabaseException e) {
- throw new CacheLoaderException("could not open the sleepycat
database", e);
- }
- txnMap = new ConcurrentHashMap<javax.transaction.Transaction,
Transaction>();
- currentTransaction = CurrentTransaction.getInstance(env);
- transactionRunner = new PreparableTransactionRunner(env);
- transactionRunner.setMaxRetries(cfg.getMaxTxRetries());
- log.debug("started cache store {1}", this);
+ return location;
}
-
/**
- * Opens all databases and initializes database related information. A {@link
StoredMap} instance is {@link
- * BdbjeCacheStore#createStoredMapViewOfDatabase(com.sleepycat.je.Database,
com.sleepycat.bind.serial.StoredClassCatalog)
- * associated} with the stored entry and class catalog databases.
+ * Stops transaction and purge processing and closes the SleepyCat environment. The
environment and databases are
+ * not removed from the file system. Exceptions during close of databases are ignored
as closing the environment will
+ * ensure the databases are also.
*/
- private void openDatabases() throws DatabaseException {
- if (trace) log.trace("opening databases");
- /* Use a generic database config, with no duplicates allowed. */
- DatabaseConfig dbConfig = new DatabaseConfig();
- dbConfig.setTransactional(true);
- dbConfig.setAllowCreate(true);
+ public void stop() throws CacheLoaderException {
+ if (trace) log.trace("stopping BdbjeCacheStore");
+ super.stop();
+ closeTransactionServices();
+ closeSleepyCatResources();
+ log.debug("started cache store {1}", this);
+ }
- if (trace) log.trace("opening or creating stored entry database {0}",
cacheDbName);
- cacheDb = env.openDatabase(null, cacheDbName, dbConfig);
- log.debug("opened stored entry database {0}", cacheDbName);
-
- if (trace) log.trace("opening or creating class catalog database {0}",
catalogDbName);
- Database catalogDb = env.openDatabase(null, catalogDbName, dbConfig);
- catalog = new StoredClassCatalog(catalogDb);
- log.debug("created stored class catalog from database {0}",
catalogDbName);
-
- cacheMap = createStoredMapViewOfDatabase(cacheDb, catalog);
+ private void closeTransactionServices() {
+ transactionRunner = null;
+ currentTransaction = null;
+ txnMap = null;
}
- /**
- * create a {@link StoredMap} persisted by the <code>database</code>
- *
- * @param database where entries in the StoredMap are persisted
- * @param classCatalog location to store class descriptions
- * @return StoredMap backed by the database and classCatalog
- * @throws DatabaseException if the StoredMap cannot be opened.
- */
- private StoredMap createStoredMapViewOfDatabase(Database database, StoredClassCatalog
classCatalog) throws DatabaseException {
- EntryBinding storedEntryKeyBinding =
- new SerialBinding(classCatalog, Object.class);
- EntryBinding storedEntryValueBinding =
- new SerialBinding(classCatalog, StoredEntry.class);
- try {
- return new StoredMap<Object, StoredEntry>(database,
- storedEntryKeyBinding,
storedEntryValueBinding, true);
- } catch (Exception caught) {
- caught = ExceptionUnwrapper.unwrap(caught);
- throw new DatabaseException("error opening stored map", caught);
- }
+ private void closeSleepyCatResources() throws CacheLoaderException {
+ cacheMap = null;
+ closeDatabases();
+ closeEnvironment();
}
/**
- * Closes the JE databases and their associated {@link StoredMap}, and nulls
references to them. The databases are
- * not removed from the file system. Exceptions during close are ignored.
+ * Exceptions are ignored so that {@link
org.horizon.loader.bdbje.BdbjeCacheStore#closeEnvironment()} will execute.
*/
private void closeDatabases() {
if (trace) log.trace("closing databases");
try {
cacheDb.close();
+ } catch (Exception e) {
+ log.error("Error closing database", e);
+ }
+ try {
catalog.close();
- } catch (DatabaseException e) {
- log.error("Error closing databases", e);
+ } catch (Exception e) {
+ log.error("Error closing catalog", e);
}
- cacheDb = null;
- catalog = null;
cacheMap = null;
+ catalog = null;
+ cacheDb = null;
}
-
- /**
- * {@link org.horizon.loader.bdbje.BdbjeCacheStore#closeDatabases() Closes the JE
databases} and the {@link
- * Environment}. The environment and databases are not removed from the file system.
Exceptions during close are
- * ignored.
- */
- public void stop() throws CacheLoaderException {
- checkOpen();
- if (trace) log.trace("stopping BdbjeCacheStore");
- transactionRunner = null;
- currentTransaction = null;
- txnMap = null;
- closeDatabases();
+ private void closeEnvironment() throws CacheLoaderException {
if (env != null) {
try {
env.close();
+ } catch (DatabaseException e) {
+ throw new CacheLoaderException("Unexpected exception closing
cacheStore", e);
}
- catch (Exception shouldNotOccur) {
- log.warn("Unexpected exception closing cacheStore",
shouldNotOccur);
- }
}
env = null;
}
@@ -281,30 +238,27 @@
*/
@Override
protected void applyModifications(List<? extends Modification> mods) throws
CacheLoaderException {
- checkOpen();
- checkNonNull(mods, "modifications");
- log.debug("performing one phase transaction");
+ if (trace) log.trace("performing one phase transaction");
try {
transactionRunner.run(new ModificationsTransactionWorker(this, mods));
- } catch (Exception e) {
- throw new CacheLoaderException("Problem committing modifications: " +
mods, e);
+ } catch (Exception caught) {
+ throw convertToCacheLoaderException("Problem committing modifications:
" + mods, caught);
}
}
/**
* Looks up the {@link Transaction SleepyCat transaction} associated with
<code>tx</code>. Creates a {@link
* org.horizon.loader.bdbje.ModificationsTransactionWorker} instance from
<code>mods</code>. Then prepares the
- * transaction via {@link
PreparableTransactionRunner#prepare(com.sleepycat.collections.TransactionWorker)}.
+ * transaction via {@link
PreparableTransactionRunner#prepare(com.sleepycat.collections.TransactionWorker)}.
Finally,
+ * it invalidates {@link
com.sleepycat.collections.CurrentTransaction#getTransaction()} so that no other thread
can
+ * accidentally commit this.
*
* @param mods modifications to be applied
* @param tx transaction identifier
* @throws CacheLoaderException in the event of problems writing to the store
*/
protected void prepare(List<? extends Modification> mods,
javax.transaction.Transaction tx) throws CacheLoaderException {
- checkOpen();
- checkNonNull(mods, "modifications");
- checkNonNull(tx, "tx");
- log.debug("preparing transaction {0}", tx);
+ if (trace) log.trace("preparing transaction {0}", tx);
try {
transactionRunner.prepare(new ModificationsTransactionWorker(this, mods));
Transaction txn = currentTransaction.getTransaction();
@@ -312,7 +266,7 @@
txnMap.put(tx, txn);
ReflectionUtil.setValue(currentTransaction, "localTrans", new
ThreadLocal());
} catch (Exception e) {
- throw new CacheLoaderException("Problem preparing transaction", e);
+ throw convertToCacheLoaderException("Problem preparing transaction",
e);
}
}
@@ -343,26 +297,23 @@
/**
* Looks up the SleepyCat transaction associated with the parameter
<code>tx</code>. If there is no associated
- * sleepycat transaction, an error is logged. If this transaction is the {@link
- * com.sleepycat.collections.CurrentTransaction#getTransaction()} current
transaction}, it calls {@link
- * BdbjeCacheStore#completeCurrentTransaction(boolean)} passing the argument
<code>commit</code>. Otherwise, {@link
- * BdbjeCacheStore#completeTransaction(com.sleepycat.je.Transaction, boolean)
completeTransaction} is called, passing
- * the SleepyCat transaction and <code>commit</code> as arguments.
+ * sleepycat transaction, an error is logged.
*
* @param tx java transaction used to lookup a SleepyCat transaction
* @param commit true to commit false to abort
* @throws CacheLoaderException if there are problems committing or aborting the
transaction
*/
protected void completeTransaction(javax.transaction.Transaction tx, boolean commit)
throws CacheLoaderException {
- checkOpen();
- checkNonNull(tx, "tx");
Transaction txn = txnMap.remove(tx);
if (txn != null) {
- log.debug("transaction {0} == sleepycat transaction {1}", tx, txn);
- if (currentTransaction.getTransaction() == txn) {
- completeCurrentTransaction(commit);
- } else {
- completeTransaction(txn, commit);
+ if (trace) log.trace("{0} sleepycat transaction {1}", commit ?
"committing" : "aborting", txn);
+ try {
+ if (commit)
+ txn.commit();
+ else
+ txn.abort();
+ } catch (Exception caught) {
+ throw convertToCacheLoaderException("Problem completing
transaction", caught);
}
} else {
if (trace) log.trace("no sleepycat transaction associated transaction
{0}", tx);
@@ -370,24 +321,6 @@
}
/**
- * commits or aborts the {@link Transaction}
- *
- * @param commit true to commit, false to abort
- * @throws CacheLoaderException if there was a problem completing the transaction
- */
- private void completeTransaction(Transaction txn, boolean commit) throws
CacheLoaderException {
- try {
- log.debug("{0} sleepycat transaction {1}", commit ?
"committing" : "aborting", txn);
- if (commit)
- txn.commit();
- else
- txn.abort();
- } catch (DatabaseException e) {
- throw new CacheLoaderException("Problem completing transaction", e);
- }
- }
-
- /**
* commits or aborts the {@link
com.sleepycat.collections.CurrentTransaction#getTransaction() current transaction}
*
* @param commit true to commit, false to abort
@@ -395,13 +328,14 @@
*/
private void completeCurrentTransaction(boolean commit) throws CacheLoaderException {
try {
- log.debug("{0} current sleepycat transaction {1}", commit ?
"committing" : "aborting", currentTransaction.getTransaction());
+ if (trace)
+ log.trace("{0} current sleepycat transaction {1}", commit ?
"committing" : "aborting", currentTransaction.getTransaction());
if (commit)
currentTransaction.commitTransaction();
else
currentTransaction.abortTransaction();
- } catch (DatabaseException e) {
- throw new CacheLoaderException("Problem completing transaction", e);
+ } catch (Exception caught) {
+ throw convertToCacheLoaderException("Problem completing transaction",
caught);
}
}
@@ -409,19 +343,15 @@
* {@inheritDoc} This implementation delegates to {@link StoredMap#remove(Object)}
*/
public boolean remove(Object key) throws CacheLoaderException {
- checkOpen();
- checkNonNull(key, "key");
- if (trace) log.trace("Removing key {0}", key);
try {
if (cacheMap.containsKey(key)) {
cacheMap.remove(key);
return true;
}
- } catch (Exception caught) {
- caught = ExceptionUnwrapper.unwrap(caught);
- throw new CacheLoaderException("error removing key " + key, caught);
+ return false;
+ } catch (RuntimeException caught) {
+ throw convertToCacheLoaderException("error removing key " + key,
caught);
}
- return false;
}
/**
@@ -429,36 +359,26 @@
* not be returned.
*/
public StoredEntry load(Object key) throws CacheLoaderException {
- checkOpen();
- checkNonNull(key, "key");
- if (trace) log.trace("Loading key {0}", key);
try {
StoredEntry s = cacheMap.get(key);
- if (s == null)
- return null;
- if (!s.isExpired())
- return s;
- else
+ if (s != null && s.isExpired()) {
cacheMap.remove(key);
- } catch (Exception caught) {
- caught = ExceptionUnwrapper.unwrap(caught);
- throw new CacheLoaderException("error loading key " + key, caught);
+ s = null;
+ }
+ return s;
+ } catch (RuntimeException caught) {
+ throw convertToCacheLoaderException("error loading key " + key,
caught);
}
- return null;
}
/**
* {@inheritDoc} This implementation delegates to {@link StoredMap#put(Object,
Object)}
*/
public void store(StoredEntry ed) throws CacheLoaderException {
- checkOpen();
- checkNonNull(ed, "entry");
- if (trace) log.trace("Storing entry {0}", ed);
try {
cacheMap.put(ed.getKey(), ed);
- } catch (Exception caught) {
- caught = ExceptionUnwrapper.unwrap(caught);
- throw new CacheLoaderException("error storing entry " + ed, caught);
+ } catch (RuntimeException caught) {
+ throw convertToCacheLoaderException("error storing entry " + ed,
caught);
}
}
@@ -466,11 +386,10 @@
* {@inheritDoc} This implementation delegates to {@link StoredMap#clear()}
*/
public void clear() throws CacheLoaderException {
- checkOpen();
- if (trace) log.trace("Clearing store");
- try {cacheMap.clear(); } catch (Exception caught) {
- caught = ExceptionUnwrapper.unwrap(caught);
- throw new CacheLoaderException("error clearing store", caught);
+ try {
+ cacheMap.clear();
+ } catch (RuntimeException caught) {
+ throw convertToCacheLoaderException("error clearing store", caught);
}
}
@@ -478,13 +397,10 @@
* {@inheritDoc} This implementation returns a Set from {@link StoredMap#values()}
*/
public Set<StoredEntry> loadAll() throws CacheLoaderException {
- checkOpen();
- if (trace) log.trace("Loading all entries");
try {
return new HashSet(cacheMap.values());
- } catch (Exception caught) {
- caught = ExceptionUnwrapper.unwrap(caught);
- throw new CacheLoaderException("error loading all entries ", caught);
+ } catch (RuntimeException caught) {
+ throw convertToCacheLoaderException("error loading all entries",
caught);
}
}
@@ -497,13 +413,10 @@
* @see BdbjeCacheStore#toStream(java.io.ObjectOutput)
*/
public void fromStream(ObjectInput ois) throws CacheLoaderException {
- checkOpen();
- log.info("Clearing all entries and loading from input");
try {
long recordCount = ois.readLong();
- log.info("reading {0} records from stream", recordCount);
- log.info("clearing all records");
currentTransaction.beginTransaction(null);
+ log.debug("clearing and reading {0} records from stream",
recordCount);
cacheMap.clear();
Cursor cursor = null;
try {
@@ -520,13 +433,10 @@
if (cursor != null) cursor.close();
}
completeCurrentTransaction(true);
- }
- catch (Exception caught) {
+ } catch (Exception caught) {
completeCurrentTransaction(false);
- caught = ExceptionUnwrapper.unwrap(caught);
- CacheLoaderException cle = (caught instanceof CacheLoaderException) ?
(CacheLoaderException) caught :
- new CacheLoaderException("Problems reading from stream",
caught);
- throw cle;
+ clear();
+ throw convertToCacheLoaderException("Problems reading from stream",
caught);
}
}
@@ -537,103 +447,69 @@
* This implementation holds a transaction open to ensure that we see no new records
added while iterating.
*/
public void toStream(ObjectOutput oos) throws CacheLoaderException {
- checkOpen();
- if (trace) log.trace("dumping current database to outputstream");
- Cursor cursor = null;
try {
currentTransaction.beginTransaction(null);
long recordCount = cacheDb.count();
- log.debug("writing {0} records to stream", recordCount);
+ if (trace) log.trace("writing {0} records to stream", recordCount);
oos.writeLong(recordCount);
-
- cursor = cacheDb.openCursor(currentTransaction.getTransaction(), null);
- DatabaseEntry key = new DatabaseEntry();
- DatabaseEntry data = new DatabaseEntry();
- int recordsWritten = 0;
- while (cursor.getNext(key, data, null) ==
- OperationStatus.SUCCESS) {
- oos.writeObject(key.getData());
- oos.writeObject(data.getData());
- recordsWritten++;
- }
- log.debug("wrote {0} records to stream", recordsWritten);
- if (recordsWritten != recordCount)
- log.warn("expected to write {0} records, but wrote {1}",
recordCount, recordsWritten);
- cursor.close();
- cursor = null;
- currentTransaction.commitTransaction();
- } catch (Exception caught) {
+ Cursor cursor = null;
try {
- currentTransaction.abortTransaction();
- } catch (DatabaseException e) {
- log.error("error aborting transaction", e);
+ cursor = cacheDb.openCursor(currentTransaction.getTransaction(), null);
+ DatabaseEntry key = new DatabaseEntry();
+ DatabaseEntry data = new DatabaseEntry();
+ int recordsWritten = 0;
+ while (cursor.getNext(key, data, null) ==
+ OperationStatus.SUCCESS) {
+ oos.writeObject(key.getData());
+ oos.writeObject(data.getData());
+ recordsWritten++;
+ }
+ if (trace) log.trace("wrote {0} records to stream",
recordsWritten);
+ if (recordsWritten != recordCount)
+ log.warn("expected to write {0} records, but wrote {1}",
recordCount, recordsWritten);
+ } finally {
+ if (cursor != null) cursor.close();
}
- caught = ExceptionUnwrapper.unwrap(caught);
- CacheLoaderException cle = (caught instanceof CacheLoaderException) ?
(CacheLoaderException) caught :
- new CacheLoaderException("Problems writing to stream", caught);
- throw cle;
+ completeCurrentTransaction(true);
+ } catch (Exception caught) {
+ completeCurrentTransaction(false);
+ throw convertToCacheLoaderException("Problems writing to stream",
caught);
}
- finally {
- if (cursor != null) try {
- cursor.close();
- } catch (DatabaseException e) {
- throw new CacheLoaderException("Error closing cursor", e);
- }
- }
}
/**
- * {@inheritDoc} If there is a {@link
com.sleepycat.collections.CurrentTransaction#getTransaction() transaction in
- * progress}, this method will invoke {@link #doPurgeExpired()} Otherwise, it will
purge expired entries,
- * autocommitting each.
+ * In order to adhere to APIs which do not throw checked exceptions, BDBJE wraps IO
and DatabaseExceptions inside
+ * RuntimeExceptions. These special Exceptions implement {@link
com.sleepycat.util.ExceptionWrapper}. This method
+ * will look for any of that type of Exception and encapsulate it into a
CacheLoaderException. In doing so, the real
+ * root cause can be obtained.
*
- * @see org.horizon.loader.bdbje.BdbjeCacheStoreConfig#isPurgeSynchronously()
- * @see org.horizon.loader.bdbje.BdbjeCacheStoreConfig#setMaxTxRetries(int)
+ * @param message what to attach to the CacheLoaderException
+ * @param caught exception to parse
+ * @return CacheLoaderException with the correct cause
*/
- public void purgeExpired() throws CacheLoaderException {
- checkOpen();
- if (currentTransaction.getTransaction() != null) {
- doPurgeExpired();
- } else {
- purgerService.execute(new Runnable() {
- public void run() {
- try {
- doPurgeExpired();
- } catch (Exception e) {
- log.error("error purging expired entries", e);
- }
- }
- });
- }
+ CacheLoaderException convertToCacheLoaderException(String message, Exception caught)
{
+ caught = ExceptionUnwrapper.unwrap(caught);
+ return (caught instanceof CacheLoaderException) ? (CacheLoaderException) caught :
+ new CacheLoaderException(message, caught);
}
/**
* Iterate through {@link com.sleepycat.collections.StoredMap#entrySet()} and remove,
if expired.
*/
- private void doPurgeExpired() {
- log.info("purging expired from database");
- Iterator<Map.Entry<Object, StoredEntry>> i =
cacheMap.entrySet().iterator();
- while (i.hasNext()) {
- if (i.next().getValue().isExpired())
- i.remove();
+ @Override
+ protected void purgeInternal() throws CacheLoaderException {
+ try {
+ Iterator<Map.Entry<Object, StoredEntry>> i =
cacheMap.entrySet().iterator();
+ while (i.hasNext()) {
+ if (i.next().getValue().isExpired())
+ i.remove();
+ }
+ } catch (RuntimeException caught) {
+ throw convertToCacheLoaderException("error purging expired entries",
caught);
}
}
/**
- * @return the name of the SleepyCat database persisting this store
- */
- public String getCacheDbName() {
- return cacheDbName;
- }
-
- /**
- * @return the name of the SleepyCat database persisting the class information for
objects in this store
- */
- public String getCatalogDbName() {
- return catalogDbName;
- }
-
- /**
* prints terms of use for Berkeley DB JE
*/
public void printLicense() {
@@ -652,34 +528,4 @@
System.out.println(license);
}
- /**
- * Throws an exception if the environment is not open.
- */
- private void checkNotOpen() {
- if (env != null) {
- throw new IllegalStateException(
- "Operation not allowed after calling create()");
- }
- }
-
- /**
- * Throws an exception if the environment is not open.
- */
- private void checkOpen() {
- if (env == null) {
- throw new IllegalStateException(
- "Operation not allowed before calling create()");
- }
- }
-
- /**
- * Throws an exception if the parameter is null.
- */
- private void checkNonNull(Object param, String paramName) {
- if (param == null) {
- throw new NullPointerException(
- "Parameter must not be null: " + paramName);
- }
- }
-
}
Modified:
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java
===================================================================
---
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java 2009-03-05
00:23:55 UTC (rev 7853)
+++
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfig.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -1,30 +1,37 @@
package org.horizon.loader.bdbje;
-import org.horizon.loader.AbstractCacheLoaderConfig;
+import org.horizon.loader.AbstractCacheStoreConfig;
/**
* Configures {@link org.horizon.loader.bdbje.BdbjeCacheStore}. This allows you to tune
a number of characteristics of
* the {@link BdbjeCacheStore}.
* <p/>
* <ul> <li><tt>location</tt> - a location on disk where the
store can write internal files. This defaults to
- * <tt>Horizon-BdbjeCacheStore</tt> in the current working
directory.</li> <li><tt>purgeSynchronously</tt> - whether {@link
- * org.horizon.loader.CacheStore#purgeExpired()} calls happen synchronously or not. By
default, this is set to
- * <tt>false</tt>.</li>
<li><tt>lockAcquistionTimeout</tt> - the length of time, in
milliseconds, to wait for locks
+ * <tt>Horizon-BdbjeCacheStore</tt> in the current working
directory.</li> <li><tt>lockAcquistionTimeout</tt> - the length of
time, in milliseconds, to wait for locks
* before timing out and throwing an exception. By default, this is set to
<tt>60000</tt>.</li>
* <li><tt>maxTxRetries</tt> - the number of times transaction prepares
will attempt to resolve a deadlock before
- * throwing an exception. By default, this is set to <tt>5</tt>.</li>
</ul>
+ * throwing an exception. By default, this is set to <tt>5</tt>.</li>
+ * <p/>
+ * <li><tt>cacheDbName</tt> - the name of the SleepyCat database
persisting this store. This defaults to <tt>{@link
+ * org.horizon.Cache#getName()} cache#name}</tt>.</li>
<li><tt>catalogDbName</tt> - the name of the SleepyCat database
+ * persisting the class information for objects in this store. This defaults to
<tt>{@link org.horizon.Cache#getName()}
+ * cache#name}_class_catalog</tt>.</li>
+ * <p/>
+ * </ul>
*
+ * Please see {@link AbstractCacheStoreConfig} for more configuration parameters.
+ *
* @author Adrian Cole
* @version $Id: $
* @since 1.0
*/
-public class BdbjeCacheStoreConfig extends AbstractCacheLoaderConfig {
+public class BdbjeCacheStoreConfig extends AbstractCacheStoreConfig {
private String location = "Horizon-BdbjeCacheStore";
- private boolean purgeSynchronously;
private long lockAcquistionTimeout = 60 * 1000;
private int maxTxRetries = 5;
+ private String cacheDbName;
+ private String catalogDbName;
-
public BdbjeCacheStoreConfig() {
setClassName(BdbjeCacheStore.class.getName());
}
@@ -55,12 +62,21 @@
this.location = location;
}
- public boolean isPurgeSynchronously() {
- return purgeSynchronously;
+
+ public String getCacheDbName() {
+ return cacheDbName;
}
- public void setPurgeSynchronously(boolean purgeSynchronously) {
- this.purgeSynchronously = purgeSynchronously;
+ public void setCacheDbName(String cacheDbName) {
+ this.cacheDbName = cacheDbName;
}
+ public String getCatalogDbName() {
+ return catalogDbName;
+ }
+
+ public void setCatalogDbName(String catalogDbName) {
+ this.catalogDbName = catalogDbName;
+ }
+
}
Added:
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java
===================================================================
--- core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java
(rev 0)
+++
core/branches/flat/src/main/java/org/horizon/loader/bdbje/BdbjeResourceFactory.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -0,0 +1,107 @@
+package org.horizon.loader.bdbje;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.collections.CurrentTransaction;
+import com.sleepycat.collections.StoredMap;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.util.ExceptionUnwrapper;
+import org.horizon.loader.StoredEntry;
+import org.horizon.logging.Log;
+import org.horizon.logging.LogFactory;
+
+import java.io.File;
+
+/**
+ * Factory that assembles objects specific to the SleepyCat JE API.
+ *
+ * @author Adrian Cole
+ * @version $Id: $
+ * @since 1.0
+ */
+public class BdbjeResourceFactory {
+ private static final Log log = LogFactory.getLog(BdbjeResourceFactory.class);
+ private static final boolean trace = log.isTraceEnabled();
+
+ private BdbjeCacheStoreConfig config;
+
+ public BdbjeResourceFactory(BdbjeCacheStoreConfig config) {
+ this.config = config;
+ }
+
+ /**
+ * @return PreparableTransactionRunner that will try to resolve deadlocks maximum of
{@link BdbjeCacheStoreConfig#getMaxTxRetries()} times.
+ */
+ public PreparableTransactionRunner createPreparableTransactionRunner(Environment env)
{
+ return new PreparableTransactionRunner(env, config.getMaxTxRetries(), null);
+ }
+
+ public CurrentTransaction createCurrentTransaction(Environment env) {
+ return CurrentTransaction.getInstance(env);
+ }
+
+ /**
+ * Open the environment, creating it if it doesn't exist.
+ * @param envLocation base directory where the Environment will write files
+ * @return open Environment with a lock timeout of {@link
org.horizon.loader.bdbje.BdbjeCacheStoreConfig#getLockAcquistionTimeout()} milliseconds.
+ */
+ public Environment createEnvironment(File envLocation) throws DatabaseException {
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setAllowCreate(true);
+ envConfig.setTransactional(true);
+ /* lock timeout is in microseconds */
+ envConfig.setLockTimeout(config.getLockAcquistionTimeout() * 1000);
+ if (trace) log.trace("opening or creating je environment at {0}",
envLocation);
+ Environment env = new Environment(envLocation, envConfig);
+ log.debug("opened je environment at {0}", envLocation);
+ return env;
+ }
+
+ public StoredClassCatalog createStoredClassCatalog(Database catalogDb) throws
DatabaseException {
+ StoredClassCatalog catalog = new StoredClassCatalog(catalogDb);
+ log.debug("created stored class catalog from database {0}",
config.getCatalogDbName());
+ return catalog;
+ }
+
+ /**
+ * Open the database, creating it if it doesn't exist.
+ * @return open transactional Database
+ */
+ public Database createDatabase(Environment env, String name) throws DatabaseException
{
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ if (trace) log.trace("opening or creating database {0}", name);
+ Database db = env.openDatabase(null, name, dbConfig);
+ log.debug("opened database {0}", name);
+ return db;
+ }
+
+ /**
+ * create a {@link com.sleepycat.collections.StoredMap} persisted by the
<code>database</code>
+ *
+ * @param database where entries in the StoredMap are persisted
+ * @param classCatalog location to store class descriptions
+ * @return StoredMap backed by the database and classCatalog
+ * @throws com.sleepycat.je.DatabaseException
+ * if the StoredMap cannot be opened.
+ */
+ public StoredMap createStoredMapViewOfDatabase(Database database, StoredClassCatalog
classCatalog) throws DatabaseException {
+ EntryBinding storedEntryKeyBinding =
+ new SerialBinding(classCatalog, Object.class);
+ EntryBinding storedEntryValueBinding =
+ new SerialBinding(classCatalog, StoredEntry.class);
+ try {
+ return new StoredMap<Object, StoredEntry>(database,
+ storedEntryKeyBinding,
storedEntryValueBinding, true);
+ } catch (Exception caught) {
+ caught = ExceptionUnwrapper.unwrap(caught);
+ throw new DatabaseException("error opening stored map", caught);
+ }
+ }
+}
\ No newline at end of file
Modified:
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java
===================================================================
---
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java 2009-03-05
00:23:55 UTC (rev 7853)
+++
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreConfigTest.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -67,13 +67,15 @@
}
@Test
- public void testIsPurgeSynchronously() {
- assert !config.isPurgeSynchronously();
+ public void testSetCacheDb() {
+ config.setCacheDbName("foo");
+ assert config.getCacheDbName().equals("foo");
}
@Test
- public void testSetPurgeSynchronously() {
- config.setPurgeSynchronously(true);
- assert config.isPurgeSynchronously();
+ public void testSetCatalogDb() {
+ config.setCatalogDbName("foo");
+ assert config.getCatalogDbName().equals("foo");
}
+
}
Modified:
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java
===================================================================
---
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java 2009-03-05
00:23:55 UTC (rev 7853)
+++
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreIntegrationTest.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -23,6 +23,7 @@
*/
@Test(groups = "unit", enabled = true, testName =
"loader.bdbje.BdbjeCacheStoreIntegrationTest")
public class BdbjeCacheStoreIntegrationTest extends BaseCacheStoreTest {
+
protected CacheStore createCacheStore() throws CacheLoaderException {
CacheStore cs = new BdbjeCacheStore();
String tmpDir = TestingUtil.TEST_FILES;
Added: core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java
===================================================================
--- core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeCacheStoreTest.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -0,0 +1,358 @@
+package org.horizon.loader.bdbje;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.collections.CurrentTransaction;
+import com.sleepycat.collections.StoredMap;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.je.Cursor;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.util.RuntimeExceptionWrapper;
+import static org.easymock.classextension.EasyMock.*;
+import org.horizon.Cache;
+import org.horizon.loader.CacheLoaderException;
+import org.horizon.loader.StoredEntry;
+import org.horizon.loader.modifications.Store;
+import org.horizon.util.ReflectionUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+
+/**
+ * @author Adrian Cole
+ * @version $Id: $
+ * @since 1.0
+ */
+@Test(groups = "unit", enabled = true, testName =
"loader.bdbje.BdbjeCacheStoreTest")
+public class BdbjeCacheStoreTest {
+ private BdbjeCacheStore cs;
+ private BdbjeCacheStoreConfig cfg;
+ private BdbjeResourceFactory factory;
+ private Cache cache;
+ private Environment env;
+ private Database cacheDb;
+ private Database catalogDb;
+ private StoredClassCatalog catalog;
+ private StoredMap cacheMap;
+ private PreparableTransactionRunner runner;
+ private CurrentTransaction currentTransaction;
+
+ private class MockBdbjeResourceFactory extends BdbjeResourceFactory {
+
+ @Override
+ public PreparableTransactionRunner createPreparableTransactionRunner(Environment
env) {
+ return runner;
+ }
+
+ @Override
+ public CurrentTransaction createCurrentTransaction(Environment env) {
+ return currentTransaction;
+ }
+
+ @Override
+ public Environment createEnvironment(File envLocation) throws DatabaseException {
+ return env;
+ }
+
+ @Override
+ public StoredClassCatalog createStoredClassCatalog(Database catalogDb) throws
DatabaseException {
+ return catalog;
+ }
+
+ @Override
+ public Database createDatabase(Environment env, String name) throws
DatabaseException {
+ if (name.equals(cfg.getCacheDbName()))
+ return cacheDb;
+ else
+ return catalogDb;
+ }
+
+ @Override
+ public StoredMap createStoredMapViewOfDatabase(Database database,
StoredClassCatalog classCatalog) throws DatabaseException {
+ return cacheMap;
+ }
+
+ public MockBdbjeResourceFactory(BdbjeCacheStoreConfig config) {
+ super(config);
+ }
+ }
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+ cfg = new BdbjeCacheStoreConfig();
+ factory = new MockBdbjeResourceFactory(cfg);
+ cache = createMock(Cache.class);
+ cs = new BdbjeCacheStore();
+ env = createMock(Environment.class);
+ cacheDb = createMock(Database.class);
+ catalogDb = createMock(Database.class);
+ catalog = createMock(StoredClassCatalog.class);
+ cacheMap = createMock(StoredMap.class);
+ currentTransaction = createMock(CurrentTransaction.class);
+ WeakReference<Environment> envRef = new
WeakReference<Environment>(env);
+ ReflectionUtil.setValue(currentTransaction,"envRef",envRef);
+ ThreadLocal localTrans = new ThreadLocal();
+ ReflectionUtil.setValue(currentTransaction,"localTrans",localTrans);
+ runner = createMock(PreparableTransactionRunner.class);
+ }
+
+ @AfterMethod
+ public void tearDown() throws CacheLoaderException {
+ runner = null;
+ currentTransaction = null;
+ cacheMap = null;
+ catalogDb = null;
+ cacheDb = null;
+ env = null;
+ factory = null;
+ cache = null;
+ cfg = null;
+ cs = null;
+ }
+
+ void start() throws DatabaseException, CacheLoaderException {
+ cs.init(cfg, factory, cache);
+ expect(cache.getName()).andReturn("cache");
+ }
+
+ @Test
+ public void testGetConfigurationClass() throws Exception {
+ replayAll();
+ assert cs.getConfigurationClass().equals(BdbjeCacheStoreConfig.class);
+ verifyAll();
+ }
+
+ void replayAll() throws Exception {
+ replay(runner);
+ replay(currentTransaction);
+ replay(cacheMap);
+ replay(catalog);
+ replay(catalogDb);
+ replay(cacheDb);
+ replay(env);
+ replay(cache);
+ }
+
+ void verifyAll() throws Exception {
+ verify(runner);
+ verify(currentTransaction);
+ verify(cacheMap);
+ verify(catalog);
+ verify(catalogDb);
+ verify(env);
+ verify(cache);
+ }
+
+ @Test
+ public void testInitNoMock() throws Exception {
+ replayAll();
+ cs.init(cfg, cache, null);
+ assert cfg.equals(ReflectionUtil.getValue(cs, "cfg"));
+ assert cache.equals(ReflectionUtil.getValue(cs, "cache"));
+ assert ReflectionUtil.getValue(cs, "factory") instanceof
BdbjeResourceFactory;
+ verifyAll();
+ }
+
+ @Test
+ void testExceptionClosingCacheDatabaseDoesntPreventEnvironmentFromClosing() throws
Exception {
+ start();
+ cacheDb.close();
+ expectLastCall().andThrow(new DatabaseException());
+ catalog.close();
+ env.close();
+ replayAll();
+ cs.start();
+ cs.stop();
+
+ verifyAll();
+ }
+
+ @Test
+ void testExceptionClosingCatalogDoesntPreventEnvironmentFromClosing() throws Exception
{
+ start();
+ cacheDb.close();
+ catalog.close();
+ expectLastCall().andThrow(new DatabaseException());
+ env.close();
+ replayAll();
+ cs.start();
+ cs.stop();
+ verifyAll();
+ }
+
+ @Test(expectedExceptions = CacheLoaderException.class)
+ void testExceptionClosingEnvironment() throws Exception {
+ start();
+ cacheDb.close();
+ catalog.close();
+ env.close();
+ expectLastCall().andThrow(new DatabaseException());
+ replayAll();
+ cs.start();
+ cs.stop();
+ verifyAll();
+ }
+
+
+ @Test(expectedExceptions = CacheLoaderException.class)
+ void testThrowsCorrectExceptionOnStartForDatabaseException() throws Exception {
+ factory = new MockBdbjeResourceFactory(cfg) {
+ @Override
+ public StoredClassCatalog createStoredClassCatalog(Database catalogDb) throws
DatabaseException {
+ throw new DatabaseException();
+ }
+ };
+ start();
+ replayAll();
+ cs.start();
+
+ }
+
+ @Test(expectedExceptions = CacheLoaderException.class)
+ void testEnvironmentDirectoryExistsButNotAFile() throws Exception {
+ File file = createMock(File.class);
+ expect(file.exists()).andReturn(true);
+ expect(file.isDirectory()).andReturn(false);
+ replay(file);
+ cs.verifyOrCreateEnvironmentDirectory(file);
+ }
+
+ @Test(expectedExceptions = CacheLoaderException.class)
+ void testCantCreateEnvironmentDirectory() throws Exception {
+ File file = createMock(File.class);
+ expect(file.exists()).andReturn(false);
+ expect(file.mkdirs()).andReturn(false);
+ replay(file);
+ cs.verifyOrCreateEnvironmentDirectory(file);
+ }
+
+ @Test
+ void testCanCreateEnvironmentDirectory() throws Exception {
+ File file = createMock(File.class);
+ expect(file.exists()).andReturn(false);
+ expect(file.mkdirs()).andReturn(true);
+ expect(file.isDirectory()).andReturn(true);
+ replay(file);
+ assert file.equals(cs.verifyOrCreateEnvironmentDirectory(file));
+ }
+
+ @Test
+ public void testNoExceptionOnRollback() throws Exception {
+ start();
+ Transaction tx = createMock(Transaction.class);
+ replayAll();
+ cs.start();
+ cs.rollback(tx);
+ verifyAll();
+ }
+
+ @Test
+ protected void testApplyModificationsThrowsOriginalDatabaseException() throws
Exception {
+ start();
+ DatabaseException ex = new DatabaseException();
+ runner.run(isA(TransactionWorker.class));
+ expectLastCall().andThrow(new RuntimeExceptionWrapper(ex));
+ replayAll();
+ cs.start();
+ try {
+ cs.applyModifications(Collections.singletonList(new Store(new
StoredEntry("k", "v"))));
+ assert false : "should have gotten an exception";
+ } catch (CacheLoaderException e) {
+ assert ex.equals(e.getCause());
+ verifyAll();
+ return;
+ }
+ assert false : "should have returned";
+
+ }
+
+ @Test
+ protected void testCommitThrowsOriginalDatabaseException() throws Exception {
+ start();
+ DatabaseException ex = new DatabaseException();
+ com.sleepycat.je.Transaction txn = createMock(com.sleepycat.je.Transaction.class);
+ expect(currentTransaction.beginTransaction(null)).andReturn(txn);
+ runner.prepare(isA(TransactionWorker.class));
+ txn.commit();
+ expectLastCall().andThrow(new RuntimeExceptionWrapper(ex));
+ replayAll();
+ replay(txn);
+ cs.start();
+ try {
+ txn = currentTransaction.beginTransaction(null);
+ Transaction t = createMock(Transaction.class);
+ cs.prepare(Collections.singletonList(new Store(new StoredEntry("k",
"v"))), t,false);
+ cs.commit(t);
+ assert false : "should have gotten an exception";
+ } catch (CacheLoaderException e) {
+ assert ex.equals(e.getCause());
+ verifyAll();
+ return;
+ }
+ assert false : "should have returned";
+
+ }
+
+ @Test
+ protected void testPrepareThrowsOriginalDatabaseException() throws Exception {
+ start();
+ DatabaseException ex = new DatabaseException();
+ runner.prepare(isA(TransactionWorker.class));
+ expectLastCall().andThrow(new RuntimeExceptionWrapper(ex));
+ replayAll();
+ cs.start();
+ try {
+ cs.prepare(Collections.singletonList(new Store(new StoredEntry("k",
"v"))), createMock(Transaction.class),false);
+ assert false : "should have gotten an exception";
+ } catch (CacheLoaderException e) {
+ assert ex.equals(e.getCause());
+ verifyAll();
+ return;
+ }
+ assert false : "should have returned";
+
+ }
+
+ @Test
+ void testClearOnAbortFromStream() throws Exception {
+ start();
+ StoredEntry entry = new StoredEntry();
+ expect(cacheMap.put(entry.getKey(), entry)).andReturn(null);
+ ObjectInput ois = createMock(ObjectInput.class);
+ expect(ois.readLong()).andReturn(new Long(1));
+ com.sleepycat.je.Transaction txn = createMock(
com.sleepycat.je.Transaction.class);
+ expect(currentTransaction.beginTransaction(null)).andReturn(txn);
+ cacheMap.clear();
+ Cursor cursor = createMock(Cursor.class);
+ expect(cacheDb.openCursor(txn, null)).andReturn(cursor);
+ IOException ex = new IOException();
+ expect(ois.readObject()).andReturn(new byte[0]);
+ expectLastCall().andThrow(ex);
+ txn.abort();
+ cacheMap.clear();
+ replay(ois);
+ replay(txn);
+ replayAll();
+ cs.start();
+ try {
+ cs.store(entry);
+ cs.fromStream(ois);
+ assert false : "should have gotten an exception";
+ } catch (CacheLoaderException e) {
+ assert ex.equals(e.getCause());
+ verifyAll();
+ verify(ois);
+ verify(txn);
+ return;
+ }
+ assert false : "should have returned";
+ }
+}
Modified:
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java
===================================================================
---
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java 2009-03-05
00:23:55 UTC (rev 7853)
+++
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeLearningTest.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -662,6 +662,7 @@
assert expected.isEmpty();
}
+ @Test (enabled = false)
public void testConcurrency() throws Throwable {
int numThreads = 3;
final int loops = 500;
Added:
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java
===================================================================
---
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/horizon/loader/bdbje/BdbjeResourceFactoryTest.java 2009-03-05
02:09:04 UTC (rev 7854)
@@ -0,0 +1,48 @@
+package org.horizon.loader.bdbje;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import static org.easymock.classextension.EasyMock.createMock;
+import org.horizon.loader.CacheLoaderException;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ * @version $Id: $
+ * @since 1.0
+ */
+@Test(groups = "unit", enabled = true, testName =
"loader.bdbje.BdbjeResourceFactoryTest")
+public class BdbjeResourceFactoryTest {
+ private BdbjeCacheStoreConfig cfg;
+ private Environment env;
+ private BdbjeResourceFactory factory;
+ private Database cacheDb;
+ private StoredClassCatalog catalog;
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+ cfg = new BdbjeCacheStoreConfig();
+ factory = new BdbjeResourceFactory(cfg);
+ env = createMock(Environment.class);
+ cacheDb = createMock(Database.class);
+ catalog = createMock(StoredClassCatalog.class);
+ }
+
+ @AfterMethod
+ public void tearDown() throws CacheLoaderException {
+ env = null;
+ factory = null;
+ cfg = null;
+ cacheDb = null;
+ catalog = null;
+ }
+
+ @Test(expectedExceptions = DatabaseException.class)
+ public void testCreateStoredMapViewOfDatabaseThrowsException() throws
DatabaseException {
+ factory.createStoredMapViewOfDatabase(cacheDb, catalog);
+ }
+}