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