From: <tho...@us...> - 2011-05-05 19:08:17
|
Revision: 4454 http://bigdata.svn.sourceforge.net/bigdata/?rev=4454&view=rev Author: thompsonbry Date: 2011-05-05 19:08:09 +0000 (Thu, 05 May 2011) Log Message: ----------- This commit ports changes already present in the quads branch back to the trunk. Those changes include: 1. synchronized keyword for BigdataSail#setChangeLog() for visibility guarantee on the field. 2. Semaphore on Journal to protect the unisolated connection used by the Sail. 3. Modified BigdataSail#getUnisolatedConnection() to use the Semaphore declared by the Journal. 4. Modified BTree#handleCommit() to take the lock used by the UnisolatedReadWriteIndex in order to protect against concurrent modification during the commit protocol for a mutable BTree. 5. Renamed TestBigdataSailWithQuads to TestBigdataSailWithQuadsAndNestedSubquery. Nested subquery is no longer supported in the dev branch. The test suite flavors for quads with nested subquery and without inlining have both been deprecated as those store variants are no longer supported in the dev branch. 6. Copied the version of TestRollbacks from the quads branch. 7. Copied the version of TestBootstrapBigdataSail from the quads branch. The only obvious problem as of this commit is that TestRollbacks fails in the trunk while it passes in the quads branch. I suspect that this has to do with the manner in which we use a full transaction for read-only connections in the quads branch while the trunk only uses a read-historical read. This last point needs to be investigated further and the problem demonstrated by TestRollbacks resolved in one way or another. There were several changes made to the quads branch when we changed to use a read-only transaction for BigdataSail#getReadOnlyConnection(). If that behavior is to be ported back to the trunk, then a more extensive survey will have to be performed. Modified Paths: -------------- trunk/bigdata/src/java/com/bigdata/btree/BTree.java trunk/bigdata/src/java/com/bigdata/journal/Journal.java trunk/bigdata-sails/src/java/com/bigdata/rdf/sail/BigdataSail.java trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoins.java trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoinsWithoutInlining.java trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBootstrapBigdataSail.java trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/contrib/TestRollbacks.java Added Paths: ----------- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndNestedSubquery.java Removed Paths: ------------- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuads.java Modified: trunk/bigdata/src/java/com/bigdata/btree/BTree.java =================================================================== --- trunk/bigdata/src/java/com/bigdata/btree/BTree.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata/src/java/com/bigdata/btree/BTree.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -29,6 +29,7 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; import com.bigdata.BigdataStatics; import com.bigdata.btree.AbstractBTreeTupleCursor.MutableBTreeTupleCursor; @@ -1126,30 +1127,47 @@ assertNotTransient(); assertNotReadOnly(); - if (/*autoCommit &&*/ needsCheckpoint()) { + /* + * Note: Acquiring this lock provides for atomicity of the checkpoint of + * the BTree during the commit protocol. Without this lock, users of the + * UnisolatedReadWriteIndex could be concurrently modifying the BTree + * while we are attempting to snapshot it for the commit. + * + * @see https://sourceforge.net/apps/trac/bigdata/ticket/288 + * + * @see https://sourceforge.net/apps/trac/bigdata/ticket/278 + */ + final Lock lock = new UnisolatedReadWriteIndex(this).writeLock(); + try { + + if (/* autoCommit && */needsCheckpoint()) { - /* - * Flush the btree, write a checkpoint record, and return the - * address of that checkpoint record. The [checkpoint] reference is - * also updated. - */ + /* + * Flush the btree, write a checkpoint record, and return the + * address of that checkpoint record. The [checkpoint] reference + * is also updated. + */ - return writeCheckpoint(); + return writeCheckpoint(); - } + } - /* - * There have not been any writes on this btree or auto-commit is - * disabled. - * - * Note: if the application has explicitly invoked writeCheckpoint() - * then the returned address will be the address of that checkpoint - * record and the BTree will have a new checkpoint address made restart - * safe on the backing store. - */ + /* + * There have not been any writes on this btree or auto-commit is + * disabled. + * + * Note: if the application has explicitly invoked writeCheckpoint() + * then the returned address will be the address of that checkpoint + * record and the BTree will have a new checkpoint address made + * restart safe on the backing store. + */ - return checkpoint.addrCheckpoint; - + return checkpoint.addrCheckpoint; + + } finally { + lock.unlock(); + } + } /** Modified: trunk/bigdata/src/java/com/bigdata/journal/Journal.java =================================================================== --- trunk/bigdata/src/java/com/bigdata/journal/Journal.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata/src/java/com/bigdata/journal/Journal.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -33,6 +33,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -1203,4 +1204,76 @@ } private final LatchedExecutor readService; + /** + * A Journal level semaphore used to restrict applications to a single + * unisolated connection. The "unisolated" connection is an application + * level construct which supports highly scalable ACID operations but only a + * single such "connection" can exist at a time for a Journal. This + * constraint arises from the need for the application to coordinate + * operations on the low level indices and commit/abort processing while it + * holds the permit. + * <p> + * Note: If by some chance the permit has become "lost" it can be rebalanced + * by {@link Semaphore#release()}. However, uses of this {@link Semaphore} + * should ensure that it is release along all code paths, including a + * finalizer if necessary. + */ + private final Semaphore unisolatedSemaphore = new Semaphore(1/* permits */, + false/* fair */); + + /** + * Acquire a permit for the UNISOLATED connection. + * + * @throws InterruptedException + */ + public void acquireUnisolatedConnection() throws InterruptedException { + + unisolatedSemaphore.acquire(); + + if (log.isDebugEnabled()) + log.debug("acquired semaphore: availablePermits=" + + unisolatedSemaphore.availablePermits()); + + if (unisolatedSemaphore.availablePermits() != 0) { + /* + * Note: This test can not be made atomic with the Semaphore API. It + * is possible unbalanced calls to release() could drive the #of + * permits in the Semaphore above ONE (1) since the Semaphore + * constructor does not place an upper bound on the #of permits, but + * rather sets the initial #of permits available. An attempt to + * acquire a permit which has a post-condition with additional + * permits available will therefore "eat" a permit. + */ + throw new IllegalStateException(); + } + + } + + /** + * Release the permit for the UNISOLATED connection. + * + * @throws IllegalStateException + * unless the #of permits available is zero. + */ + public void releaseUnisolatedConnection() { + + if (log.isDebugEnabled()) + log.debug("releasing semaphore: availablePermits=" + + unisolatedSemaphore.availablePermits()); + + if (unisolatedSemaphore.availablePermits() != 0) { + /* + * Note: This test can not be made atomic with the Semaphore API. It + * is possible that a concurrent call could drive the #of permits in + * the Semaphore above ONE (1) since the Semaphore constructor does + * not place an upper bound on the #of permits, but rather sets the + * initial #of permits available. + */ + throw new IllegalStateException(); + } + + unisolatedSemaphore.release(); + + } + } Modified: trunk/bigdata-sails/src/java/com/bigdata/rdf/sail/BigdataSail.java =================================================================== --- trunk/bigdata-sails/src/java/com/bigdata/rdf/sail/BigdataSail.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata-sails/src/java/com/bigdata/rdf/sail/BigdataSail.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -1156,12 +1156,18 @@ public BigdataSailConnection getUnisolatedConnection() throws InterruptedException { - Lock writeLock = lock.writeLock(); + if (getDatabase().getIndexManager() instanceof Journal) { + // acquire permit from Journal. + ((Journal) getDatabase().getIndexManager()) + .acquireUnisolatedConnection(); + } + + final Lock writeLock = lock.writeLock(); writeLock.lock(); // new writable connection. - final BigdataSailConnection conn = - new BigdataSailConnection(database, writeLock); + final BigdataSailConnection conn = new BigdataSailConnection(database, + writeLock, true/* unisolated */); return conn; @@ -1197,7 +1203,7 @@ database.getNamespace(), TimestampUtility.asHistoricalRead(timestamp)); - return new BigdataSailConnection(view, null); + return new BigdataSailConnection(view, null, false/*unisolated*/); } @@ -1225,7 +1231,7 @@ final Lock readLock = lock.readLock(); readLock.lock(); - return new BigdataSailConnection(readLock) { + return new BigdataSailConnection(readLock,false/*unisolated*/) { /** * The transaction id. @@ -1428,8 +1434,21 @@ * Used to coordinate between read/write transactions and the unisolated * view. */ - private Lock lock; + final private Lock lock; + /** + * <code>true</code> iff this is the UNISOLATED connection (only one of + * those at a time). + */ + private final boolean unisolated; + + public String toString() { + + return getClass().getName() + "{timestamp=" + + TimestampUtility.toString(database.getTimestamp()) + "}"; + + } + /** * Return the assertion buffer. * <p> @@ -1539,10 +1558,11 @@ } - protected BigdataSailConnection(final Lock lock) { + protected BigdataSailConnection(final Lock lock,final boolean unisolated) { this.lock = lock; - + this.unisolated = unisolated; + } /** @@ -1553,11 +1573,12 @@ * {@link SailConnection} will not support update. */ protected BigdataSailConnection(final AbstractTripleStore database, - final Lock lock) { + final Lock lock, final boolean unisolated) { attach(database); this.lock = lock; + this.unisolated = unisolated; } @@ -2663,6 +2684,11 @@ if (lock != null) { lock.unlock(); } + if (unisolated && getDatabase().getIndexManager() instanceof Journal) { + // release the permit. + ((Journal) getDatabase().getIndexManager()) + .releaseUnisolatedConnection(); + } open = false; } @@ -3471,7 +3497,7 @@ * @param log * the change log */ - public void setChangeLog(final IChangeLog changeLog) { + synchronized public void setChangeLog(final IChangeLog changeLog) { this.changeLog = changeLog; Deleted: trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuads.java =================================================================== --- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuads.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuads.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -1,176 +0,0 @@ -/** -Copyright (C) SYSTAP, LLC 2006-2007. All rights reserved. - -Contact: - SYSTAP, LLC - 4501 Tower Road - Greensboro, NC 27410 - lic...@bi... - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/* - * Created on Sep 4, 2008 - */ - -package com.bigdata.rdf.sail; - -import java.util.Properties; - -import junit.extensions.proxy.ProxyTestSuite; -import junit.framework.Test; -import junit.framework.TestSuite; - -import com.bigdata.rdf.axioms.NoAxioms; -import com.bigdata.rdf.sail.BigdataSail.Options; -import com.bigdata.rdf.sail.tck.BigdataConnectionTest; -import com.bigdata.rdf.sail.tck.BigdataSparqlTest; -import com.bigdata.rdf.sail.tck.BigdataStoreTest; -import com.bigdata.relation.AbstractResource; - -/** - * Test suite for the {@link BigdataSail} with quads enabled. The provenance - * mode is disabled. Inference is disabled. - * - * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - * @version $Id$ - */ -public class TestBigdataSailWithQuads extends AbstractBigdataSailTestCase { - - /** - * - */ - public TestBigdataSailWithQuads() { - } - - public TestBigdataSailWithQuads(String name) { - super(name); - } - - public static Test suite() { - - final TestBigdataSailWithQuads delegate = new TestBigdataSailWithQuads(); // !!!! THIS CLASS !!!! - - /* - * Use a proxy test suite and specify the delegate. - */ - - final ProxyTestSuite suite = new ProxyTestSuite(delegate, "SAIL with Quads (nested subquery joins)"); - - // test pruning of variables not required for downstream processing. - suite.addTestSuite(TestPruneBindingSets.class); - - // misc named graph API stuff. - suite.addTestSuite(TestQuadsAPI.class); - - // SPARQL named graphs tests. - suite.addTestSuite(TestNamedGraphs.class); - - // test suite for optionals handling (left joins). - suite.addTestSuite(TestOptionals.class); - - // test of the search magic predicate - suite.addTestSuite(TestSearchQuery.class); - - // high-level query tests. - suite.addTestSuite(TestQuery.class); - - // test of high-level query on a graph with statements about statements. - suite.addTestSuite(TestProvenanceQuery.class); - - // unit tests for custom evaluation of high-level query - suite.addTestSuite(TestBigdataSailEvaluationStrategyImpl.class); - - suite.addTestSuite(TestUnions.class); - - suite.addTestSuite(TestDescribe.class); - - // The Sesame TCK, including the SPARQL test suite. - { - - final TestSuite tckSuite = new TestSuite("Sesame 2.x TCK"); - - tckSuite.addTestSuite(BigdataStoreTest.LTSWithNestedSubquery.class); - - tckSuite.addTestSuite(BigdataConnectionTest.LTSWithNestedSubquery.class); - - try { - - tckSuite.addTest(BigdataSparqlTest.suiteLTSWithNestedSubquery()); - - } catch (Exception ex) { - - throw new RuntimeException(ex); - - } - - suite.addTest(tckSuite); - - } - - return suite; - - } - - @Override - protected BigdataSail getSail(final Properties properties) { - - return new BigdataSail(properties); - - } - - public Properties getProperties() { - - final Properties properties = new Properties(super.getProperties()); -/* - properties.setProperty(Options.STATEMENT_IDENTIFIERS, "false"); - - properties.setProperty(Options.QUADS, "true"); - - properties.setProperty(Options.AXIOMS_CLASS, NoAxioms.class.getName()); -*/ - properties.setProperty(Options.QUADS_MODE, "true"); - - properties.setProperty(Options.TRUTH_MAINTENANCE, "false"); - - properties.setProperty(AbstractResource.Options.NESTED_SUBQUERY, "true"); - - return properties; - - } - - @Override - protected BigdataSail reopenSail(final BigdataSail sail) { - - final Properties properties = sail.database.getProperties(); - - if (sail.isOpen()) { - - try { - - sail.shutDown(); - - } catch (Exception ex) { - - throw new RuntimeException(ex); - - } - - } - - return getSail(properties); - - } - -} Copied: trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndNestedSubquery.java (from rev 4431, trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuads.java) =================================================================== --- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndNestedSubquery.java (rev 0) +++ trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndNestedSubquery.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -0,0 +1,180 @@ +/** +Copyright (C) SYSTAP, LLC 2006-2007. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + * Created on Sep 4, 2008 + */ + +package com.bigdata.rdf.sail; + +import java.util.Properties; + +import junit.extensions.proxy.ProxyTestSuite; +import junit.framework.Test; +import junit.framework.TestSuite; + +import com.bigdata.rdf.axioms.NoAxioms; +import com.bigdata.rdf.sail.BigdataSail.Options; +import com.bigdata.rdf.sail.tck.BigdataConnectionTest; +import com.bigdata.rdf.sail.tck.BigdataSparqlTest; +import com.bigdata.rdf.sail.tck.BigdataStoreTest; +import com.bigdata.relation.AbstractResource; + +/** + * Test suite for the {@link BigdataSail} with quads enabled. The provenance + * mode is disabled. Inference is disabled. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id$ + * + * @deprecated Support for nested subquery has been dropped in the development branch. + */ +public class TestBigdataSailWithQuadsAndNestedSubquery extends AbstractBigdataSailTestCase { + + /** + * + */ + public TestBigdataSailWithQuadsAndNestedSubquery() { + } + + public TestBigdataSailWithQuadsAndNestedSubquery(String name) { + super(name); + } + + public static Test suite() { + + final TestBigdataSailWithQuadsAndNestedSubquery delegate = new TestBigdataSailWithQuadsAndNestedSubquery(); // !!!! THIS CLASS !!!! + + /* + * Use a proxy test suite and specify the delegate. + */ + + final ProxyTestSuite suite = new ProxyTestSuite(delegate, "SAIL with Quads (nested subquery joins)"); + + // test pruning of variables not required for downstream processing. + suite.addTestSuite(TestPruneBindingSets.class); + + // misc named graph API stuff. + suite.addTestSuite(TestQuadsAPI.class); + + // SPARQL named graphs tests. + suite.addTestSuite(TestNamedGraphs.class); + + // test suite for optionals handling (left joins). + suite.addTestSuite(TestOptionals.class); + + // test of the search magic predicate + suite.addTestSuite(TestSearchQuery.class); + + // high-level query tests. + suite.addTestSuite(TestQuery.class); + + // test of high-level query on a graph with statements about statements. + suite.addTestSuite(TestProvenanceQuery.class); + + // unit tests for custom evaluation of high-level query + suite.addTestSuite(TestBigdataSailEvaluationStrategyImpl.class); + + suite.addTestSuite(TestUnions.class); + + suite.addTestSuite(TestDescribe.class); + + suite.addTestSuite(com.bigdata.rdf.sail.contrib.TestRollbacks.class); + + // The Sesame TCK, including the SPARQL test suite. + { + + final TestSuite tckSuite = new TestSuite("Sesame 2.x TCK"); + + tckSuite.addTestSuite(BigdataStoreTest.LTSWithNestedSubquery.class); + + tckSuite.addTestSuite(BigdataConnectionTest.LTSWithNestedSubquery.class); + + try { + + tckSuite.addTest(BigdataSparqlTest.suiteLTSWithNestedSubquery()); + + } catch (Exception ex) { + + throw new RuntimeException(ex); + + } + + suite.addTest(tckSuite); + + } + + return suite; + + } + + @Override + protected BigdataSail getSail(final Properties properties) { + + return new BigdataSail(properties); + + } + + public Properties getProperties() { + + final Properties properties = new Properties(super.getProperties()); +/* + properties.setProperty(Options.STATEMENT_IDENTIFIERS, "false"); + + properties.setProperty(Options.QUADS, "true"); + + properties.setProperty(Options.AXIOMS_CLASS, NoAxioms.class.getName()); +*/ + properties.setProperty(Options.QUADS_MODE, "true"); + + properties.setProperty(Options.TRUTH_MAINTENANCE, "false"); + + properties.setProperty(AbstractResource.Options.NESTED_SUBQUERY, "true"); + + return properties; + + } + + @Override + protected BigdataSail reopenSail(final BigdataSail sail) { + + final Properties properties = sail.database.getProperties(); + + if (sail.isOpen()) { + + try { + + sail.shutDown(); + + } catch (Exception ex) { + + throw new RuntimeException(ex); + + } + + } + + return getSail(properties); + + } + +} Modified: trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoins.java =================================================================== --- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoins.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoins.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -32,7 +32,6 @@ import junit.framework.Test; import junit.framework.TestSuite; -import com.bigdata.rdf.axioms.NoAxioms; import com.bigdata.rdf.sail.BigdataSail.Options; import com.bigdata.rdf.sail.tck.BigdataConnectionTest; import com.bigdata.rdf.sail.tck.BigdataSparqlTest; @@ -97,7 +96,9 @@ suite.addTestSuite(TestDescribe.class); - // The Sesame TCK, including the SPARQL test suite. + suite.addTestSuite(com.bigdata.rdf.sail.contrib.TestRollbacks.class); + + // The Sesame TCK, including the SPARQL test suite. { final TestSuite tckSuite = new TestSuite("Sesame 2.x TCK"); Modified: trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoinsWithoutInlining.java =================================================================== --- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoinsWithoutInlining.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuadsAndPipelineJoinsWithoutInlining.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -46,6 +46,8 @@ * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ + * + * @deprecated Support for inlining is non-optional in the development branch. */ public class TestBigdataSailWithQuadsAndPipelineJoinsWithoutInlining extends AbstractBigdataSailTestCase { @@ -97,6 +99,8 @@ suite.addTestSuite(TestDescribe.class); + suite.addTestSuite(com.bigdata.rdf.sail.contrib.TestRollbacks.class); + // The Sesame TCK, including the SPARQL test suite. { Modified: trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBootstrapBigdataSail.java =================================================================== --- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBootstrapBigdataSail.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBootstrapBigdataSail.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -30,8 +30,15 @@ import java.io.File; import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import junit.framework.TestCase; +import junit.framework.TestCase2; import org.openrdf.model.Statement; import org.openrdf.model.URI; @@ -41,8 +48,13 @@ import org.openrdf.sail.SailConnection; import org.openrdf.sail.SailException; +import com.bigdata.journal.ITx; +import com.bigdata.journal.Journal; import com.bigdata.rdf.model.BigdataStatement; +import com.bigdata.rdf.sail.BigdataSail.BigdataSailConnection; import com.bigdata.rdf.sail.BigdataSail.Options; +import com.bigdata.rdf.store.AbstractTripleStore; +import com.bigdata.rdf.store.LocalTripleStore; /** * Bootstrap test case for bringing up the {@link BigdataSail}. @@ -50,7 +62,7 @@ * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ -public class TestBootstrapBigdataSail extends TestCase { +public class TestBootstrapBigdataSail extends TestCase2 { /** * @@ -71,33 +83,19 @@ * @throws SailException */ public void test_ctor_1() throws SailException { - + final BigdataSail sail = new BigdataSail(); - sail.initialize(); - try { + sail.initialize(); + sail.shutDown(); + + } finally { - } + sail.getDatabase().getIndexManager().destroy(); - finally { - - String filename = sail.properties.getProperty(Options.FILE); - - if (filename != null) { - - File file = new File(filename); - - if(file.exists() && ! file.delete()) { - - fail("Could not delete file after test: "+filename); - - } - - } - } } @@ -121,22 +119,20 @@ } - Properties properties = new Properties(); + final Properties properties = new Properties(); properties.setProperty(Options.FILE, file.toString()); - BigdataSail sail = new BigdataSail(properties); + final BigdataSail sail = new BigdataSail(properties); - sail.initialize(); - try { + sail.initialize(); + sail.shutDown(); - } + } finally { - finally { - if (!file.exists()) { fail("Could not locate store: " + file); @@ -161,94 +157,403 @@ */ public void test_getConnection() throws SailException { - final File file = new File(getName() + Options.JNL); - - if(file.exists()) { - - if(!file.delete()) { - - fail("Could not delete file before test: " + file); + final Properties properties = new Properties(); - } - - } + properties.setProperty(Options.CREATE_TEMP_FILE, "true"); - final Properties properties = new Properties(); + final BigdataSail sail = new BigdataSail(properties); - properties.setProperty(Options.FILE, file.toString()); + try { - final BigdataSail sail = new BigdataSail(properties); + sail.initialize(); - sail.initialize(); - - try { + final SailConnection conn = sail.getConnection(); - final SailConnection conn = sail.getConnection(); - - conn.close(); - - sail.shutDown(); + conn.close(); - } + sail.shutDown(); - finally { + } finally { - if (!file.exists()) { + sail.getDatabase().getIndexManager().destroy(); - fail("Could not locate store: " + file); + } - if (!file.delete()) { + } - fail("Could not delete file after test: " + file); + /** + * Unit test verifies that a thread may not obtain more than one instance of + * the unisolated connection at a time from the {@link BigdataSail}. + * + * @throws SailException + * @throws InterruptedException + * + * FIXME Re-propagate test changes to the trunk along with the + * changes to Journal (the semaphore) and to BigdataSail (using + * the semaphore). + * + * @throws ExecutionException + */ + public void test_getConnectionAllowedExactlyOnce1() throws SailException, + InterruptedException, ExecutionException { - } + final Properties properties = new Properties(); - } + properties.setProperty(Options.CREATE_TEMP_FILE, "true"); - } + ExecutorService service = null; + final BigdataSail sail = new BigdataSail(properties); - } + try { - /** - * Test creates a database, obtains a writable connection, writes some data - * on the store, verifies that the data can be read back from within the - * connection but that it is not visible in a read-committed view, commits - * the write set, and verifies that the data is now visible in a - * read-committed view. - * - * @todo variant that writes, aborts the write, and verifies that the data - * was not made restart safe. - * - * @throws SailException - */ - public void test_isolation() throws SailException { + sail.initialize(); + service = Executors.newSingleThreadExecutor(); - final File file = new File(getName() + Options.JNL); - - if(file.exists()) { - - if(!file.delete()) { - - fail("Could not delete file before test: " + file); + Future<Void> f = null; + + try { - } - - } + final Callable<Void> task = new Callable<Void>() { - final Properties properties = new Properties(); + public Void call() throws Exception { - properties.setProperty(Options.FILE, file.toString()); + SailConnection conn1 = null; + SailConnection conn2 = null; - final BigdataSail sail = new BigdataSail(properties); + try { - sail.initialize(); - - final SailConnection conn = sail.getConnection(); - - final SailConnection readConn = sail.getReadOnlyConnection(); - - try { + log.info("Requesting 1st unisolated connection."); + conn1 = sail.getUnisolatedConnection(); + + log.info("Requesting 2nd unisolated connection."); + + conn2 = sail.getUnisolatedConnection(); + + fail("Not expecting a 2nd unisolated connection"); + + return (Void) null; + + } finally { + + if (conn1 != null) + conn1.close(); + + if (conn2 != null) + conn2.close(); + + } + } + + }; + + // run task. it should block when attempting to get the 2nd + // connection. + f = service.submit(task); + + // wait up to a timeout to verify that the task blocked rather + // than acquiring the 2nd connection. + f.get(250, TimeUnit.MILLISECONDS); + + } catch (TimeoutException e) { + + /* + * This is the expected outcome. + */ + log.info("timeout"); + + } finally { + + if (f != null) { + // Cancel task. + f.cancel(true/* mayInterruptIfRunning */); + } + + sail.shutDown(); + + } + + } finally { + + if (service != null) { + service.shutdownNow(); + } + + sail.getDatabase().getIndexManager().destroy(); + + } + + } + + /** + * Unit test verifies exactly one unisolated connection for two different + * {@link BigdataSail} instances for the same {@link AbstractTripleStore} on + * the same {@link Journal}. + * + * @throws SailException + * @throws InterruptedException + */ + public void test_getConnectionAllowedExactlyOnce2() throws SailException, + InterruptedException, ExecutionException { + + final Properties properties = new Properties(); + + properties.setProperty(Options.CREATE_TEMP_FILE, "true"); + + ExecutorService service = null; + final BigdataSail sail = new BigdataSail(properties); + + try { + + sail.initialize(); + service = Executors.newSingleThreadExecutor(); + + // wrap a 2nd sail around the same tripleStore. + final BigdataSail sail2 = new BigdataSail(sail.getDatabase()); + sail2.initialize(); + + Future<Void> f = null; + + try { + + final Callable<Void> task = new Callable<Void>() { + + public Void call() throws Exception { + + SailConnection conn1 = null; + SailConnection conn2 = null; + + try { + + log.info("Requesting 1st unisolated connection."); + + conn1 = sail.getUnisolatedConnection(); + + log.info("Requesting 2nd unisolated connection."); + + conn2 = sail2.getUnisolatedConnection(); + + fail("Not expecting a 2nd unisolated connection"); + + return (Void) null; + + } finally { + + if (conn1 != null) + conn1.close(); + + if (conn2 != null) + conn2.close(); + + } + } + + }; + + // run task. it should block when attempting to get the 2nd + // connection. + f = service.submit(task); + + // wait up to a timeout to verify that the task blocked rather + // than acquiring the 2nd connection. + f.get(250, TimeUnit.MILLISECONDS); + + } catch (TimeoutException e) { + + /* + * This is the expected outcome. + */ + log.info("timeout"); + + } finally { + + if (f != null) { + // Cancel task. + f.cancel(true/* mayInterruptIfRunning */); + } + + if (sail2 != null) + sail2.shutDown(); + + sail.shutDown(); + + } + + } finally { + + if (service != null) { + service.shutdownNow(); + } + + sail.getDatabase().getIndexManager().destroy(); + + } + + } + + /** + * Unit test verifying that exactly one unisolated connection is allowed at + * a time for two sails wrapping different {@link AbstractTripleStore} + * instances. (This guarantee is needed to preserve ACID semantics for the + * unisolated connection when there is more than one + * {@link AbstractTripleStore} on the same {@link Journal}. However, + * scale-out should not enforce this constraint since it is shard-wise ACID + * for unisolated operations.) + * + * @throws SailException + * @throws InterruptedException + */ + public void test_getConnectionAllowedExactlyOnce3() throws SailException, + InterruptedException, ExecutionException { + + final Properties properties = new Properties(); + + properties.setProperty(Options.CREATE_TEMP_FILE, "true"); + + ExecutorService service = null; + final BigdataSail sail = new BigdataSail(properties); + + try { + + sail.initialize(); + service = Executors.newSingleThreadExecutor(); + + // wrap a 2nd sail around a different tripleStore. + final BigdataSail sail2; + { + + // tunnel through to the Journal. + final Journal jnl = (Journal) sail.getDatabase() + .getIndexManager(); + + // describe another tripleStore with a distinct namespace. + final AbstractTripleStore tripleStore = new LocalTripleStore( + jnl, "foo", ITx.UNISOLATED, properties); + + // create that triple store. + tripleStore.create(); + + // wrap a 2nd sail around the 2nd tripleStore. + sail2 = new BigdataSail(tripleStore); + sail2.initialize(); + + } + + Future<Void> f = null; + + try { + + final Callable<Void> task = new Callable<Void>() { + + public Void call() throws Exception { + + SailConnection conn1 = null; + SailConnection conn2 = null; + + try { + + log.info("Requesting 1st unisolated connection."); + + conn1 = sail.getUnisolatedConnection(); + + log.info("Requesting 2nd unisolated connection."); + + conn2 = sail2.getUnisolatedConnection(); + + fail("Not expecting a 2nd unisolated connection"); + + return (Void) null; + + } finally { + + if (conn1 != null) + conn1.close(); + + if (conn2 != null) + conn2.close(); + + } + } + + }; + + // run task. it should block when attempting to get the 2nd + // connection. + f = service.submit(task); + + // wait up to a timeout to verify that the task blocked rather + // than acquiring the 2nd connection. + f.get(250, TimeUnit.MILLISECONDS); + + } catch (TimeoutException e) { + + /* + * This is the expected outcome. + */ + log.info("timeout"); + + } finally { + + if (f != null) { + // Cancel task. + f.cancel(true/* mayInterruptIfRunning */); + } + + if (sail2 != null) + sail2.shutDown(); + + sail.shutDown(); + + } + + } finally { + + if (service != null) { + service.shutdownNow(); + } + + sail.getDatabase().getIndexManager().destroy(); + + } + + } + + /** + * Test creates a database, obtains a writable connection, writes some data + * on the store, verifies that the data can be read back from within the + * connection but that it is not visible in a read-committed view, commits + * the write set, and verifies that the data is now visible in a + * read-committed view. + * + * TODO variant that writes, aborts the write, and verifies that the data + * was not made restart safe. + * + * @throws SailException + * @throws InterruptedException + */ + public void test_isolationOfUnisolatedConnection() throws SailException, + InterruptedException { + + final Properties properties = new Properties(); + + properties.setProperty(Options.CREATE_TEMP_FILE, "true"); + + BigdataSailConnection conn = null; + + BigdataSailConnection readConn = null; + + final BigdataSail sail = new BigdataSail(properties); + + try { + + sail.initialize(); + + // the unisolated connection + conn = sail.getUnisolatedConnection(); + + // a read-only transaction. + readConn = sail.getReadOnlyConnection(); + final URI s = new URIImpl("http://www.bigdata.com/s"); final URI p = new URIImpl("http://www.bigdata.com/p"); @@ -348,32 +653,26 @@ } - } + } finally { - finally { - if (conn != null) conn.close(); if (readConn != null) readConn.close(); - sail.shutDown(); + sail.getDatabase().getIndexManager().destroy(); - if (!file.exists()) { - - fail("Could not locate store: " + file); - - if (!file.delete()) { - - fail("Could not delete file after test: " + file); - - } - - } - } } + /** + * Unit test verifies that we can mix read/write transactions and the use + * of the unisolated connection. + */ + public void test_readWriteTxAndUnisolatedConnection() { + fail("write this test"); + } + } Modified: trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/contrib/TestRollbacks.java =================================================================== --- trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/contrib/TestRollbacks.java 2011-05-05 18:12:38 UTC (rev 4453) +++ trunk/bigdata-sails/src/test/com/bigdata/rdf/sail/contrib/TestRollbacks.java 2011-05-05 19:08:09 UTC (rev 4454) @@ -1,296 +1,358 @@ -/** -Copyright (C) SYSTAP, LLC 2011. All rights reserved. - -Contact: - SYSTAP, LLC - 4501 Tower Road - Greensboro, NC 27410 - lic...@bi... - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package com.bigdata.rdf.sail.contrib; - -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicReference; - -import org.openrdf.OpenRDFException; -import org.openrdf.model.URI; -import org.openrdf.model.Value; -import org.openrdf.query.MalformedQueryException; -import org.openrdf.query.QueryEvaluationException; -import org.openrdf.query.QueryLanguage; -import org.openrdf.query.TupleQuery; -import org.openrdf.query.TupleQueryResult; -import org.openrdf.repository.RepositoryConnection; -import org.openrdf.repository.RepositoryException; -import org.openrdf.repository.sail.SailRepository; - -import com.bigdata.journal.IIndexManager; -import com.bigdata.rdf.axioms.NoAxioms; -import com.bigdata.rdf.sail.BigdataSail; -import com.bigdata.rdf.sail.QuadsTestCase; -import com.bigdata.rdf.vocab.NoVocabulary; - -/** - * Unit test template for use in submission of bugs. - * <p> - * This test case will delegate to an underlying backing store. You can specify - * this store via a JVM property as follows: - * <code>-DtestClass=com.bigdata.rdf.sail.TestBigdataSailWithQuads</code> - * <p> - * There are three possible configurations for the testClass: - * <ul> - * <li>com.bigdata.rdf.sail.TestBigdataSailWithQuads (quads mode)</li> - * <li>com.bigdata.rdf.sail.TestBigdataSailWithoutSids (triples mode)</li> - * <li>com.bigdata.rdf.sail.TestBigdataSailWithSids (SIDs mode)</li> - * </ul> - * <p> - * The default for triples and SIDs mode is for inference with truth maintenance - * to be on. If you would like to turn off inference, make sure to do so in - * {@link #getProperties()}. - * - * @author <a href="mailto:mrp...@us...">Mike Personick</a> - * @version $Id$ - */ -public class TestRollbacks extends QuadsTestCase { - public TestRollbacks() { - } - - public TestRollbacks(String arg0) { - super(arg0); - } - - /** - * Please set your database properties here, except for your journal file, - * please DO NOT SPECIFY A JOURNAL FILE. - */ - @Override - public Properties getProperties() { - Properties props = super.getProperties(); - - /* - * For example, here is a set of five properties that turns off - * inference, truth maintenance, and the free text index. - */ - props.setProperty(BigdataSail.Options.AXIOMS_CLASS, - NoAxioms.class.getName()); - props.setProperty(BigdataSail.Options.VOCABULARY_CLASS, - NoVocabulary.class.getName()); - props.setProperty(BigdataSail.Options.TRUTH_MAINTENANCE, "false"); - props.setProperty(BigdataSail.Options.JUSTIFY, "false"); - props.setProperty(BigdataSail.Options.ISOLATABLE_INDICES, "true"); -// props.setProperty(BigdataSail.Options.EXACT_SIZE, "true"); - - return props; - } - - - /** The thrown exception which is the first cause of failure. */ - private AtomicReference<Throwable> firstCause; - - /** - * Service used to run the individual tasks. This makes it possible to - * interrupt them as soon as one of the tasks fails. - */ - private ExecutorService executorService = null; - - @Override - protected void setUp() throws Exception { - super.setUp(); - firstCause = new AtomicReference<Throwable>(null); - executorService = Executors.newFixedThreadPool(3/*nthreads*/); - } - - @Override - protected void tearDown() throws Exception { - if (executorService != null) { - // interrupt any running tasks. - executorService.shutdownNow(); - } - // clear references so that junit does not hold onto them. - executorService = null; - firstCause = null; - super.tearDown(); - } - - public void testBug() throws Exception { - BigdataSail sail = getSail(); - try { - SailRepository repo = new SailRepository(sail); - repo.initialize(); - runConcurrentStuff(repo); - } finally { - final IIndexManager db = sail.getDatabase().getIndexManager(); - if (sail.isOpen()) - sail.shutDown(); - db.destroy(); - } - } - - private void runConcurrentStuff(final SailRepository repo) - throws Exception, - InterruptedException { - try { - final List<Callable<Void>> tasks = new LinkedList<Callable<Void>>(); - tasks.add(new DoStuff(repo, true)); - tasks.add(new DoStuff(repo, false)); - tasks.add(new DoStuff(repo, false)); - final List<Future<Void>> futures = executorService.invokeAll(tasks); - // Look for the first cause. - final Throwable t = firstCause.get(); - if (t != null) { - // Found it. - throw new RuntimeException(t); - } - // test each future. - for (Future<Void> f : futures) { - f.get(); - } - } finally { - repo.shutDown(); - } - } - - private class DoStuff implements Callable<Void> { - private SailRepository repo; - private boolean writer; - int counter = 0; - - private DoStuff(SailRepository repo, boolean writer) - throws OpenRDFException { - this.repo = repo; - this.writer = writer; - } - - public Void call() throws Exception { -// if (writer) { -// // Initial sleep on the writer. -// Thread.sleep(500); -// } - RepositoryConnection conn = null; - try { - while (firstCause.get() == null) { - /* - * Note: If connection obtained/closed within the loop then - * the query is more likely to have some data to visit - * within its tx view. - */ - conn = repo.getConnection(); - conn.setAutoCommit(false); - if (writer) - writer(conn); - else - reader(conn); - conn.close(); - } - return (Void) null; - } catch (Throwable t) { - firstCause.compareAndSet(null/* expect */, t); - throw new RuntimeException(t); - } finally { - if (conn != null && conn.isOpen()) - conn.close(); - } - } - - private void reader(final RepositoryConnection conn) - throws RepositoryException, MalformedQueryException, - QueryEvaluationException, InterruptedException { - query(conn); -// Thread.sleep(100); - query(conn); - ++counter; - - if (counter % 3 == 0) - conn.commit(); - else - conn.rollback(); - - // if (counter % 7 == 0) { - // conn.close(); - // conn = repo.getConnection(); - // conn.setAutoCommit(false); - // } - } - - private void writer(final RepositoryConnection conn) throws RepositoryException, - MalformedQueryException, QueryEvaluationException, - InterruptedException { - - final URI subj = conn.getValueFactory().createURI( - "u:s" + (counter++)); - final Value value = conn.getValueFactory().createLiteral( - "literal" + counter); - query(conn); -// Thread.sleep(200); - conn.add(subj, conn.getValueFactory().createURI("u:p"), subj); - conn.add(subj, conn.getValueFactory().createURI("u:p"), value); - conn.commit(); - - if(log.isInfoEnabled()) - log.info("Added statements: size="+conn.size()); - - // if (counter % 12 == 0) { - // conn.close(); - // conn = repo.getConnection(); - // conn.setAutoCommit(false); - // } - } - - private void query(final RepositoryConnection conn) throws RepositoryException, - MalformedQueryException, QueryEvaluationException { - final long begin = System.currentTimeMillis(); - /* - * Note: This query will do an access path scan rather than a join. - * There are different code paths involved with a join, so there - * might be problems on those code paths as well. - */ - final boolean useJoin = counter % 2 == 0; - final String query = !useJoin// - // access path scan - ? "SELECT ?b { ?a ?b ?c } LIMIT 20"// - // join - : "SELECT ?b { ?a ?b ?c . ?d ?b ?e} LIMIT 20"// - ; - final TupleQuery q = conn.prepareTupleQuery(QueryLanguage.SPARQL, query); - q.setBinding("b", conn.getValueFactory().createURI("u:p")); - if (useJoin) - q.setBinding("d", conn.getValueFactory().createLiteral( - "literal1")); - final TupleQueryResult tqr = q.evaluate(); - int n = 0; - try { - while (tqr.hasNext()) { - tqr.next(); - n++; - } - } finally { - tqr.close(); - } - if (log.isInfoEnabled()) - log.info("Query: writer=" + writer + ", counter=" + counter - + ", nresults=" + n + ", elapsed=" - + (System.currentTimeMillis() - begin)); - } - } - -} +/** +Copyright (C) SYSTAP, LLC 2011. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package com.bigdata.rdf.sail.contrib; + +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.log4j.Logger; +import org.openrdf.OpenRDFException; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.query.MalformedQueryException; +import org.openrdf.query.QueryEvaluationException; +import org.openrdf.query.QueryLanguage; +import org.openrdf.query.TupleQuery; +import org.openrdf.query.TupleQueryResult; +import org.openrdf.repository.RepositoryConnection; +import org.openrdf.repository.RepositoryException; +import org.openrdf.repository.sail.SailRepository; + +import com.bigdata.journal.IIndexManager; +import com.bigdata.rdf.axioms.NoAxioms; +import com.bigdata.rdf.sail.BigdataSail; +import com.bigdata.rdf.sail.BigdataSailRepository; +import com.bigdata.rdf.sail.QuadsTestCase; +import com.bigdata.rdf.vocab.NoVocabulary; + +/** + * This is a stress test for abort/rollback semantics. + * <p> + * This test case will delegate to an underlying backing store. You can specify + * this store via a JVM property as follows: + * <code>-DtestClass=com.bigdata.rdf.sail.TestBigdataSailWithQuads</code> + * <p> + * There are three possible configurations for the testClass: + * <ul> + * <li>com.bigdata.rdf.sail.TestBigdataSailWithQuads (quads mode)</li> + * <li>com.bigdata.rdf.sail.TestBigdataSailWithoutSids (triples mode)</li> + * <li>com.bigdata.rdf.sail.TestBigdataSailWithSids (SIDs mode)</li> + * </ul> + * <p> + * The default for triples and SIDs mode is for inference with truth maintenance + * to be on. If you would like to turn off inference, make sure to do so in + * {@link #getProperties()}. + * + * @see https://sourceforge.net/apps/trac/bigdata/ticket/278 + * + * @author <a href="mailto:mrp...@us...">Mike Personick</a> + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @author <a href="mailto:ge...@us...">Gerjon</a> + * @version $Id$ + */ +public class TestRollbacks extends QuadsTestCase { + + private static final Logger log = Logger.getLogger(TestRollbacks.class); + + public TestRollbacks() { + } + + public TestRollbacks(String arg0) { + super(arg0); + } + + @Override + public Properties getProperties() { + + final Properties props = super.getProperties(); + + /* + * For example, here is a set of five properties that turns off + * inference, truth maintenance, and the free text index. + */ + props.setProperty(BigdataSail.Options.AXIOMS_CLASS, + NoAxioms.class.getName()); + props.setProperty(BigdataSail.Options.VOCABULARY_CLASS, + NoVocabulary.class.getName()); + props.setProperty(BigdataSail.Options.TRUTH_MAINTENANCE, "false"); + props.setProperty(BigdataSail.Options.JUSTIFY, "false"); + props.setProperty(BigdataSail.Options.ISOLATABLE_INDICES, "true"); + +// props.setProperty(BigdataSail.Options.CREATE_TEMP_FILE, "true"); +// props.setProperty(BigdataSail.Options.BUFFER_MODE, BufferMode.DiskRW +// .toString()); + +// props.setProperty(BigdataSail.Options.EXACT_SIZE, "true"); + + return props; + } + + + /** The thrown exception which is the first cause of failure. */ + private AtomicReference<Throwable> firstCause; + + /** + * Service used to run the individual tasks. This makes it possible to + * interrupt them as soon as one of the tasks fails. + */ + private ExecutorService executorService = null; + + @Override + protected void setUp() throws Exception { + super.setUp(); + firstCause = new AtomicReference<Throwable>(null); + executorService = Executors.newFixedThreadPool(3/*nthreads*/); + } + + @Override + protected void tearDown() throws Exception { + if (executorService != null) { + // interrupt any running tasks. + executorService.shutdownNow(); + } + // clear references so that junit does not hold onto them. + executorService = null; + firstCause = null; + super.tearDown(); + } + + /** + * Stress test for abort/rollback semantics consisting of many short + * runs of the basic test. + * + * @throws Exception + */ + public void testManyShortRuns() throws Exception { + + for (int i = 0; i < 20; i++) { + + doTest(10); + + } + + } + + /** + * Stress test for abort/rollback semantics consisting of one moderate + * duration run of the basic test. + * + * @throws Exception + */ + public void testModerateDuration() throws Exception { + + doTest(100); + + } + + private void doTest(final int maxCounter) throws InterruptedException, Exception { + final BigdataSail sail = getSail(); + try { + // Note: Modified to use the BigdataSailRepository rather than the base SailRepository class. + final BigdataSailRepository repo = new BigdataSailRepository(sail); + repo.initialize(); + runConcurrentStuff(repo,maxCounter); + } finally { + final IIndexManager db = sail.getDatabase().getIndexManager(); + if (sail.isOpen()) + sail.shutDown(); + db.destroy(); + } + } + + private void runConcurrentStuff(final SailRepository repo,final int maxCounter) + throws Exception, + InterruptedException { + try { + final List<Callable<Void>> tasks = new LinkedList<Callable<Void>>(); + tasks.add(new DoStuff(repo, true/*writer*/, maxCounter)); + tasks.add(new DoStuff(repo, false/*reader*/, maxCounter)); + tasks.add(new DoStuff(repo, false/*reader*/, maxCounter)); + final List<Future<Void>> futures = executorService.invokeAll(tasks); + // Look for the first cause. + final Throwable t = firstCause.get(); + if (t != null) { + // Found it. + throw new RuntimeException(t); + } + // test each future. + for (Future<Void> f : futures) { + f.get(); + } + } finally { + repo.shutDown(); + } + } + + private class DoStuff implements Callable<Void> { + + private SailRepository repo; + private boolean writer; + private final int maxCounter; + int counter = 0; + + /** + * @param repo + * The repository. + * @param writer + * <code>true</code> iff this is a writer. + * @param maxCounter + * Sets a limit on the length of the stress test. A value of + * 1000 results in a 26 second run. A value of 100-200 is + * more reasonable and is sufficient to readily identify any + * ... [truncated message content] |