Update of /cvsroot/cweb/bigdata/src/test/com/bigdata/journal In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv12401/src/test/com/bigdata/journal Modified Files: TestTxRunState.java TestJournal.java TestRootBlockView.java AbstractTestCase.java TestTx.java TestAll.java TestJournalBasics.java Added Files: TestCommitRecordIndex.java TestReadCommittedTx.java TestCommitHistory.java TestConflictResolution.java TestConcurrentSchedules.java TestReadOnlyTx.java AbstractCommitRecordTestCase.java TestName2Addr.java TestCommitRecordSerializer.java TestTxJournalProtocol.java Log Message: Working through transactional isolation. --- NEW FILE: TestCommitHistory.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 16, 2007 */ package com.bigdata.journal; import java.nio.ByteBuffer; import java.util.Properties; /** * Test the ability to get (exact match) and find (most recent less than * or equal to) historical commit records in a {@link Journal}. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestCommitHistory extends ProxyTestCase { /** * */ public TestCommitHistory() { } /** * @param name */ public TestCommitHistory(String name) { super(name); } /** * Compare two {@link ICommitRecord}s for equality in their data. * * @param expected * @param actual */ public void assertEquals(ICommitRecord expected, ICommitRecord actual) { if (expected == null) assertNull("Expected actual to be null", actual); else assertNotNull("Expected actual to be non-null", actual); assertEquals("timestamp", expected.getTimestamp(), actual.getTimestamp()); assertEquals("#roots", expected.getRootAddrCount(), actual.getRootAddrCount()); final int n = expected.getRootAddrCount(); for(int i=0; i<n; i++) { if(expected.getRootAddr(i) != actual.getRootAddr(i)) { assertEquals("rootAddr[" + i + "]", expected.getRootAddr(i), actual.getRootAddr(i)); } } } /** * Test that {@link Journal#getCommitRecord(long)} returns null if invoked * before anything has been committed. */ public void test_behaviorBeforeAnythingIsCommitted() { Journal journal = new Journal(getProperties()); assertNull(journal.getCommitRecord(journal.timestampFactory.nextTimestamp())); } /** * Test the ability to recover a {@link ICommitRecord} from the * {@link CommitRecordIndex}. */ public void test_recoverCommitRecord() { Journal journal = new Journal(getProperties()); /* * The first commit flushes the root leaves of some indices so we get * back a non-zero commit timestamp. */ assertTrue(0L!=journal.commit()); /* * A follow up commit in which nothing has been written should return a * 0L timestamp. */ assertEquals(0L,journal.commit()); journal.write(ByteBuffer.wrap(new byte[]{1,2,3})); final long commitTime1 = journal.commit(); assertTrue(commitTime1!=0L); ICommitRecord commitRecord = journal.getCommitRecord(commitTime1); assertNotNull(commitRecord); assertNotNull(journal.getCommitRecord()); assertEquals(commitTime1, journal.getCommitRecord().getTimestamp()); assertEquals(journal.getCommitRecord(),commitRecord); } /** * Tests whether the {@link CommitRecordIndex} is restart-safe. */ public void test_commitRecordIndex_restartSafe() { Properties properties = getProperties(); properties.setProperty(Options.DELETE_ON_CLOSE,"false"); Journal journal = new Journal(properties); if(!journal.isStable()) { // test only applies to restart-safe journals. return; } /* * Write a record directly on the store in order to force a commit to * write a commit record (if you write directly on the store it will not * cause a state change in the root addresses, but it will cause a new * commit record to be written with a new timestamp). */ // write some data. journal.write(ByteBuffer.wrap(new byte[]{1,2,3})); // commit the store. final long commitTime1 = journal.commit(); assertTrue(commitTime1!=0L); ICommitRecord commitRecord1 = journal.getCommitRecord(commitTime1); assertEquals(commitTime1, commitRecord1.getTimestamp()); assertEquals(commitTime1, journal.getRootBlockView().getCommitTimestamp()); /* * Close and then re-open the store and verify that the correct commit * record is returned. */ journal.close(); journal = new Journal(properties); ICommitRecord commitRecord2 = journal.getCommitRecord(); assertEquals(commitRecord1, commitRecord2); /* * Now recover the commit record by searching the commit record index. */ ICommitRecord commitRecord3 = journal.getCommitRecord(commitTime1); assertEquals(commitRecord1, commitRecord3); assertEquals(commitRecord2, commitRecord3); } /** * Tests for finding (less than or equal to) historical commit records using * the commit record index. This also tests restart-safety of the index with * multiple records (if the store is stable). */ public void test_commitRecordIndex_find() { Properties properties = getProperties(); properties.setProperty(Options.DELETE_ON_CLOSE,"false"); Journal journal = new Journal(properties); final int limit = 10; final long[] commitTime = new long[limit]; final long[] commitRecordIndexAddrs = new long[limit]; final ICommitRecord[] commitRecords = new ICommitRecord[limit]; for(int i=0; i<limit; i++) { // write some data. journal.write(ByteBuffer.wrap(new byte[]{1,2,3})); // commit the store. commitTime[i] = journal.commit(); assertTrue(commitTime[i]!=0L); if (i > 0) assertTrue(commitTime[i] > commitTime[i - 1]); commitRecordIndexAddrs[i] = journal.getRootBlockView().getCommitRecordIndexAddr(); assertTrue(commitRecordIndexAddrs[i]!=0L); if (i > 0) assertTrue(commitRecordIndexAddrs[i] > commitRecordIndexAddrs[i - 1]); // get the current commit record. commitRecords[i] = journal.getCommitRecord(); // test exact match on this timestamp. assertEquals(commitRecords[i],journal.getCommitRecord(commitTime[i])); if(i>0) { // test exact match on the prior timestamp. assertEquals(commitRecords[i-1],journal.getCommitRecord(commitTime[i-1])); } /* * Obtain a unique timestamp from the same source that the journal * is using to generate the commit timestamps. This ensures that * there will be at least one possible timestamp between each commit * timestamp. */ final long ts = journal.timestampFactory.nextTimestamp(); assertTrue(ts>commitTime[i]); } if (journal.isStable()) { /* * Close and then re-open the store so that we will also be testing * restart-safety of the commit record index. */ journal.close(); journal = new Journal(properties); } /* * Verify the historical commit records on exact match (get). */ { for( int i=0; i<limit; i++) { assertEquals(commitRecords[i], journal .getCommitRecord(commitTime[i])); } } /* * Verify access to historical records on LTE search (find). * * We ensured above that there is at least one possible timestamp value * between each pair of commit timestamps. We already verified that * timestamps that exactly match a known commit time return the * associated commit record. * * Now we verify that timestamps which proceed a known commit time but * follow after any earlier commit time, return the proceeding commit * record (finds the most recent commit record having a commit time less * than or equal to the probe time). */ { for( int i=1; i<limit; i++) { assertEquals(commitRecords[i - 1], journal .getCommitRecord(commitTime[i] - 1)); } /* * Verify a null return if we probe with a timestamp before any * commit time. */ assertNull(journal.getCommitRecord(commitTime[0] - 1)); } } } --- NEW FILE: TestConflictResolution.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 17, 2007 */ package com.bigdata.journal; /** * Tests of write-write conflict resolution. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestConflictResolution extends ProxyTestCase { /** * */ public TestConflictResolution() { // TODO Auto-generated constructor stub } /** * @param name */ public TestConflictResolution(String name) { super(name); // TODO Auto-generated constructor stub } public void test_something() { fail("write tests"); } } Index: TestTxRunState.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestTxRunState.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** TestTxRunState.java 13 Feb 2007 23:01:01 -0000 1.1 --- TestTxRunState.java 17 Feb 2007 21:34:12 -0000 1.2 *************** *** 52,55 **** --- 52,58 ---- /** + * Test suite for the state machine governing the transaction {@link RunState} + * transitions. + * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ *************** *** 91,95 **** ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getId()); assertTrue( tx0.isActive() ); --- 94,98 ---- ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getStartTimestamp()); assertTrue( tx0.isActive() ); *************** *** 140,144 **** ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getId()); assertTrue( tx0.isActive() ); --- 143,147 ---- ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getStartTimestamp()); assertTrue( tx0.isActive() ); *************** *** 200,204 **** ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getId()); assertTrue( tx0.isActive() ); --- 203,207 ---- ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getStartTimestamp()); assertTrue( tx0.isActive() ); *************** *** 262,266 **** ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getId()); assertTrue( tx0.isActive() ); --- 265,269 ---- ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getStartTimestamp()); assertTrue( tx0.isActive() ); *************** *** 330,334 **** ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getId()); assertTrue( tx0.isActive() ); --- 333,337 ---- ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getStartTimestamp()); assertTrue( tx0.isActive() ); *************** *** 398,402 **** ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getId()); assertTrue( tx0.isActive() ); --- 401,405 ---- ITx tx0 = new Tx(journal,ts0); ! assertEquals(ts0,tx0.getStartTimestamp()); assertTrue( tx0.isActive() ); Index: AbstractTestCase.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/AbstractTestCase.java,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** AbstractTestCase.java 9 Feb 2007 18:56:59 -0000 1.16 --- AbstractTestCase.java 17 Feb 2007 21:34:12 -0000 1.17 *************** *** 72,94 **** * </p> */ - abstract public class AbstractTestCase extends TestCase2 { - // /** - // * The name of the optional property whose boolean value indicates whether - // * or not {@link #dropStore()} should be invoked before each test - // * (default is "false"). - // */ - // public static final String dropBeforeTest = "dropBeforeTest"; - // - // /** - // * The name of the optional property whose boolean value indicates whether - // * or not {@link #dropStore()} should be invoked before each test - // * (default is "false" ). - // */ - // public static final String dropAfterTest = "dropAfterTest"; - // // Constructors. --- 72,79 ---- *************** *** 99,149 **** public AbstractTestCase(String name) {super(name);} - // // - // // Test suite. - // // - // - // /** - // * <p> - // * Appends to the <i>suite</i> the tests defined by this module. - // * </p> - // * - // * @param suite - // * A suite - may be empty. - // */ - // - // public static void addGenericSuite(ProxyTestSuite suite) { - // - // if (suite == null) { - // - // throw new IllegalArgumentException( - // "The ProxyTestSuite may not be null."); - // - // } - // - // /* - // * Create sub-suites (proxy suites) for each package defined in this - // * module. - // */ - //// ProxyTestSuite suite2 = new ProxyTestSuite(suite.getDelegate(),"org.CognitiveWeb.generic"); - //// ProxyTestSuite suite3 = new ProxyTestSuite(suite.getDelegate(),"org.CognitiveWeb.generic.gql"); - //// ProxyTestSuite suite4 = new ProxyTestSuite(suite.getDelegate(),"org.CognitiveWeb.generic.isomorph"); - // - // /* - // * Test suites for the core generic apis. - // */ - // - //// suite2.addTestSuite(IGenericProxyTestCase.class); - // - // /* - // * Combine into the parent test suite using a structure that mirrors the - // * package structure. - // */ - // - //// suite2.addTest(suite3); - //// suite2.addTest(suite4); - //// suite.addTest(suite2); - // - // } - //************************************************************ //************************************************************ --- 84,87 ---- *************** *** 153,161 **** * Invoked from {@link TestCase#setUp()} for each test in the suite. */ - // * This - // * method writes a test header into the log and is responsible for invoking - // * {@link #dropStore()} if the optional boolean property - // * {@link #dropBeforeTest} was specified and has the value "true". - public void setUp(ProxyTestCase testCase) throws Exception { --- 91,94 ---- *************** *** 163,177 **** + ":BEGIN:===================="); - // if (new Boolean(getProperties().getProperty(dropBeforeTest, - // "false")).booleanValue()) { - // - // try { - // dropStore(); - // } catch (Throwable ex) { - // log.error("Could not drop store.", ex); - // } - // - // } - } --- 96,99 ---- *************** *** 179,213 **** * Invoked from {@link TestCase#tearDown()} for each test in the suite. */ - // * This - // * method writes a test trailer into the log and is responsible for invoking - // * {@link #dropStore()} if the optional boolean property - // * {@link #dropAfterTest} was specified and has the value "true". - public void tearDown(ProxyTestCase testCase) throws Exception { - // if (isStoreOpen()) { - // - // log.warn("object manager not closed: test=" + testCase.getName() - // + ", closing now."); - // - // try { - // closeStore(); - // } catch (Throwable ex) { - // log.error("Could not close object manager.", ex); - // } - // - // } - // - // if (new Boolean(getProperties().getProperty(dropAfterTest, - // "false")).booleanValue()) { - // - // try { - // dropStore(); - // } catch (Throwable ex) { - // log.error("Could not drop store.", ex); - // } - // - // } - log.info("\n================:END:" + testCase.getName() + ":END:====================\n"); --- 101,106 ---- *************** *** 236,240 **** * @return A new properties object. */ - public Properties getProperties() { --- 129,132 ---- *************** *** 291,434 **** } - - // // - // // ObjectManager - // // - // - // private IObjectManager m_om; - // - // /** - // * <p> - // * Return the configured object manager. A new object manager will be - // * created if there is not one that is currently configured. - // * </p> - // * - // * @return The configured object manager. - // */ - // public IObjectManager getObjectManager() { - // checkIfProxy(); - // if( m_om == null ) { - // m_om = openStore(); - // } - // return m_om; - // } - // - // /** - // * <p> - // * Closes the current object manager and then opens a new object manager. - // * onto the configured store. - // * </p> - // * - // * @return A new object manager. - // */ - // public IObjectManager reopenStore() { - // checkIfProxy(); - // closeStore(); - // m_om = null; // make sure that this is cleared. - // m_om = openStore(); // make sure that this is re-assigned. - // return m_om; - // } - // - // /** - // * <p> - // * Opens and returns an object manager instance for the configured - // * persistence layer and store. The object manager is configured - // * using the properties returned by {@link #getProperties()}. - // * </p> - // * - // * @return A new object manager instance. - // * - // * @exception IllegalStateException - // * if there is a current object manager. - // */ - // protected IObjectManager openStore() { - // checkIfProxy(); - // if( m_om != null ) { - // throw new IllegalStateException("ObjectManager exists."); - // } - // m_om = ObjectManagerFactory.INSTANCE.newInstance(getProperties()); - // return m_om; - // } - // - // /** - // * <p> - // * Closes the current object manager. - // * </p> - // * - // * @exception IllegalStateException - // * if the object manager is not configured. - // */ - // protected void closeStore() { - // checkIfProxy(); - // if( m_om == null ) { - // throw new IllegalStateException("ObjectManager does not exist."); - // } - // m_om.close(); - // m_om = null; - // } - // - // /** - // * <p> - // * Return true iff the object manager exists. - // * </p> - // * - // * @return True if there is a configured object manager. - // */ - // protected boolean isStoreOpen() { - // checkIfProxy(); - // return m_om != null; - // } - // - // /** - // * <p> - // * Drop the configured database in use for the tests. This method may be - // * automatically invoked before and/or after each test by declaring the - // * appropriate property. - // * </p> - // * <p> - // * The semantics of "drop" depend on the GOM implementation and persistence - // * layer under test and can range from clearing a transient object manager, - // * to deleting the files corresponding to the store on disk, to dropping a - // * test database in a federation. As a rule, the object manager must be - // * closed when this method is invoked. - // * </p> - // * - // * @see #dropBeforeTest - // * @see #dropAfterTest - // */ - // abstract protected void dropStore(); - // - // // - // // Unique property name factory. - // // - // - // private Random r = new Random(); - // - // /** - // * <p> - // * A property name is derived from the test name plus a random integer to - // * avoid side effects. The store is NOT tested to verify that this property - // * name is unique, so it is possible that tests will occasionally fail - // * through rare collisions with existing property names. - // * </p> - // * <p> - // * Note: This method also gets used to generate unique association names and - // * object names. - // * </p> - // */ - // protected String getUniquePropertyName() { - // return getName()+"-"+r.nextInt(); - // } - // - // /** - // * Similar to {@link #getUniquePropertyName()} but embeds <i>name</i> in - // * the returned value. - // * - // * @see #getUniquePropertyName() - // */ - // protected String getUniquePropertyName(String name) { - // return getName()+"-"+name+"-"+r.nextInt(); - // } - //************************************************************ --- 183,186 ---- *************** *** 609,789 **** } - // /** - // * Test helper verifies that the data is deleted. - // */ - // public void assertDeleted(IStore store, int id) { - // - // try { - // - // store.read(id, null); - // - // fail("Expecting " + DataDeletedException.class); - // - // } catch (DataDeletedException ex) { - // - // System.err.println("Ignoring expected exception: " + ex); - // - // } - // - // } - - // /** - // * Test helper checks for the parameter for the semantics of "not found" as - // * defined by {@link IStore#read(int, ByteBuffer)}. - // * - // * @param actual - // * The value returned by either of those methods. - // */ - // public void assertNotFound(ByteBuffer actual) { - // - // assertNull("Expecting 'not found'", actual); - // - // } - - // /** - // * Test the version counter for a persistent identifier in the global scope. - // * - // * @param journal - // * The journal. - // * @param id - // * The int32 within segment persistent identifier. - // * @param expectedVersionCounter - // * The expected value of the version counter. - // * - // * @exception AssertionFailedError - // * if the persistent identifier is not found in the global - // * object index. - // * @exception AssertionFailedError - // * if the identifer is found, but the version counter value - // * differs from the expected version counter. - // */ - // protected void assertVersionCounter(Journal journal, int id, long expectedVersionCounter ) { - // - // // FIXME hardwired to SimpleObjectIndex. - // IObjectIndexEntry entry = ((SimpleObjectIndex)journal.objectIndex).objectIndex.get(id); - // - // if( entry == null ) fail("No entry in journal: id="+id); - // - // assertEquals("versionCounter", expectedVersionCounter, entry.getVersionCounter() ); - // - // } - // - // /** - // * Test the version counter for a persistent identifier in the transaction - // * scope. - // * - // * @param tx - // * The transaction. - // * @param id - // * The int32 within segment persistent identifier. - // * @param expectedVersionCounter - // * The expected value of the version counter. - // * @exception AssertionFailedError - // * if the persistent identifier is not found in the - // * transaction's outer object index (this test does NOT read - // * through to the inner index so you MUST NOT invoke it - // * before the version has been overwritten by the - // * transaction). - // * @exception AssertionFailedError - // * if the identifer is found, but the version counter value - // * differs from the expected version counter. - // */ - // protected void assertVersionCounter(Tx tx, int id, int expectedVersionCounter ) { - // - // // FIXME hardwired to SimpleObjectIndex. - // IObjectIndexEntry entry = ((SimpleObjectIndex)tx.getObjectIndex()).objectIndex.get(id); - // - //// IObjectIndexEntry entry = tx.getObjectIndex().objectIndex.get(id); - // - // if( entry == null ) fail("No entry in transaction: tx="+tx+", id="+id); - // - // assertEquals("versionCounter", (short) expectedVersionCounter, entry.getVersionCounter() ); - // - // } - - // /** - // * Write a data version consisting of N random bytes and verify that we can - // * read it back out again. - // * - // * @param store - // * The store. - // * @param id - // * The int32 within-segment persistent identifier. - // * @param nbytes - // * The data version length. - // * - // * @return The data written. This can be used to re-verify the write after - // * intervening reads. - // */ - // - // protected byte[] doWriteRoundTripTest(IStore store, int id, int nbytes) { - // - // System.err.println("Test writing: id="+id+", nbytes="+nbytes); - // - // byte[] expected = new byte[nbytes]; - // - // r.nextBytes(expected); - // - // ByteBuffer data = ByteBuffer.wrap(expected); - // - //// assertNull((tx == null ? journal.objectIndex.getSlots(id) - //// : tx.getObjectIndex().getSlots(id))); - // - // store.write(id,data); - // assertEquals("limit() != #bytes", expected.length, data.limit()); - // assertEquals("position() != limit()",data.limit(),data.position()); - // - //// ISlotAllocation slots = (tx == null ? journal.objectIndex.getSlots(id) - //// : tx.getObjectIndex().getSlots(id)); - //// assertEquals("#bytes",nbytes,slots.getByteCount()); - //// assertEquals("#slots",journal.slotMath.getSlotCount(nbytes),slots.getSlotCount()); - //// assertEquals(firstSlot,tx.objectIndex.getFirstSlot(id)); - // - // /* - // * Read into a buffer allocated by the Journal. - // */ - // ByteBuffer actual = store.read(id, null); - // - // assertEquals("acutal.position()",0,actual.position()); - // assertEquals("acutal.limit()",expected.length,actual.limit()); - // assertEquals("limit() - position() == #bytes",expected.length,actual.limit() - actual.position()); - // assertEquals(expected,actual); - // - // /* - // * Read multiple copies into a buffer that we allocate ourselves. - // */ - // final int ncopies = 7; - // int pos = 0; - // actual = ByteBuffer.allocate(expected.length * ncopies); - // for( int i=0; i<ncopies; i++ ) { - // - // /* - // * Setup to read into the next slice of our buffer. - // */ - //// System.err.println("reading @ i="+i+" of "+ncopies); - // pos = i * expected.length; - // actual.limit( actual.capacity() ); - // actual.position( pos ); - // - // ByteBuffer tmp = store.read(id, actual); - // assertTrue("Did not read into the provided buffer", tmp == actual); - // assertEquals("position()", pos, actual.position() ); - // assertEquals("limit() - position()", expected.length, actual.limit() - actual.position()); - // assertEquals(expected,actual); - // - // /* - // * Attempt to read with insufficient remaining bytes in the buffer - // * and verify that the data are read into a new buffer. - // */ - // actual.limit(pos+expected.length-1); - // tmp = store.read(id, actual); - // assertFalse("Read failed to allocate a new buffer", tmp == actual); - // assertEquals(expected,tmp); - // - // } - // - // return expected; - // - // } - } --- 361,363 ---- --- NEW FILE: TestCommitRecordSerializer.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 13, 2007 */ package com.bigdata.journal; import java.nio.ByteBuffer; import java.util.Random; import junit.framework.TestCase2; /** * Test suite for {@link CommitRecordSerializer}. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestCommitRecordSerializer extends AbstractCommitRecordTestCase { /** * */ public TestCommitRecordSerializer() { } /** * @param arg0 */ public TestCommitRecordSerializer(String arg0) { super(arg0); } public void test_stress() { final int ntrials = 1000; for(int trial=0;trial<ntrials; trial++) { doRoundTripTest(getRandomCommitRecord()); } } public void doRoundTripTest(ICommitRecord roots) { CommitRecordSerializer ser = CommitRecordSerializer.INSTANCE; assertEquals(roots, ser.deserialize(ByteBuffer.wrap(ser .serialize(roots)))); } } --- NEW FILE: AbstractCommitRecordTestCase.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 16, 2007 */ package com.bigdata.journal; import java.util.Random; import junit.framework.TestCase; /** * Defines some helper methods for testing {@link ICommitRecord}s. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ abstract public class AbstractCommitRecordTestCase extends TestCase { public AbstractCommitRecordTestCase() { } public AbstractCommitRecordTestCase(String name) { super(name); } Random r = new Random(); /** * Compare two {@link ICommitRecord}s for equality in their data. * * @param expected * @param actual */ public void assertEquals(ICommitRecord expected, ICommitRecord actual) { assertEquals("timestamp", expected.getTimestamp(), actual.getTimestamp()); assertEquals("#roots", expected.getRootAddrCount(), actual.getRootAddrCount()); final int n = expected.getRootAddrCount(); for(int i=0; i<n; i++) { assertEquals("rootAddrs", expected.getRootAddr(i), actual.getRootAddr(i)); } } public ICommitRecord getRandomCommitRecord() { final long timestamp = System.currentTimeMillis(); final int n = ICommitRecord.MAX_ROOT_ADDRS; long[] roots = new long[n]; for(int i=0; i<n; i++) { boolean empty = r.nextInt(100)<30; roots[i] = empty ? 0L : r.nextInt(Integer.MAX_VALUE); } return new CommitRecord(timestamp,roots); } } Index: TestJournal.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestJournal.java,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -d -r1.25 -r1.26 *** TestJournal.java 8 Feb 2007 21:32:09 -0000 1.25 --- TestJournal.java 17 Feb 2007 21:34:12 -0000 1.26 *************** *** 101,103 **** --- 101,109 ---- } + public void test_something() { + + fail("write tests"); + + } + } Index: TestJournalBasics.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestJournalBasics.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** TestJournalBasics.java 13 Feb 2007 23:01:01 -0000 1.7 --- TestJournalBasics.java 17 Feb 2007 21:34:13 -0000 1.8 *************** *** 84,88 **** * @see ProxyTestSuite */ - public static Test suite() { --- 84,87 ---- *************** *** 90,102 **** TestSuite suite = new TestSuite("Core Journal Test Suite"); ! // @todo basic journal tests. ! // suite.addTestSuite( TestJournal.class ); ! // tests of creation, loolup, use, commit of named indices. suite.addTestSuite( TestNamedIndices.class ); ! // @todo transactional isolation tests. suite.addTestSuite( TestTxRunState.class ); suite.addTestSuite( TestTx.class ); return suite; --- 89,118 ---- TestSuite suite = new TestSuite("Core Journal Test Suite"); ! // @todo basic journal tests (none are defined yet). ! suite.addTestSuite( TestJournal.class ); ! // tests of creation, lookup, use, commit of named indices. suite.addTestSuite( TestNamedIndices.class ); ! // tests the ability to recover and find historical commit records. ! suite.addTestSuite( TestCommitHistory.class ); ! ! /* ! * 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. + suite.addTestSuite( TestReadCommittedTx.class ); + // @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; Index: TestTx.java =================================================================== RCS file: /cvsroot/cweb/bigdata/src/test/com/bigdata/journal/TestTx.java,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** TestTx.java 13 Feb 2007 23:01:01 -0000 1.15 --- TestTx.java 17 Feb 2007 21:34:12 -0000 1.16 *************** *** 48,60 **** package com.bigdata.journal; - import java.io.IOException; import java.util.Properties; /** ! * Test suite for transaction isolation with respect to the underlying journal. ! * The tests in this suite are designed to verify isolation of changes within ! * the scope of the transaction when compared to the last committed state of the ! * journal. This basically amounts to verifying that operations read through the ! * transaction scope object index into the journal scope object index. * * @todo Do stress test with writes, reads, and deletes. --- 48,66 ---- package com.bigdata.journal; import java.util.Properties; + import com.bigdata.isolation.IsolatedBTree; + import com.bigdata.isolation.UnisolatedBTree; + import com.bigdata.objndx.IIndex; + /** ! * Test suite for fully-isolated read-write transactions. ! * ! * @todo Test suite for transaction isolation with respect to the underlying ! * journal. The tests in this suite are designed to verify isolation of ! * changes within the scope of the transaction when compared to the last ! * committed state of the journal. This basically amounts to verifying ! * that operations read through the transaction scope object index into ! * the journal scope object index. * * @todo Do stress test with writes, reads, and deletes. *************** *** 108,113 **** * transaction starts or - to enforce the data type specificity at the * risk of tighter integration of components - as part of the schema ! * declaration. Declare IConflictResolver that either merges ! * state into object in the transaction or causes the tx to abort. * * @todo Verify correct abort after 'prepare'. --- 114,119 ---- * transaction starts or - to enforce the data type specificity at the * risk of tighter integration of components - as part of the schema ! * declaration. Declare IConflictResolver that either merges state into ! * object in the transaction or causes the tx to abort. * * @todo Verify correct abort after 'prepare'. *************** *** 123,129 **** public class TestTx extends ProxyTestCase { - /** - * - */ public TestTx() { } --- 129,132 ---- *************** *** 134,227 **** /** ! * Test verifiers that duplicate transaction identifiers are detected in the ! * case where the first transaction is active. */ ! public void test_duplicateTransactionIdentifiers01() throws IOException { ! final Properties properties = getProperties(); ! try { ! Journal journal = new Journal(properties); ! Tx tx0 = new Tx(journal,0); ! try { ! // Try to create another transaction with the same identifier. ! new Tx(journal,0); ! ! fail( "Expecting: "+IllegalStateException.class); ! ! } ! catch( IllegalStateException ex ) { ! ! System.err.println("Ignoring expected exception: "+ex); ! ! } ! tx0.abort(); ! journal.close(); ! } finally { ! deleteTestJournalFile(); ! } } ! /** ! * Test verifiers that duplicate transaction identifiers are detected in the ! * case where the first transaction has already prepared. ! * ! * @todo The {@link Journal} does not maintain a collection of committed ! * transaction identifier for transactions that have already ! * committed. However, it might make sense to maintain a transient ! * collection that is rebuilt on restart of those transactions that ! * are waiting for GC. Also, it may be possible to summarily reject ! * transaction identifiers if they are before a timestamp when a ! * transaction service has notified the journal that no active ! * transactions remain before that timestamp. If those modifications ! * are made, then add the appropriate tests here. */ ! public void test_duplicateTransactionIdentifiers02() throws IOException { ! final Properties properties = getProperties(); ! try { ! Journal journal = new Journal(properties); ! ITx tx0 = new Tx(journal,0); ! tx0.prepare(); try { ! // Try to create another transaction with the same identifier. ! new Tx(journal,0); ! fail( "Expecting: "+IllegalStateException.class); - } - - catch( IllegalStateException ex ) { - System.err.println("Ignoring expected exception: "+ex); } - - tx0.abort(); ! journal.close(); ! ! } finally { ! ! deleteTestJournalFile(); ! ! } } --- 137,434 ---- /** ! * Test verifies that a transaction may start when there are (a) no commits ! * on the journal; and (b) no indices have been registered. ! * ! * @todo In the current implementation the transaction will be unable to ! * isolate an index if the index has not been registered already by an ! * unisolated transaction. */ ! public void test_noIndicesRegistered() { ! ! Properties properties = getProperties(); ! ! Journal journal = new Journal(properties); ! ! journal.commit(); ! ITx tx = journal.newTx(); ! ! /* ! * nothing written on this transaction. ! */ ! ! tx.prepare(); ! ! // commit. ! assertTrue(tx.commit()!=0L); ! journal.close(); ! ! } ! /** ! * Verify that an index is not visible in the tx until the native ! * transaction in which it is registered has already committed before ! * the tx starts. ! */ ! public void test_indexNotVisibleUnlessCommitted() { ! ! Properties properties = getProperties(); ! Journal journal = new Journal(properties); ! String name = "abc"; ! ! // register index in unisolated scope, but do not commit yet. ! journal.registerIndex(name, new UnisolatedBTree(journal, 3)); ! ! // start tx1. ! ITx tx1 = journal.newTx(); ! // the index is not visible in tx1. ! assertNull(tx1.getIndex(name)); ! ! // do unisolated commit. ! assertTrue(journal.commit()!=0L); ! ! // start tx2. ! ITx tx2 = journal.newTx(); ! ! // the index still is not visible in tx1. ! assertNull(tx1.getIndex(name)); ! ! // the index is visible in tx2. ! assertNotNull(tx2.getIndex(name)); ! ! tx1.abort(); ! ! tx2.abort(); ! ! journal.close(); ! ! } ! ! /** ! * Create a journal, setup an index, write an entry on that index, and ! * commit the store. Setup a transaction and verify that we can isolated ! * that index and read the written value. Write a value on the unisolated ! * index and verify that it is not visible within the transaction. ! */ ! public void test_readIsolation() { ! ! Properties properties = getProperties(); ! ! Journal journal = new Journal(properties); ! ! final String name = "abc"; ! ! final int branchingFactor = 3; ! ! final byte[] k1 = new byte[]{1}; ! final byte[] k2 = new byte[]{2}; ! ! final byte[] v1 = new byte[]{1}; ! final byte[] v2 = new byte[]{2}; ! ! { ! ! /* ! * register the index, write an entry on the unisolated index, ! * and commit the journal. ! */ ! IIndex index = journal.registerIndex(name, new UnisolatedBTree( ! journal, branchingFactor)); ! ! assertNull(index.insert(k1, v1)); ! assert(journal.commit()!=0L); ! } ! ! ITx tx1 = journal.newTx(); ! ! { ! /* ! * verify that the write is visible in a transaction that starts ! * after the commit. ! */ ! ! IIndex index = tx1.getIndex(name); ! ! assertTrue(index.contains(k1)); ! ! assertEquals(v1,(byte[])index.lookup(k1)); ! ! } ! { ! ! /* ! * obtain the unisolated index and write another entry and commit ! * the journal. ! */ ! ! IIndex index = journal.getIndex(name); ! ! assertNull(index.insert(k2, v2)); ! ! assertTrue(journal.commit()!=0L); ! ! } ! ! { ! ! /* ! * verify that the entry written on the unisolated index is not ! * visible to the transaction that started before that write. ! */ ! IIndex index = tx1.getIndex(name); ! ! assertTrue(index.contains(k1)); ! assertFalse(index.contains(k2)); ! ! } ! ! ITx tx2 = journal.newTx(); ! ! { ! ! /* ! * start another transaction and verify that the 2nd committed ! * write is now visible to that transaction. ! */ ! ! IIndex index = tx2.getIndex(name); ! ! assertTrue(index.contains(k1)); ! assertTrue(index.contains(k2)); ! ! } ! ! tx1.abort(); ! ! journal.close(); } ! /** ! * Test verifies that an isolated write is visible inside of a transaction ! * (tx1) but not in a concurrent transaction (tx2) and not in the unisolated ! * index until the tx1 commits. Once the tx1 commits, the write is visible ! * in the unisolated index. The write never becomes visible in tx2. If tx2 ! * attempts to write a value under the same key then a write-write conflict ! * is reported and validation fails. */ ! public void test_writeIsolation() { ! Properties properties = getProperties(); ! Journal journal = new Journal(properties); ! ! final String name = "abc"; ! ! final int branchingFactor = 3; ! ! final byte[] k1 = new byte[]{1}; ! final byte[] v1 = new byte[]{1}; ! final byte[] v1a = new byte[]{1,1}; ! ! { ! /* ! * register an index and commit the journal. ! */ ! ! journal.registerIndex(name, new UnisolatedBTree(journal, ! branchingFactor)); ! ! assert(journal.commit()!=0L); ! ! } ! /* ! * create two transactions. ! */ ! ! ITx tx1 = journal.newTx(); ! ! ITx tx2 = journal.newTx(); ! ! { ! ! /* ! * write an entry in tx1. verify that the entry is not visible ! * in the unisolated index or in the index as isolated by tx2. ! */ ! ! IsolatedBTree ndx1 = (IsolatedBTree)tx1.getIndex(name); ! ! assertFalse(ndx1.contains(k1)); + assertNull(ndx1.insert(k1,v1)); + + // check the version counter in tx1. + assertEquals("versionCounter", 0, ndx1.getValue(k1) + .getVersionCounter()); + + // not visible in the other tx. + assertFalse(tx2.getIndex(name).contains(k1)); + + // not visible in the unisolated index. + assertFalse(journal.getIndex(name).contains(k1)); + + /* + * commit tx1. verify that the write is still not visible in tx2 but + * that it is now visible in the unisolated index. + */ + + // prepare tx1. + tx1.prepare(); + + // commit tx1. + assertTrue(tx1.commit()!=0L); + + // still not visible in the other tx. + assertFalse(tx2.getIndex(name).contains(k1)); + + // but now visible in the unisolated index. + assertTrue(journal.getIndex(name).contains(k1)); + + // check the version counter in the unisolated index. + assertEquals("versionCounter", 1, ((UnisolatedBTree) journal + .getIndex(name)).getValue(k1).getVersionCounter()); + + /* + * write a conflicting entry in tx2 and verify that validation of + * tx2 fails. + */ + + assertNull(tx2.getIndex(name).insert(k1,v1a)); + + // check the version counter in tx2. + assertEquals("versionCounter", 0, ((IsolatedBTree) tx2 + .getIndex(name)).getValue(k1).getVersionCounter()); + try { ! tx2.prepare(); ! fail("Expecting: "+IllegalStateException.class); ! ! } catch(IllegalStateException ex) { System.err.println("Ignoring expected exception: "+ex); } ! assertTrue(tx2.isAborted()); ! ! } ! ! journal.close(); } --- NEW FILE: TestTxJournalProtocol.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 16, 2007 */ package com.bigdata.journal; import java.io.IOException; import java.util.Properties; /** * Test suite for the integration of the {@link Journal} and the {@link ITx} * implementations. * * @todo the tests in this suite are stale and need to be reviewed, possibly * revised or replaced, and certainly extended. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestTxJournalProtocol extends ProxyTestCase { public TestTxJournalProtocol() { } public TestTxJournalProtocol(String name) { super(name); } /** * Test verifies that duplicate transaction identifiers are detected in the * case where the first transaction is active. */ public void test_duplicateTransactionIdentifiers01() throws IOException { final Properties properties = getProperties(); try { Journal journal = new Journal(properties); Tx tx0 = new Tx(journal,0); try { // Try to create another transaction with the same identifier. new Tx(journal,0); fail( "Expecting: "+IllegalStateException.class); } catch( IllegalStateException ex ) { System.err.println("Ignoring expected exception: "+ex); } tx0.abort(); journal.close(); } finally { deleteTestJournalFile(); } } /** * Test verifies that duplicate transaction identifiers are detected in the * case where the first transaction has already prepared. * * @todo The {@link Journal} does not maintain a collection of committed * transaction identifier for transactions that have already * committed. However, it might make sense to maintain a transient * collection that is rebuilt on restart of those transactions that * are waiting for GC. Also, it may be possible to summarily reject * transaction identifiers if they are before a timestamp when a * transaction service has notified the journal that no active * transactions remain before that timestamp. If those modifications * are made, then add the appropriate tests here. */ public void test_duplicateTransactionIdentifiers02() throws IOException { final Properties properties = getProperties(); try { Journal journal = new Journal(properties); ITx tx0 = new Tx(journal,0); tx0.prepare(); try { // Try to create another transaction with the same identifier. new Tx(journal,0); fail( "Expecting: "+IllegalStateException.class); } catch( IllegalStateException ex ) { System.err.println("Ignoring expected exception: "+ex); ... [truncated message content] |