Author: manik.surtani(a)jboss.com
Date: 2008-10-10 05:43:27 -0400 (Fri, 10 Oct 2008)
New Revision: 6901
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java
Modified:
core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java
core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java
core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java
core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java
core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java
core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java
core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java
Log:
Fixed stuff
Modified:
core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -21,6 +21,9 @@
*/
package org.jboss.cache.transaction;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.InvalidTransactionException;
@@ -41,6 +44,8 @@
{
static ThreadLocal<Transaction> thread_local = new
ThreadLocal<Transaction>();
private static final long serialVersionUID = -6716097342564237376l;
+ private static final Log log = LogFactory.getLog(DummyBaseTransactionManager.class);
+ private static final boolean trace = log.isTraceEnabled();
/**
* Starts a new transaction, and associate it with the calling thread.
@@ -214,6 +219,7 @@
{
Transaction retval = getTransaction();
setTransaction(null);
+ if (trace) log.trace("Suspending tx " + retval);
return retval;
}
@@ -233,6 +239,7 @@
*/
public void resume(Transaction tx) throws InvalidTransactionException,
IllegalStateException, SystemException
{
+ if (trace) log.trace("Resuming tx " + tx);
setTransaction(tx);
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -76,4 +76,12 @@
{
return (key != null ? key.hashCode() : 0);
}
+
+
+ public String toString()
+ {
+ return getClass().getSimpleName() + "{" +
+ "key=" + key +
+ '}';
+ }
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -61,7 +61,7 @@
MVCCEntry entry = ctx.lookupEntry(key);
if (entry == null || entry.isNullEntry())
{
- if (trace) log.trace("Node not found");
+ if (trace) log.trace("Entry not found");
return null;
}
if (entry.isDeleted())
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -62,12 +62,4 @@
{
return METHOD_ID;
}
-
-
- public String toString()
- {
- return "AbstractDataCommand{" +
- "key=" + key +
- '}';
- }
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -79,7 +79,7 @@
MVCCEntry mvccEntry;
if (forceWriteLock)
{
- if (trace) log.trace("Forcing lock on reading key " + key);
+ if (trace) log.trace("Forcing lock on reading");
return wrapEntryForWriting(ctx, key, false, false);
}
else if ((mvccEntry = ctx.lookupEntry(key)) == null)
@@ -88,12 +88,12 @@
// simple implementation. Peek the node, wrap it, put wrapped node in the
context.
Object value = container.get(key);
mvccEntry = entryFactory.createWrappedEntry(key, value, false);
- if (mvccEntry != null && putInContext) ctx.putLookedUpEntry(mvccEntry);
+ if (mvccEntry != null && putInContext) ctx.putLookedUpEntry(key,
mvccEntry);
return mvccEntry;
}
else
{
- if (trace) log.trace("Key " + key + " is already in
context.");
+ if (trace) log.trace("Key is already in context");
return mvccEntry;
}
}
@@ -110,7 +110,7 @@
// create a copy of the underlying node
mvccEntry.copyForUpdate(container, writeSkewCheck);
}
- if (trace) log.trace("Retrieving wrapped node " + key);
+ if (trace) log.trace("Exists in context.");
if (mvccEntry.isDeleted() && createIfAbsent)
{
if (trace) log.trace("Node is deleted in current scope. Need to
un-delete.");
@@ -124,21 +124,23 @@
Object value = container.get(key);
if (value != null)
{
+ if (trace) log.trace("Retrieved from container.");
// exists in cache! Just acquire lock if needed, and wrap.
// do we need a lock?
boolean needToCopy = false;
if (acquireLock(ctx, key)) needToCopy = true;
mvccEntry = entryFactory.createWrappedEntry(key, value, false);
- ctx.putLookedUpEntry(mvccEntry);
+ ctx.putLookedUpEntry(key, mvccEntry);
if (needToCopy) mvccEntry.copyForUpdate(container, writeSkewCheck);
}
else if (createIfAbsent) // else, do we need to create one?
{
+ if (trace) log.trace("Creating new entry.");
// now to lock and create the node. Lock first to prevent concurrent
creation!
acquireLock(ctx, key);
mvccEntry = entryFactory.createWrappedEntry(key, value, true);
mvccEntry.setCreated(true);
- ctx.putLookedUpEntry(mvccEntry);
+ ctx.putLookedUpEntry(key, mvccEntry);
mvccEntry.copyForUpdate(container, writeSkewCheck);
}
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -202,4 +202,17 @@
else
unsetFlag(DELETED);
}
+
+ public String toString()
+ {
+ return getClass().getSimpleName() + "(" + System.identityHashCode(this) +
"){" +
+ "key=" + key +
+ ", value=" + value +
+ ", oldValue=" + oldValue +
+ ", isCreated=" + isCreated() +
+ ", isChanged=" + isChanged() +
+ ", isDeleted=" + isDeleted() +
+ ", isValid=" + isValid() +
+ '}';
+ }
}
\ No newline at end of file
Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -24,7 +24,6 @@
import org.jboss.starobrno.container.MVCCEntry;
import java.util.Map;
-import java.util.Set;
/**
* // TODO: MANIK: Document this
@@ -38,9 +37,9 @@
Map<Object, MVCCEntry> getLookedUpEntries();
- void putLookedUpEntry(MVCCEntry e);
+ void putLookedUpEntry(Object key, MVCCEntry e);
- void putLookedUpEntries(Set<MVCCEntry> lookedUpEntries);
+ void putLookedUpEntries(Map<Object, MVCCEntry> lookedUpEntries);
void clearLookedUpEntries();
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -21,7 +21,6 @@
*/
package org.jboss.starobrno.context;
-import org.jboss.starobrno.commands.VisitableCommand;
import org.jboss.starobrno.config.Option;
import org.jboss.starobrno.transaction.GlobalTransaction;
@@ -84,10 +83,6 @@
long getLockAcquisitionTimeout(long timeout);
- void setCommand(VisitableCommand cacheCommand);
-
- VisitableCommand getCommand();
-
boolean isValidTransaction();
void throwIfNeeded(Throwable e) throws Throwable;
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -24,7 +24,6 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.util.Immutables;
-import org.jboss.starobrno.commands.VisitableCommand;
import org.jboss.starobrno.config.Option;
import org.jboss.starobrno.container.MVCCEntry;
import org.jboss.starobrno.transaction.GlobalTransaction;
@@ -36,7 +35,6 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* // TODO: MANIK: Document this
@@ -51,13 +49,11 @@
private Transaction transaction;
private GlobalTransaction globalTransaction;
- protected TransactionContext transactionContext;
+ protected volatile TransactionContext transactionContext;
private Option optionOverrides;
// defaults to true.
private boolean originLocal = true;
private boolean localRollbackOnly;
- @Deprecated
- private VisitableCommand command;
/**
* LinkedHashSet of locks acquired by the invocation. We use a LinkedHashSet because
we need efficient Set semantics
@@ -80,8 +76,14 @@
*/
public MVCCEntry lookupEntry(Object k)
{
- if (transactionContext != null) return transactionContext.lookupEntry(k);
- return lookedUpEntries == null ? null : lookedUpEntries.get(k);
+ if (transactionContext != null)
+ {
+ return transactionContext.lookupEntry(k);
+ }
+ else
+ {
+ return lookedUpEntries == null ? null : lookedUpEntries.get(k);
+ }
}
/**
@@ -90,21 +92,20 @@
* If a transaction is in progress, implementations should delegate to {@link
org.jboss.cache.transaction.MVCCTransactionContext#putLookedUpNode(Fqn, NodeSPI)}
* <p/>
*
- * @param f fqn to add
- * @param n node to add
+ * @param key
*/
- public void putLookedUpEntry(MVCCEntry e)
+ public void putLookedUpEntry(Object key, MVCCEntry e)
{
if (transactionContext != null)
- transactionContext.putLookedUpEntry(e);
+ transactionContext.putLookedUpEntry(key, e);
else
{
if (lookedUpEntries == null) lookedUpEntries = new HashMap<Object,
MVCCEntry>(4);
- lookedUpEntries.put(e.getKey(), e);
+ lookedUpEntries.put(key, e);
}
}
- public void putLookedUpEntries(Set<MVCCEntry> lookedUpEntries)
+ public void putLookedUpEntries(Map<Object, MVCCEntry> lookedUpEntries)
{
if (transactionContext != null)
transactionContext.putLookedUpEntries(lookedUpEntries);
@@ -113,20 +114,15 @@
if (this.lookedUpEntries == null)
this.lookedUpEntries = new HashMap<Object, MVCCEntry>();
- for (MVCCEntry e : lookedUpEntries) this.lookedUpEntries.put(e.getKey(), e);
+ this.lookedUpEntries.putAll(lookedUpEntries);
}
}
/**
* Clears the registry of looked up nodes.
- * <p/>
- * If a transaction is in progress, implementations should delegate to {@link
org.jboss.cache.transaction.MVCCTransactionContext#clearLookedUpNodes()}.
*/
public void clearLookedUpEntries()
{
-// if (transactionContext != null)
-// transactionContext.clearLookedUpEntries();
-// else if (lookedUpEntries != null) lookedUpEntries.clear();
if (lookedUpEntries != null) lookedUpEntries.clear();
}
@@ -452,7 +448,6 @@
optionOverrides = null;
originLocal = true;
invocationLocks = null;
- command = null;
if (lookedUpEntries != null)
{
lookedUpEntries.clear();
@@ -498,31 +493,6 @@
}
/**
- * This is only used for backward compatibility with old interceptors implementation
and should <b>NOT</b> be
- * use by any new custom interceptors. The commands is now passed in as the second
param in each implementing
- * handlers (handler = method in ChainedInterceptor class)
- *
- * @param cacheCommand command to set
- */
- @Deprecated
- @SuppressWarnings("deprecation")
- public void setCommand(VisitableCommand cacheCommand)
- {
- this.command = cacheCommand;
- }
-
- /**
- * @return command that is in scope
- * @see #setCommand(org.jboss.cache.commands.VisitableCommand)
- */
- @Deprecated
- @SuppressWarnings("deprecation")
- public VisitableCommand getCommand()
- {
- return command;
- }
-
- /**
* @return true if there is current transaction associated with the invocation, and
this transaction is in a valid state.
*/
public boolean isValidTransaction()
@@ -555,7 +525,6 @@
protected void doCopy(InvocationContext c)
{
InvocationContextImpl copy = (InvocationContextImpl) c;
- copy.command = command;
copy.globalTransaction = globalTransaction;
copy.invocationLocks = invocationLocks == null ? null : new
LinkedHashSet(invocationLocks);
copy.localRollbackOnly = localRollbackOnly;
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -37,7 +37,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* A transaction context specially geared to dealing with MVCC.
@@ -116,12 +115,11 @@
* would delegate to this method if a transaction is in scope.
* <p/>
*
- * @param f fqn to add
- * @param n node to add
+ * @param key
*/
- public void putLookedUpEntry(MVCCEntry entry)
+ public void putLookedUpEntry(Object key, MVCCEntry entry)
{
- lookedUpEntries.put(entry.getKey(), entry);
+ lookedUpEntries.put(key, entry);
}
/**
@@ -162,9 +160,9 @@
lookedUpEntries.clear();
}
- public void putLookedUpEntries(Set<MVCCEntry> entries)
+ public void putLookedUpEntries(Map<Object, MVCCEntry> entries)
{
- for (MVCCEntry e : entries) lookedUpEntries.put(e.getKey(), e);
+ lookedUpEntries.putAll(entries);
}
public void addModification(VisitableCommand command)
@@ -291,7 +289,7 @@
public String toString()
{
StringBuilder sb = new StringBuilder();
- sb.append("TransactionEntry\nmodificationList:
").append(modificationList);
+ sb.append("TransactionContext (" + System.identityHashCode(this) +
") nmodificationList: ").append(modificationList);
return sb.toString();
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -259,7 +259,6 @@
@SuppressWarnings("deprecation")
public Object invoke(InvocationContext ctx, VisitableCommand command)
{
- ctx.setCommand(command);
try
{
return command.acceptVisitor(ctx, firstInChain);
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -60,7 +60,7 @@
@Override
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand
command) throws Throwable
{
- return handleAll(ctx, command, ctx.getGlobalTransaction(), false);
+ return handleAll(ctx, command, ctx.getGlobalTransaction(), true);
}
@Override
@@ -102,7 +102,7 @@
@Override
public Object handleDefault(InvocationContext ctx, VisitableCommand command) throws
Throwable
{
- return handleAll(ctx, command, null, false);
+ return handleAll(ctx, command, null, true);
}
@SuppressWarnings("deprecation")
@@ -199,9 +199,6 @@
}
}
- // reset the context to prevent leakage of internals
- ctx.setCommand(null);
-
// TODO: Calling ctx.reset() here breaks stuff. Check whether this is just
becuse UTs expect stuff in the ctx or whether this really breaks functionality.
// ctx.reset();
// instead, for now, just wipe contents of the looked up node map
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -226,7 +226,7 @@
Set<Object> keysToRemove = new HashSet<Object>();
for (MVCCEntry e : ctx.getLookedUpEntries().values())
{
- if (e.isChanged()) keysToRemove.add(e.getKey());
+ if (!e.isChanged()) keysToRemove.add(e.getKey());
}
for (Object k : keysToRemove) ctx.removeKeyLocked(k);
}
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -482,16 +482,7 @@
{
GlobalTransaction gtx = ctx.getGlobalTransaction();
Object result;
- VisitableCommand originalCommand = ctx.getCommand();
- ctx.setCommand(command);
- try
- {
- result = invokeNextInterceptor(ctx, command);
- }
- finally
- {
- ctx.setCommand(originalCommand);
- }
+ result = invokeNextInterceptor(ctx, command);
if (log.isDebugEnabled()) log.debug("Finished local commit/rollback method for
" + gtx);
return result;
}
@@ -605,16 +596,7 @@
Transaction currentTransaction = txManager.getTransaction();
if (currentTransaction != null && ltx != null &&
currentTransaction.equals(ltx))
{
- VisitableCommand originalCommand = ctx.getCommand();
- ctx.setCommand(prepareCommand);
- try
- {
- result = invokeNextInterceptor(ctx, prepareCommand);
- }
- finally
- {
- ctx.setCommand(originalCommand);
- }
+ result = invokeNextInterceptor(ctx, prepareCommand);
}
else
{
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java 2008-10-10
08:18:13 UTC (rev 6900)
+++
core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -35,7 +35,6 @@
import org.jboss.starobrno.CacheException;
import org.jboss.starobrno.CacheSPI;
import org.jboss.starobrno.config.Configuration;
-import org.jboss.starobrno.container.MVCCEntry;
import org.jboss.starobrno.context.InvocationContext;
import org.jboss.starobrno.factories.annotations.Destroy;
import org.jboss.starobrno.factories.annotations.Inject;
@@ -638,10 +637,7 @@
{
InvocationContext currentIC = cache.getInvocationContext();
backup.clearLookedUpEntries();
- for (MVCCEntry me : currentIC.getLookedUpEntries().values())
- {
- backup.putLookedUpEntry(me);
- }
+ backup.putLookedUpEntries(currentIC.getLookedUpEntries());
cache.setInvocationContext(backup);
}
@@ -658,10 +654,7 @@
cache.setInvocationContext(null);
// get a new Invocation Context
InvocationContext newContext = cache.getInvocationContext();
- for (MVCCEntry me : ctx.getLookedUpEntries().values())
- {
- newContext.putLookedUpEntry(me);
- }
+ newContext.putLookedUpEntries(ctx.getLookedUpEntries());
return ctx;
}
Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
(rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,154 @@
+package org.jboss.starobrno.api;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.transaction.GenericTransactionManagerLookup;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.ConfigurationException;
+import org.jboss.starobrno.util.TestingUtil;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests the {@link org.jboss.cache.Cache} public API at a high level
+ *
+ * @author <a href="mailto:manik@jboss.org">Manik Surtani</a>
+ */
+
+@Test(groups = {"functional", "pessimistic"})
+public class CacheAPITest
+{
+ private CacheSPI<String, String> cache;
+ final List<String> events = new ArrayList<String>();
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() throws Exception
+ {
+ // start a single cache instance
+ CacheFactory<String, String> cf = new DefaultCacheFactory<String,
String>();
+ cache = (CacheSPI<String, String>)
cf.createCache("configs/local-tx.xml", false);
+ cache.getConfiguration().setEvictionConfig(null);
+ configure(cache.getConfiguration());
+ cache.start();
+ events.clear();
+ }
+
+ protected void configure(Configuration c)
+ {
+ }
+
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown()
+ {
+ TestingUtil.killCaches(cache);
+ }
+
+ /**
+ * Tests that the configuration contains the values expected, as well as immutability
of certain elements
+ */
+ public void testConfiguration()
+ {
+ Configuration c = cache.getConfiguration();
+ assertEquals(Configuration.CacheMode.LOCAL, c.getCacheMode());
+ assertEquals(GenericTransactionManagerLookup.class.getName(),
c.getTransactionManagerLookupClass());
+
+ // note that certain values should be immutable. E.g., CacheMode cannot be changed
on the fly.
+ try
+ {
+ c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+ assert false : "Should have thrown an Exception";
+ }
+ catch (ConfigurationException e)
+ {
+ // expected
+ }
+
+ // others should be changeable though.
+ c.setLockAcquisitionTimeout(100);
+ }
+
+ public void testGetMembersInLocalMode()
+ {
+ assert cache.getRPCManager() == null : "Cache members should be null if
running in LOCAL mode";
+ }
+
+ /**
+ * All cache operations should happen on a {@link Node} - I.e., you look up a {@link
Node} and perform data operations
+ * on this {@link Node}. For convenience and familiarity with JBoss Cache 1.x, we
provide some helpers in {@link Cache}
+ * which dives you direct data access to nodes.
+ * <p/>
+ * This test exercises these.
+ */
+ public void testConvenienceMethods()
+ {
+ String key = "key", value = "value";
+ Map<String, String> data = new HashMap<String, String>();
+ data.put(key, value);
+
+ assertNull(cache.get(key));
+
+ cache.put(key, value);
+
+ assertEquals(value, cache.get(key));
+
+ cache.remove(key);
+
+ assertNull(cache.get(key));
+
+ cache.putAll(data);
+
+ assertEquals(value, cache.get(key));
+ }
+
+ /**
+ * Tests basic eviction
+ */
+ public void testEvict()
+ {
+ String key1 = "keyOne", key2 = "keyTwo", value =
"value";
+
+ cache.put(key1, value);
+ cache.put(key2, value);
+
+ assert cache.containsKey(key1);
+ assert cache.containsKey(key2);
+ assert cache.size() == 2;
+
+ // evict two
+ cache.evict(key2);
+
+ assert cache.containsKey(key1);
+ assert !cache.containsKey(key2);
+ assert cache.size() == 1;
+
+ cache.evict(key1);
+
+ assert !cache.containsKey(key1);
+ assert !cache.containsKey(key2);
+ assert cache.size() == 0;
+ }
+
+ public void testStopClearsData() throws Exception
+ {
+ String key = "key", value = "value";
+ cache.put(key, value);
+ assert cache.get(key).equals(value);
+ assert 1 == cache.size();
+ cache.stop();
+
+ cache.start();
+
+ assert !cache.containsKey(key);
+ assert cache.isEmpty();
+ }
+}
Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java
(rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,97 @@
+package org.jboss.starobrno.api;
+
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.Configuration.CacheMode;
+import org.jboss.starobrno.util.TestingUtil;
+import org.jboss.starobrno.util.internals.ViewChangeListener;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Test(groups = {"functional", "pessimistic"})
+public class CacheSPITest
+{
+ private CacheSPI<Object, Object> cache1;
+ private CacheSPI<Object, Object> cache2;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() throws Exception
+ {
+
+ Configuration conf1 = new Configuration();
+ conf1.setCacheMode(CacheMode.REPL_SYNC);
+
+ Configuration conf2 = conf1.clone();
+
+ cache1 = (CacheSPI<Object, Object>) new DefaultCacheFactory<Object,
Object>().createCache(conf1, false);
+ cache2 = (CacheSPI<Object, Object>) new DefaultCacheFactory<Object,
Object>().createCache(conf2, false);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown() throws Exception
+ {
+ if (cache1 != null)
+ {
+ try
+ {
+ cache1.stop();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ if (cache2 != null)
+ {
+ try
+ {
+ cache2.stop();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }
+
+ public void testGetMembers() throws Exception
+ {
+ cache1.start();
+ List memb1 = cache1.getRPCManager().getMembers();
+ assert 1 == memb1.size();
+
+ Object coord = memb1.get(0);
+
+ cache2.start();
+ memb1 = cache1.getRPCManager().getMembers();
+ TestingUtil.blockUntilViewsReceived(5000, false, cache1, cache2);
+ List memb2 = cache2.getRPCManager().getMembers();
+ assert 2 == memb1.size();
+ assert memb1 == memb2;
+
+ cache1.stop();
+ TestingUtil.blockUntilViewsReceived(5000, false, cache2);
+ memb2 = cache2.getRPCManager().getMembers();
+ assert 1 == memb2.size();
+ assert !coord.equals(memb2.get(0));
+ }
+
+ public void testIsCoordinator() throws Exception
+ {
+ cache1.start();
+ assert cache1.getRPCManager().isCoordinator();
+
+ cache2.start();
+ assert cache1.getRPCManager().isCoordinator();
+ assert !cache2.getRPCManager().isCoordinator();
+ ViewChangeListener viewChangeListener = new ViewChangeListener(cache2);
+ cache1.stop();
+ // wait till cache2 gets the view change notification
+ assert viewChangeListener.waitForViewChange(60, TimeUnit.SECONDS) : "Should
have received a view change!";
+ assert cache2.getRPCManager().isCoordinator();
+ }
+}
\ No newline at end of file
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,24 @@
+package org.jboss.starobrno.api.batch;
+
+import org.jboss.starobrno.Cache;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public abstract class AbstractBatchTest
+{
+ protected String getOnDifferentThread(final Cache<String, String> cache, final
String key) throws InterruptedException
+ {
+ final AtomicReference<String> ref = new AtomicReference<String>();
+ Thread t = new Thread()
+ {
+ public void run()
+ {
+ ref.set(cache.get(key));
+ }
+ };
+
+ t.start();
+ t.join();
+ return ref.get();
+ }
+}
Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,123 @@
+package org.jboss.starobrno.api.batch;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+
+
+@Test(groups = {"functional", "transaction"})
+public class BatchWithTM extends AbstractBatchTest
+{
+ public void testBatchWithOngoingTM() throws Exception
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache();
+ TransactionManager tm = getTransactionManager(cache);
+ tm.begin();
+ cache.put("k", "v");
+ cache.startBatch();
+ cache.put("k2", "v2");
+ tm.commit();
+
+ assert "v".equals(cache.get("k"));
+ assert "v2".equals(cache.get("k2"));
+
+ cache.endBatch(false); // should be a no op
+ assert "v".equals(cache.get("k"));
+ assert "v2".equals(cache.get("k2"));
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ public void testBatchWithoutOngoingTMSuspension() throws Exception
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache();
+ TransactionManager tm = getTransactionManager(cache);
+ assert tm.getTransaction() == null : "Should have no ongoing txs";
+ cache.startBatch();
+ cache.put("k", "v");
+ assert tm.getTransaction() == null : "Should have no ongoing txs";
+ cache.put("k2", "v2");
+
+ assert getOnDifferentThread(cache, "k") == null;
+ assert getOnDifferentThread(cache, "k2") == null;
+
+ try
+ {
+ tm.commit(); // should have no effect
+ }
+ catch (Exception e)
+ {
+ // the TM may barf here ... this is OK.
+ }
+
+ assert tm.getTransaction() == null : "Should have no ongoing txs";
+
+ assert getOnDifferentThread(cache, "k") == null;
+ assert getOnDifferentThread(cache, "k2") == null;
+
+ cache.endBatch(true); // should be a no op
+
+ assert "v".equals(getOnDifferentThread(cache, "k"));
+ assert "v2".equals(getOnDifferentThread(cache, "k2"));
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ public void testBatchRollback() throws Exception
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache();
+ TransactionManager tm = getTransactionManager(cache);
+ cache.startBatch();
+ cache.put("k", "v");
+ cache.put("k2", "v2");
+
+ assert getOnDifferentThread(cache, "k") == null;
+ assert getOnDifferentThread(cache, "k2") == null;
+
+ cache.endBatch(false);
+
+ assert getOnDifferentThread(cache, "k") == null;
+ assert getOnDifferentThread(cache, "k2") == null;
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ private TransactionManager getTransactionManager(Cache<String, String> c)
+ {
+ return c.getConfiguration().getRuntimeConfig().getTransactionManager();
+ }
+
+ private Cache<String, String> createCache()
+ {
+ CacheFactory<String, String> cf = new DefaultCacheFactory<String,
String>();
+ Configuration c = new Configuration();
+ c.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+ c.setInvocationBatchingEnabled(true);
+ assert c.getTransactionManagerLookupClass() != null : "Should have a
transaction manager lookup class attached!!";
+ return cf.createCache(c);
+ }
+}
Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,144 @@
+package org.jboss.starobrno.api.batch;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.ConfigurationException;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.Test;
+
+@Test(groups = "functional")
+public class BatchWithoutTM extends AbstractBatchTest
+{
+ public void testBatchWithoutCfg()
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache(false);
+ try
+ {
+ cache.startBatch();
+ assert false : "Should have failed";
+ }
+ catch (ConfigurationException good)
+ {
+ // do nothing
+ }
+
+ try
+ {
+ cache.endBatch(true);
+ assert false : "Should have failed";
+ }
+ catch (ConfigurationException good)
+ {
+ // do nothing
+ }
+
+ try
+ {
+ cache.endBatch(false);
+ assert false : "Should have failed";
+ }
+ catch (ConfigurationException good)
+ {
+ // do nothing
+ }
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ public void testEndBatchWithoutStartBatch()
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache(true);
+ cache.endBatch(true);
+ cache.endBatch(false);
+ // should not fail.
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ public void testStartBatchIdempotency()
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache(true);
+ cache.startBatch();
+ cache.put("k", "v");
+ cache.startBatch(); // again
+ cache.put("k2", "v2");
+ cache.endBatch(true);
+
+ assert "v".equals(cache.get("k"));
+ assert "v2".equals(cache.get("k2"));
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ public void testBatchVisibility() throws InterruptedException
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache(true);
+ cache.startBatch();
+ cache.put("k", "v");
+ assert getOnDifferentThread(cache, "k") == null : "Other thread
should not see batch update till batch completes!";
+
+ cache.endBatch(true);
+
+ assert "v".equals(getOnDifferentThread(cache, "k"));
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ public void testBatchRollback() throws Exception
+ {
+ Cache<String, String> cache = null;
+ try
+ {
+ cache = createCache(true);
+ cache.startBatch();
+ cache.put("k", "v");
+ cache.put("k2", "v2");
+
+ assert getOnDifferentThread(cache, "k") == null;
+ assert getOnDifferentThread(cache, "k2") == null;
+
+ cache.endBatch(false);
+
+ assert getOnDifferentThread(cache, "k") == null;
+ assert getOnDifferentThread(cache, "k2") == null;
+ }
+ finally
+ {
+ TestingUtil.killCaches(cache);
+ }
+ }
+
+ private Cache<String, String> createCache(boolean enableBatch)
+ {
+ CacheFactory<String, String> cf = new DefaultCacheFactory<String,
String>();
+ Configuration c = new Configuration();
+ c.setInvocationBatchingEnabled(enableBatch);
+ return cf.createCache(c);
+ }
+}
Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,35 @@
+package org.jboss.starobrno.api.mvcc;
+
+import org.jboss.cache.util.concurrent.locks.LockContainer;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.util.TestingUtil;
+
+/**
+ * Helper class to assert lock status in MVCC
+ *
+ * @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
+ * @since 3.0
+ */
+public class LockAssert
+{
+ public static void assertLocked(Object key, LockManager lockManager,
InvocationContextContainer icc)
+ {
+ assert lockManager.isLocked(key) : key + " not locked!";
+// assert icc.get().getKeysLocked().contains(key) : "Lock not recorded for
" + key;
+ }
+
+ public static void assertNotLocked(Object key, InvocationContextContainer icc)
+ {
+ // can't rely on the negative test since other nodes may share the same lock
with lock striping.
+// assert !lockManager.isLocked(fqn) : fqn + " is locked!";
+ assert !icc.get().getKeysLocked().contains(key) : key + " lock
recorded!";
+ }
+
+ public static void assertNoLocks(LockManager lockManager, InvocationContextContainer
icc)
+ {
+ LockContainer lc = (LockContainer) TestingUtil.extractField(lockManager,
"lockContainer");
+ assert lc.getNumLocksHeld() == 0 : "Stale locks exist! NumLocksHeld is "
+ lc.getNumLocksHeld() + " and lock info is " + lockManager.printLockInfo();
+ assert icc.get().getKeysLocked().isEmpty() : "Stale (?) locks recorded! "
+ icc.get().getKeysLocked();
+ }
+}
Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,301 @@
+package org.jboss.starobrno.api.mvcc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+
+/**
+ * @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
+ * @since 3.0
+ */
+@Test(groups = {"functional", "mvcc"})
+public abstract class LockTestBase
+{
+ protected Cache<String, String> cache;
+ protected TransactionManager tm;
+ protected LockManager lockManager;
+ protected InvocationContextContainer icc;
+ protected boolean repeatableRead = true;
+ protected boolean lockParentForChildInsertRemove = false;
+ private Log log = LogFactory.getLog(LockTestBase.class);
+
+
+ @BeforeMethod
+ public void setUp()
+ {
+ cache = new DefaultCacheFactory<String, String>().createCache(new
Configuration(), false);
+
cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+ cache.getConfiguration().setIsolationLevel(repeatableRead ?
IsolationLevel.REPEATABLE_READ : IsolationLevel.READ_COMMITTED);
+
cache.getConfiguration().setLockParentForChildInsertRemove(lockParentForChildInsertRemove);
+ // reduce lock acquisition timeout so this doesn't take forever to run
+ cache.getConfiguration().setLockAcquisitionTimeout(200); // 200 ms
+ cache.start();
+ lockManager =
TestingUtil.extractComponentRegistry(cache).getComponent(LockManager.class);
+ icc =
TestingUtil.extractComponentRegistry(cache).getComponent(InvocationContextContainer.class);
+ tm =
TestingUtil.extractComponentRegistry(cache).getComponent(TransactionManager.class);
+ }
+
+ @AfterMethod
+ public void tearDown()
+ {
+ log.debug("**** - STARTING TEARDOWN - ****");
+ TestingUtil.killCaches(cache);
+ }
+
+ protected void assertLocked(Object key)
+ {
+ LockAssert.assertLocked(key, lockManager, icc);
+ }
+
+ protected void assertNotLocked(Object key)
+ {
+ LockAssert.assertNotLocked(key, icc);
+ }
+
+ protected void assertNoLocks()
+ {
+ LockAssert.assertNoLocks(lockManager, icc);
+ }
+
+ public void testLocksOnPutKeyVal() throws Exception
+ {
+ tm.begin();
+ cache.put("k", "v");
+ assertLocked("k");
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.begin();
+ assert cache.get("k").equals("v");
+ assertNotLocked("k");
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.begin();
+ cache.remove("k");
+ assertLocked("k");
+ tm.commit();
+
+ assertNoLocks();
+ }
+
+ public void testLocksOnPutData() throws Exception
+ {
+ tm.begin();
+ cache.putAll(Collections.singletonMap("k", "v"));
+ assertLocked("k");
+ assert "v".equals(cache.get("k"));
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.begin();
+ assert "v".equals(cache.get("k"));
+ assertNoLocks();
+ tm.commit();
+
+ assertNoLocks();
+ }
+
+ public void testLocksOnEvictNode() throws Exception
+ {
+ // init some data on a node
+ cache.putAll(Collections.singletonMap("k", "v"));
+
+ assert "v".equals(cache.get("k"));
+
+ tm.begin();
+ cache.evict("k");
+ assertLocked("k");
+ tm.commit();
+ assert !cache.containsKey("k") : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnRemoveNonexistentNode() throws Exception
+ {
+ assert !cache.containsKey("k") : "Should not exist";
+
+ tm.begin();
+ cache.remove("k");
+ assertLocked("k");
+ tm.commit();
+ assert !cache.containsKey("k") : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnEvictNonexistentNode() throws Exception
+ {
+ assert !cache.containsKey("k") : "Should not exist";
+
+ tm.begin();
+ cache.evict("k");
+ assertLocked("k");
+ tm.commit();
+ assert !cache.containsKey("k") : "Should not exist";
+ assertNoLocks();
+ }
+
+ public void testLocksOnRemoveData() throws Exception
+ {
+ // init some data on a node
+ cache.put("k", "v");
+ cache.put("k2", "v2");
+
+ assert "v".equals(cache.get("k"));
+ assert "v2".equals(cache.get("k2"));
+
+ // remove
+ tm.begin();
+ cache.clear();
+ assertLocked("k");
+ assertLocked("k2");
+ tm.commit();
+
+ assert cache.isEmpty();
+ assertNoLocks();
+ }
+
+ public void testWriteDoesntBlockRead() throws Exception
+ {
+ cache.put("k", "v");
+
+ // start a write.
+ tm.begin();
+ cache.put("k2", "v2");
+ assertLocked("k2");
+ Transaction write = tm.suspend();
+
+ // now start a read and confirm that the write doesn't block it.
+ tm.begin();
+ assert "v".equals(cache.get("k"));
+ assert null == cache.get("k2") : "Should not see uncommitted
changes";
+ Transaction read = tm.suspend();
+
+ // commit the write
+ tm.resume(write);
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.resume(read);
+ if (repeatableRead)
+ assert null == cache.get("k2") : "Should have repeatable
read";
+ else
+ assert "v2".equals(cache.get("k2")) : "Read committed
should see committed changes";
+ tm.commit();
+ assertNoLocks();
+ }
+
+ public void testWriteDoesntBlockReadNonexistent() throws Exception
+ {
+ // start a write.
+ tm.begin();
+ cache.put("k", "v");
+ assertLocked("k");
+ Transaction write = tm.suspend();
+
+ // now start a read and confirm that the write doesn't block it.
+ tm.begin();
+ assert null == cache.get("k") : "Should not see uncommitted
changes";
+ Transaction read = tm.suspend();
+
+ // commit the write
+ tm.resume(write);
+ tm.commit();
+
+ assertNoLocks();
+
+ tm.resume(read);
+ if (repeatableRead)
+ {
+ assert null == cache.get("k") : "Should have repeatable
read";
+ }
+ else
+ {
+ assert "v".equals(cache.get("k")) : "Read committed
should see committed changes";
+ }
+ tm.commit();
+ assertNoLocks();
+ }
+
+ public void testConcurrentWriters() throws Exception
+ {
+ tm.begin();
+ cache.put("k", "v");
+ Transaction t1 = tm.suspend();
+
+ tm.begin();
+ try
+ {
+ cache.put("k", "v");
+ assert false : "Should fail lock acquisition";
+ }
+ catch (TimeoutException expected)
+ {
+// expected.printStackTrace(); // for debugging
+ }
+ tm.commit();
+ tm.resume(t1);
+ tm.commit();
+ assertNoLocks();
+ }
+
+ public void testRollbacks() throws Exception
+ {
+ cache.put("k", "v");
+ tm.begin();
+ assert "v".equals(cache.get("k"));
+ Transaction reader = tm.suspend();
+
+ tm.begin();
+ cache.put("k", "v2");
+ tm.rollback();
+
+ tm.resume(reader);
+ Object value = cache.get("k");
+ assert "v".equals(value) : "Expecting 'v' but was " +
value;
+ tm.commit();
+
+ // even after commit
+ assert "v".equals(cache.get("k"));
+ assertNoLocks();
+ }
+
+ public void testRollbacksOnNullNode() throws Exception
+ {
+ tm.begin();
+ assert null == cache.get("k");
+ Transaction reader = tm.suspend();
+
+ tm.begin();
+ cache.put("k", "v");
+ assert "v".equals(cache.get("k"));
+ tm.rollback();
+
+ tm.resume(reader);
+ assert null == cache.get("k") : "Expecting null but was " +
cache.get("k");
+ tm.commit();
+
+ // even after commit
+ assert null == cache.get("k");
+ assertNoLocks();
+ }
+}
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
===================================================================
---
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,20 @@
+package org.jboss.starobrno.api.mvcc.read_committed;
+
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.starobrno.api.CacheAPITest;
+import org.jboss.starobrno.config.Configuration;
+import org.testng.annotations.Test;
+
+/**
+ * MVCC version of {@link org.jboss.cache.api.CacheAPITest}
+ */
+@Test(groups = {"functional", "mvcc"})
+public class CacheAPIMVCCTest extends CacheAPITest
+{
+ @Override
+ protected void configure(Configuration c)
+ {
+ super.configure(c);
+ c.setIsolationLevel(IsolationLevel.READ_COMMITTED);
+ }
+}
\ No newline at end of file
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java
===================================================================
---
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,13 @@
+package org.jboss.starobrno.api.mvcc.read_committed;
+
+import org.jboss.starobrno.api.mvcc.LockTestBase;
+import org.testng.annotations.Test;
+
+@Test(groups = {"functional", "mvcc"})
+public class ReadCommittedLockTest extends LockTestBase
+{
+ public ReadCommittedLockTest()
+ {
+ repeatableRead = false;
+ }
+}
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
===================================================================
---
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,20 @@
+package org.jboss.starobrno.api.mvcc.repeatable_read;
+
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.starobrno.api.CacheAPITest;
+import org.jboss.starobrno.config.Configuration;
+import org.testng.annotations.Test;
+
+/**
+ * MVCC version of {@link org.jboss.cache.api.CacheAPITest}
+ */
+@Test(groups = {"functional", "mvcc"})
+public class CacheAPIMVCCTest extends CacheAPITest
+{
+ @Override
+ protected void configure(Configuration c)
+ {
+ super.configure(c);
+ c.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
+ }
+}
\ No newline at end of file
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java
===================================================================
---
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,90 @@
+package org.jboss.starobrno.api.mvcc.repeatable_read;
+
+import org.jboss.starobrno.api.mvcc.LockTestBase;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+
+@Test(groups = {"functional", "mvcc"})
+public class RepeatableReadLockTest extends LockTestBase
+{
+ public RepeatableReadLockTest()
+ {
+ repeatableRead = true;
+ }
+
+ public void testRepeatableReadWithRemove() throws Exception
+ {
+ cache.put("k", "v");
+
+ tm.begin();
+ assert cache.get("k") != null;
+ Transaction reader = tm.suspend();
+
+ tm.begin();
+ assert cache.remove("k") != null;
+ assert cache.get("k") == null;
+ tm.commit();
+
+ assert cache.get("k") == null;
+
+ tm.resume(reader);
+ assert cache.get("k") != null;
+ assert "v".equals(cache.get("k"));
+ tm.commit();
+
+ assert cache.get("k") == null;
+ assertNoLocks();
+ }
+
+ public void testRepeatableReadWithEvict() throws Exception
+ {
+ cache.put("k", "v");
+
+ tm.begin();
+ assert cache.get("k") != null;
+ Transaction reader = tm.suspend();
+
+ tm.begin();
+ cache.evict("k");
+ assert cache.get("k") == null;
+ tm.commit();
+
+ assert cache.get("k") == null;
+
+ tm.resume(reader);
+ assert cache.get("k") != null;
+ assert "v".equals(cache.get("k"));
+ tm.commit();
+
+ assert cache.get("k") == null;
+ assertNoLocks();
+ }
+
+ public void testRepeatableReadWithNull() throws Exception
+ {
+ assert cache.get("k") == null;
+
+ tm.begin();
+ assert cache.get("k") == null;
+ Transaction reader = tm.suspend();
+
+ tm.begin();
+ cache.put("k", "v");
+ assert cache.get("k") != null;
+ assert "v".equals(cache.get("k"));
+ tm.commit();
+
+ assert cache.get("k") != null;
+ assert "v".equals(cache.get("k"));
+
+ tm.resume(reader);
+ Object o = cache.get("k");
+ assert o == null : "found value " + o;
+ tm.commit();
+
+ assert cache.get("k") != null;
+ assert "v".equals(cache.get("k"));
+ assertNoLocks();
+ }
+}
Added:
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java
===================================================================
---
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java
(rev 0)
+++
core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java 2008-10-10
09:43:27 UTC (rev 6901)
@@ -0,0 +1,191 @@
+package org.jboss.starobrno.api.mvcc.repeatable_read;
+
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.api.mvcc.LockAssert;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+@Test(groups = {"functional", "mvcc"})
+public class WriteSkewTest
+{
+ protected Cache<String, String> cache;
+ protected TransactionManager tm;
+ protected LockManager lockManager;
+ protected InvocationContextContainer icc;
+ protected boolean repeatableRead = true;
+
+ @BeforeMethod
+ public void setUp()
+ {
+ cache = new DefaultCacheFactory<String, String>().createCache(new
Configuration(), false);
+
cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+ cache.getConfiguration().setIsolationLevel(repeatableRead ?
IsolationLevel.REPEATABLE_READ : IsolationLevel.READ_COMMITTED);
+ // reduce lock acquisition timeout so this doesn't take forever to run
+ cache.getConfiguration().setLockAcquisitionTimeout(200); // 200 ms
+ }
+
+ @AfterMethod
+ public void tearDown()
+ {
+ TestingUtil.killCaches(cache);
+ }
+
+ private void postStart()
+ {
+ lockManager =
TestingUtil.extractComponentRegistry(cache).getComponent(LockManager.class);
+ icc =
TestingUtil.extractComponentRegistry(cache).getComponent(InvocationContextContainer.class);
+ tm =
TestingUtil.extractComponentRegistry(cache).getComponent(TransactionManager.class);
+ }
+
+ protected void assertNoLocks()
+ {
+ LockAssert.assertNoLocks(lockManager, icc);
+ }
+
+ public void testDontCheckWriteSkew() throws Exception
+ {
+ cache.getConfiguration().setWriteSkewCheck(false);
+ cache.start();
+ postStart();
+ doTest(true);
+ }
+
+ public void testCheckWriteSkew() throws Exception
+ {
+ cache.getConfiguration().setWriteSkewCheck(true);
+ cache.start();
+ postStart();
+ doTest(false);
+ }
+
+ private void doTest(final boolean allowWriteSkew) throws Exception
+ {
+ if (repeatableRead)
+ {
+ cache.put("k", "v");
+ final Set<Exception> w1exceptions = new HashSet<Exception>();
+ final Set<Exception> w2exceptions = new HashSet<Exception>();
+ final CountDownLatch w1Signal = new CountDownLatch(1);
+ final CountDownLatch w2Signal = new CountDownLatch(1);
+ final CountDownLatch threadSignal = new CountDownLatch(2);
+
+ Thread w1 = new Thread("Writer-1")
+ {
+ public void run()
+ {
+ boolean didCoundDown = false;
+ try
+ {
+ tm.begin();
+ assert "v".equals(cache.get("k"));
+ threadSignal.countDown();
+ didCoundDown = true;
+ w1Signal.await();
+ cache.put("k", "v2");
+ tm.commit();
+ }
+ catch (Exception e)
+ {
+ w1exceptions.add(e);
+ }
+ finally
+ {
+ if (!didCoundDown) threadSignal.countDown();
+ }
+ }
+ };
+
+ Thread w2 = new Thread("Writer-2")
+ {
+ public void run()
+ {
+ boolean didCoundDown = false;
+ try
+ {
+ tm.begin();
+ assert "v".equals(cache.get("k"));
+ threadSignal.countDown();
+ didCoundDown = true;
+ w2Signal.await();
+ cache.put("k", "v3");
+ tm.commit();
+ }
+ catch (Exception e)
+ {
+ w2exceptions.add(e);
+ // the exception will be thrown when doing a cache.put(). We should
make sure we roll back the tx to release locks.
+ if (!allowWriteSkew)
+ {
+ try
+ {
+ tm.rollback();
+ }
+ catch (SystemException e1)
+ {
+ // do nothing.
+ }
+ }
+ }
+ finally
+ {
+ if (!didCoundDown) threadSignal.countDown();
+ }
+ }
+ };
+
+ w1.start();
+ w2.start();
+
+ threadSignal.await();
+ // now. both txs have read.
+ // let tx1 start writing
+ w1Signal.countDown();
+ w1.join();
+
+ w2Signal.countDown();
+ w2.join();
+
+ if (allowWriteSkew)
+ {
+ // should have no exceptions!!
+ throwExceptions(w1exceptions, w2exceptions);
+ assert w2exceptions.size() == 0;
+ assert w1exceptions.size() == 0;
+ assert "v3".equals(cache.get("k")) : "W2 should have
overwritten W1's work!";
+ }
+ else
+ {
+ // there should be a single exception from w2.
+ assert w2exceptions.size() == 1;
+ throwExceptions(w1exceptions);
+ assert w1exceptions.size() == 0;
+ assert "v2".equals(cache.get("k")) : "W2 should NOT
have overwritten W1's work!";
+ }
+
+ assertNoLocks();
+ }
+ }
+
+ private void throwExceptions(Collection<Exception>... exceptions) throws
Exception
+ {
+ for (Collection<Exception> ce : exceptions)
+ {
+ for (Exception e : ce) throw e;
+ }
+ }
+}