Thanks to Norbert and Bela for the reply.
I tested Norberts theory on Thread start position, and it didn't seem to make
any difference.
I took Bela's test case, and this test does work, BUT WITH ONE subtle
difference.
In Bela's test case, he places a value in the cache before starting things.
This is a _crucial_ difference to mine.
If I commented out the initial put(..) call before the Readers are created and
started, I get the same results as my original test case, Reader 2 actually
reads the null while Reader 1 is pausing.
Here is example output from Bela's original test case:
| main: sleeping for 100
| reader1: about to access tree
| reader1: accessed tree, retval: testvalue
| reader1: sleeping for 3000
| reader2: about to access tree
| reader1: About to commit
| reader1: committed, exiting
| reader2: accessed tree, retval: testvalue
| reader2: About to commit
| reader2: committed, exiting
The above is exactly what I want, but also occuring when there is null values
in the cache. Here's the output when you simply comment out the first put(...)
call:
| main: sleeping for 100
| reader1: about to access tree
| reader1: accessed tree, retval: null
| reader1: sleeping for 3000
| reader2: about to access tree
| reader2: accessed tree, retval: null
| reader2: About to commit
| reader2: committed, exiting
| reader1: About to commit
| reader1: committed, exiting
A null value in the cache seems to be specially treated, as it does not block
reads. Unfortunately I need serialized access (read or write) to each leaf
node in the tree to guarantee that 2 threads don't try to go off and hit the db
and potentially clobber each other.
Here is the complete test case that I adapted from Bela's original, combining
it with the basic shell provided by the
org.jboss.test.cache.perf.basic.LocalPerfTestCase class that is provided in the
examples src of the distro. You will note that I have added the code to set
the cache Isolation level in the initCache() method:
package com.aconex.jbosscache;
|
| import java.util.Properties;
|
| import javax.naming.Context;
| import javax.naming.InitialContext;
| import javax.transaction.UserTransaction;
|
| import org.jboss.cache.PropertyConfigurator;
| import org.jboss.cache.TreeCache;
| import org.jboss.cache.lock.IsolationLevel;
| import org.jboss.cache.transaction.DummyTransactionManager;
|
| import junit.framework.TestCase;
|
| /**
| * @author psmith
| *
| */
| public class SerializableTests extends TestCase {
| TreeCache cache_;
|
| int cachingMode_ = TreeCache.LOCAL;
|
| final static Properties p_;
|
| // final static Logger log_ =
Logger.getLogger(LocalPerfAopTest.class);
| String oldFactory_ = null;
|
| final String FACTORY =
"org.jboss.cache.transaction.DummyContextFactory";
|
| DummyTransactionManager tm_;
|
| static {
| p_ = new Properties();
| p_.put(Context.INITIAL_CONTEXT_FACTORY,
|
"org.jboss.cache.transaction.DummyContextFactory");
| }
|
| /*
| * @see TestCase#setUp()
| */
| protected void setUp() throws Exception {
| super.setUp();
|
| oldFactory_ =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
| System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
|
| DummyTransactionManager.getInstance();
| initCaches(TreeCache.LOCAL);
| tm_ = new DummyTransactionManager();
|
| log("LocalPerfAopTest: cacheMode=LOCAL, one cache");
| }
|
| /**
| * @param string
| */
| private void log(String msg) {
| System.out.println(Thread.currentThread().getName() + ": " +
msg);
|
| }
|
| /*
| * @see TestCase#tearDown()
| */
| protected void tearDown() throws Exception {
| super.tearDown();
|
| DummyTransactionManager.destroy();
| destroyCaches();
|
| if (oldFactory_ != null) {
| System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
oldFactory_);
| oldFactory_ = null;
| }
| }
|
| void initCaches(int caching_mode) throws Exception {
| cachingMode_ = caching_mode;
| cache_ = new TreeCache();
| PropertyConfigurator config = new PropertyConfigurator();
| config.configure(cache_, "META-INF/local-service.xml"); // read
in
| // generic local
| // xml
| cache_
|
.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
| cache_.setIsolationLevel(IsolationLevel.SERIALIZABLE);
| cache_.startService();
| }
|
| void destroyCaches() throws Exception {
| cache_.stopService();
| cache_ = null;
| }
|
| public void
testConcurrentReadsWithSerializableIsolationLevelValueAlreadyInCache()
| throws Exception {
|
| cache_.put("/testfqn", "testkey", "testvalue"); // add initial
value, to
| runSerializableTest();
| }
|
| public void
testConcurrentReadsWithSerializableIsolationLevelNOValueInCache()
| throws Exception {
|
| runSerializableTest();
| }
|
| /**
| * @throws Exception
| * @throws InterruptedException
| */
| private void runSerializableTest() throws Exception,
InterruptedException {
| final long TIMEOUT = 5000;
| Reader r1, r2;
| r1 = new Reader("reader1", 3000);
| r2 = new Reader("reader2", 0);
| r1.start();
| pause(100); // make sure thread1 starts and acquires the lock
before
| // thread2
| r2.start();
| r1.join(TIMEOUT);
| r2.join(TIMEOUT);
| }
|
| /**
| * @param i
| * @throws Exception
| */
| private void pause(long i) throws Exception {
| log("sleeping for " + i);
| Thread.sleep(i);
| }
|
| class Reader extends Thread {
| long timeout;
|
| public Reader(String name, long timeout) {
| super(name);
| this.timeout = timeout;
| }
|
| public void run() {
| UserTransaction trans = null;
| try {
| trans = (UserTransaction) new InitialContext(p_)
| .lookup("UserTransaction");
| trans.begin();
| Object retval = null;
| log("about to access tree");
| retval = cache_.get("testfqn", "testkey");
| log("accessed tree, retval: " + retval);
| if (timeout > 0) {
| pause(timeout);
| }
| } catch (Exception e) {
| e.printStackTrace();
| } finally {
| log("About to commit");
| try {
| trans.commit();
| } catch (Throwable t) {
| }
| log("committed, exiting");
| }
| }
| }
|
| }
I would appreciate any thoughts on this.
cheers,
Paul Smith
View the original post :
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3854886#3854886
Reply to the post :
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=3854886
-------------------------------------------------------
This SF.Net email is sponsored by:
Sybase ASE Linux Express Edition - download now for FREE
LinuxWorld Reader's Choice Award Winner for best database on Linux.
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
_______________________________________________
JBoss-Development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development