From: Bryan T. <tho...@us...> - 2007-02-19 01:05:49
|
Update of /cvsroot/cweb/bigdata/src/test/com/bigdata/journal In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv7992/src/test/com/bigdata/journal Modified Files: TestJournalBasics.java TestConflictResolution.java TestReadOnlyTx.java Added Files: StressTestConcurrent.java Log Message: Working on transaction processing support. Index: TestJournalBasics.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestJournalBasics.java,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** TestJournalBasics.java 17 Feb 2007 21:34:13 -0000 1.8 --- TestJournalBasics.java 19 Feb 2007 01:05:39 -0000 1.9 *************** *** 101,111 **** * tests of transaction support. */ // tests of transitions in the transaction RunState state machine. suite.addTestSuite( TestTxRunState.class ); // @todo update these tests of the tx-journal integration. suite.addTestSuite( TestTxJournalProtocol.class ); ! // @todo tests of read-write transactions. suite.addTestSuite( TestTx.class ); ! // @todo tests of read-only transactions. suite.addTestSuite( TestReadOnlyTx.class ); // @todo tests of read-committed transactions. --- 101,112 ---- * tests of transaction support. */ + // tests of transitions in the transaction RunState state machine. suite.addTestSuite( TestTxRunState.class ); // @todo update these tests of the tx-journal integration. suite.addTestSuite( TestTxJournalProtocol.class ); ! // tests of read-write transactions and isolation. suite.addTestSuite( TestTx.class ); ! // tests of read-only transactions. suite.addTestSuite( TestReadOnlyTx.class ); // @todo tests of read-committed transactions. *************** *** 113,118 **** // @todo tests of concurrent schedules and conflict detection. suite.addTestSuite( TestConcurrentSchedules.class ); ! // @todo tests of write-write conflict resolution. suite.addTestSuite(TestConflictResolution.class); return suite; --- 114,146 ---- // @todo tests of concurrent schedules and conflict detection. suite.addTestSuite( TestConcurrentSchedules.class ); ! // todo tests of write-write conflict resolution. suite.addTestSuite(TestConflictResolution.class); + + /* + * @todo tests of batch api and group commit mechanisms for very high + * volume updates. These tests might be more relevent to the data server + * since group commit can be achieved by transparently collecting small + * non-conflicting updates into a transaction that succeeds or fails all + * updates in the group. in this model transactions are local and + * updates do not have atomicity across journals. another alternative is + * to use a pulse to commit a global group update transaction with a + * frequency that trades off the size of the commit groups against + * latency. the advantage of the latter approach is that it can be + * combined with normal transaction processing in a trivial manner and I + * am not sure whether or not that is true of the former approach. + */ + + /* + * @todo stress tests of concurrent transactions parameterized so that + * we can also test overflow handling and scale up. Scale out testing + * may require a refactor of the clients to lookup services. This could + * be moved out of the per-journal strategy test suite and performed + * only for the target strategy, e.g., Direct. Measure throughput rates + * and compare TPS and write/read rates with other systems. + * + * @todo we could add tests based on known transaction processing + * benchmarks here as well. + */ + suite.addTestSuite(StressTestConcurrent.class); return suite; Index: TestConflictResolution.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestConflictResolution.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** TestConflictResolution.java 17 Feb 2007 21:34:12 -0000 1.1 --- TestConflictResolution.java 19 Feb 2007 01:05:39 -0000 1.2 *************** *** 48,51 **** --- 48,57 ---- package com.bigdata.journal; + import java.util.Properties; + + import com.bigdata.isolation.IConflictResolver; + import com.bigdata.isolation.UnisolatedBTree; + import com.bigdata.isolation.Value; + /** * Tests of write-write conflict resolution. *************** *** 60,64 **** */ public TestConflictResolution() { - // TODO Auto-generated constructor stub } --- 66,69 ---- *************** *** 68,77 **** public TestConflictResolution(String name) { super(name); - // TODO Auto-generated constructor stub } ! public void test_something() { ! fail("write tests"); } --- 73,323 ---- public TestConflictResolution(String name) { super(name); } ! /** ! * Test correct detection of a write-write conflict. An index is registered ! * and the journal is committed. Two transactions (tx1, tx2) are then ! * started. Both transactions write a value under the same key. tx1 prepares ! * and commits. tx2 attempts to prepare, and the test verifies that a ! * {@link ValidationError} is reported. ! */ ! public void test_writeWriteConflict_correctDetection() { ! ! Properties properties = getProperties(); ! ! Journal journal = new Journal(properties); ! ! String name = "abc"; ! ! final byte[] k1 = new byte[] { 1 }; ! ! final byte[] v1a = new byte[] { 1 }; ! final byte[] v1b = new byte[] { 2 }; ! ! { ! ! /* ! * register an index and commit the journal. ! */ ! ! journal.registerIndex(name, new UnisolatedBTree(journal)); ! ! journal.commit(); ! ! } ! ! /* ! * Create two transactions. ! */ ! ITx tx1 = journal.newTx(); ! ! ITx tx2 = journal.newTx(); ! ! /* ! * Write a value under the same key on the same index in both ! * transactions. ! */ ! ! tx1.getIndex(name).insert(k1, v1a); ! ! tx2.getIndex(name).insert(k1, v1b); ! ! tx1.prepare(); ! ! tx1.commit(); ! ! /* ! * verify that the value from tx1 is found under the key on the ! * unisolated index. ! */ ! assertEquals(v1a,(byte[])journal.getIndex(name).lookup(k1)); ! ! try { ! tx2.prepare(); ! fail("Expecting: "+ValidationError.class); ! } catch(ValidationError ex) { ! System.err.println("Ignoring expected exception: "+ex); ! assertTrue(tx2.isAborted()); ! } ! ! journal.close(); ! ! } ! ! /** ! * Test correct detection and resolution of a write-write conflict. An index ! * is registered with an {@link IConflictResolver} and the journal is ! * committed. Two transactions (tx1, tx2) are then started. Both ! * transactions write a value under the same key. tx1 prepares and commits. ! * tx2 attempts to prepare, and the test verifies that the conflict resolver ! * is invoked, that it may resolve the conflict causing validation to ! * succeed and that the value determined by conflict resolution is made ! * persistent when tx2 commits. ! */ ! public void test_writeWriteConflict_conflictIsResolved() { ! ! Properties properties = getProperties(); ! ! Journal journal = new Journal(properties); ! ! String name = "abc"; ! ! final byte[] k1 = new byte[] { 1 }; ! ! final byte[] v1a = new byte[] { 1 }; ! final byte[] v1b = new byte[] { 2 }; ! final byte[] v1c = new byte[] { 3 }; ! ! { ! ! /* ! * register an index with a conflict resolver and commit the ! * journal. ! */ ! ! journal.registerIndex(name, new UnisolatedBTree(journal, ! new SingleValueConflictResolver(k1, v1c))); ! ! journal.commit(); ! ! } ! ! /* ! * Create two transactions. ! */ ! ! ITx tx1 = journal.newTx(); ! ! ITx tx2 = journal.newTx(); ! ! /* ! * Write a value under the same key on the same index in both ! * transactions. ! */ ! ! tx1.getIndex(name).insert(k1, v1a); ! ! tx2.getIndex(name).insert(k1, v1b); ! ! tx1.prepare(); ! ! tx1.commit(); ! ! /* ! * verify that the value from tx1 is found under the key on the ! * unisolated index. ! */ ! assertEquals(v1a,(byte[])journal.getIndex(name).lookup(k1)); ! ! tx2.prepare(); ! ! // @todo the indices should probably become read only at this point. ! assertEquals(v1c,(byte[])tx2.getIndex(name).lookup(k1)); ! ! tx2.commit(); ! ! /* ! * verify that the resolved value is found under the key on the ! * unisolated index. ! */ ! assertEquals(v1c,(byte[])journal.getIndex(name).lookup(k1)); ! ! journal.close(); ! ! } ! ! /** ! * The concurrency control algorithm must not permit two transactions to ! * prepare at the same time since that violates the basic rules of ! * serializability. ! * ! * @todo javadoc and move into schedules test suite or its own test suite. ! */ ! public void test_serializability() { ! ! Properties properties = getProperties(); ! ! Journal journal = new Journal(properties); ! ! String name = "abc"; ! ! final byte[] k1 = new byte[] { 1 }; ! ! final byte[] v1a = new byte[] { 1 }; ! final byte[] v1b = new byte[] { 2 }; ! ! { ! ! /* ! * register an index and commit the journal. ! */ ! ! journal.registerIndex(name, new UnisolatedBTree(journal)); ! ! journal.commit(); ! ! } ! ! /* ! * Create two transactions. ! */ ! ! ITx tx1 = journal.newTx(); ! ! ITx tx2 = journal.newTx(); ! ! /* ! * Write a value under the same key on the same index in both ! * transactions. ! */ ! ! tx1.getIndex(name).insert(k1, v1a); ! ! tx2.getIndex(name).insert(k1, v1b); ! ! tx1.prepare(); ! ! try { ! tx2.prepare(); ! fail("Expecting: "+IllegalStateException.class); ! } catch(IllegalStateException ex) { ! System.err.println("Ignoring expected exception: "+ex); ! } ! ! journal.close(); ! ! } ! ! /** ! * Helper class used to resolve a predicted conflict to a known value. ! * ! * @author <a href="mailto:tho...@us...">Bryan Thompson</a> ! * @version $Id$ ! */ ! public static class SingleValueConflictResolver implements IConflictResolver ! { ! ! private final byte[] expectedKey; ! private final byte[] resolvedValue; ! ! private static final long serialVersionUID = -1161201507073182976L; ! ! public SingleValueConflictResolver(byte[] expectedKey, byte[] resolvedValue) { ! ! this.expectedKey = expectedKey; ! ! this.resolvedValue = resolvedValue; ! ! } ! ! public byte[] resolveConflict(byte[] key, Value comittedValue, ! Value txEntry) throws RuntimeException { ! ! assertEquals("key",expectedKey,key); ! ! return resolvedValue; ! ! } } Index: TestReadOnlyTx.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestReadOnlyTx.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** TestReadOnlyTx.java 17 Feb 2007 21:34:13 -0000 1.1 --- TestReadOnlyTx.java 19 Feb 2007 01:05:39 -0000 1.2 *************** *** 48,51 **** --- 48,56 ---- package com.bigdata.journal; + import java.util.Properties; + + import com.bigdata.isolation.UnisolatedBTree; + import com.bigdata.objndx.IIndex; + /** * Test suite for fully isolated read-only transactions. *************** *** 69,76 **** } ! public void test_something() { ! fail("write tests"); } --- 74,161 ---- } ! /** ! * Test verifies that you can not write on a read-only transaction. ! */ ! public void test_isReadOnly() { ! Properties properties = getProperties(); + Journal journal = new Journal(properties); + + String name = "abc"; + + final byte[] k1 = new byte[]{1}; + + final byte[] v1 = new byte[]{1}; + + { + + /* + * register an index, write on the index, and commit the journal. + */ + IIndex ndx = journal.registerIndex(name, new UnisolatedBTree( + journal)); + + ndx.insert(k1, v1); + + journal.commit(); + + } + + { + + /* + * create a read-only transaction, verify that we can read the + * value written on the index but that we can not write on the + * index. + */ + + ITx tx1 = journal.newTx(true); + + IIndex ndx = tx1.getIndex(name); + + assertNotNull(ndx); + + assertEquals((byte[])v1,(byte[])ndx.lookup(k1)); + + try { + ndx.insert(k1,new byte[]{1,2,3}); + fail("Expecting: "+UnsupportedOperationException.class); + } catch( UnsupportedOperationException ex) { + System.err.println("Ignoring expected exception: "+ex); + } + + tx1.prepare(); + + tx1.commit(); + + } + + { + + /* + * do it again, but this time we will abort the read-only + * transaction. + */ + + ITx tx1 = journal.newTx(true); + + IIndex ndx = tx1.getIndex(name); + + assertNotNull(ndx); + + assertEquals((byte[])v1,(byte[])ndx.lookup(k1)); + + try { + ndx.insert(k1,new byte[]{1,2,3}); + fail("Expecting: "+UnsupportedOperationException.class); + } catch( UnsupportedOperationException ex) { + System.err.println("Ignoring expected exception: "+ex); + } + + tx1.abort(); + + } + } --- NEW FILE: StressTestConcurrent.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.1 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb are Copyright (c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact information for CognitiveWeb is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Feb 18, 2007 */ package com.bigdata.journal; /** * Stress tests for concurrent transaction processing. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class StressTestConcurrent extends ProxyTestCase { public StressTestConcurrent() { } public StressTestConcurrent(String name) { super(name); } public void test_concurrentClients() { fail("write tests"); } } |