You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2016/09/27 20:11:43 UTC

[1/6] jena git commit: JENA-1237: Capture transaction snapshot during begin.

Repository: jena
Updated Branches:
  refs/heads/master 0a60d3804 -> fbb53efcc


JENA-1237: Capture transaction snapshot during begin.

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/cc2c4bd5
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/cc2c4bd5
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/cc2c4bd5

Branch: refs/heads/master
Commit: cc2c4bd54c15b958dede6b4e83e6ee440a3157c8
Parents: 0a60d38
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Sep 17 16:51:25 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Sep 17 16:51:25 2016 +0100

----------------------------------------------------------------------
 .../java/org/apache/jena/sparql/core/mem/PMapTupleTable.java   | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/cc2c4bd5/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTupleTable.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTupleTable.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTupleTable.java
index 3231f2d..c1cda88 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTupleTable.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/PMapTupleTable.java
@@ -55,7 +55,7 @@ public abstract class PMapTupleTable<TupleMapType, TupleType, ConsumerType>
         return master;
     }
 
-    private final ThreadLocal<TupleMapType> local = withInitial(() -> master().get());
+    private final ThreadLocal<TupleMapType> local = withInitial(()->null);
 
     /**
      * @return a thread-local transactional reference to the internal table structure
@@ -88,7 +88,9 @@ public abstract class PMapTupleTable<TupleMapType, TupleType, ConsumerType>
      * {@link #local} is initialized via {@link #initial()}
      */
     @Override
-    public void begin(final ReadWrite rw) {}
+    public void begin(final ReadWrite rw) {
+        local.set(master().get());
+    }
 
     @Override
     public void end() {


[5/6] jena git commit: JENA-1223: Incorporate review suggestions

Posted by an...@apache.org.
JENA-1223: Incorporate review suggestions


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/779e85cf
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/779e85cf
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/779e85cf

Branch: refs/heads/master
Commit: 779e85cf4d66a0dcbfea41a657f262249c2d9f57
Parents: 2610908
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Sep 27 18:51:17 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Sep 27 18:51:17 2016 +0100

----------------------------------------------------------------------
 .../sparql/core/mem/TestDatasetGraphInMemoryPromote.java     | 2 +-
 .../jena/sparql/transaction/AbstractTestTransPromote.java    | 5 +++--
 .../sparql/transaction/AbstractTestTransactionIsolation.java | 8 ++------
 .../org/apache/jena/tdb/transaction/TestTransPromoteTDB.java | 2 +-
 4 files changed, 7 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/779e85cf/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
index dbcfde0..644de58 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
@@ -59,7 +59,7 @@ public class TestDatasetGraphInMemoryPromote extends AbstractTestTransPromote {
     }
 
     @Override
-    protected Class<?> getTransactionExceptionClass() {
+    protected Class<JenaTransactionException> getTransactionExceptionClass() {
         return JenaTransactionException.class ;
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/779e85cf/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
index f7c7fcb..aec1b8f 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
@@ -81,7 +81,7 @@ public abstract class AbstractTestTransPromote {
     // The exact class used by exceptions of the system under test.
     // TDB transctions are in the TDBException hierarchy
     // so can't be JenaTransactionException.
-    protected abstract Class<?> getTransactionExceptionClass() ;
+    protected abstract Class<? extends Exception> getTransactionExceptionClass() ;
     
     @Before
     public void before() {
@@ -287,7 +287,8 @@ public abstract class AbstractTestTransPromote {
                getTransactionExceptionClass()) ;
     }
     
-    private void expect(Runnable runnable, Class<?>...classes) {
+    @SafeVarargs
+    private final void expect(Runnable runnable, Class<? extends Exception>...classes) {
         try {
             runnable.run(); 
             fail("Exception expected") ;

http://git-wip-us.apache.org/repos/asf/jena/blob/779e85cf/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
index 85a574f..f4d85cd 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
@@ -18,9 +18,8 @@
 
 package org.apache.jena.sparql.transaction;
 
-import static org.apache.jena.query.ReadWrite.* ;
+import static org.apache.jena.query.ReadWrite.WRITE ;
 
-import org.apache.jena.atlas.iterator.Iter ;
 import org.apache.jena.sparql.core.DatasetGraph ;
 import org.apache.jena.sparql.core.Quad ;
 import org.apache.jena.sparql.sse.SSE ;
@@ -42,10 +41,7 @@ public abstract class AbstractTestTransactionIsolation {
         // returns but the action of the ThreadTxn is not triggered
         // until other.run() is called.
         DatasetGraph dsg = create() ;
-        ThreadAction other = ThreadTxn.threadTxnRead(dsg, ()-> {
-            long x = Iter.count(dsg.find()) ;
-            Assert.assertEquals(0, x) ;
-        }) ;
+        ThreadAction other = ThreadTxn.threadTxnRead(dsg, ()-> Assert.assertTrue(dsg.isEmpty()) ) ;
         dsg.begin(WRITE) ;
         dsg.add(q1) ;
         dsg.commit() ;

http://git-wip-us.apache.org/repos/asf/jena/blob/779e85cf/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
index 61ba5f1..c93ecb1 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
@@ -66,7 +66,7 @@ public class TestTransPromoteTDB extends AbstractTestTransPromote {
     }
 
     @Override
-    protected Class<?> getTransactionExceptionClass() {
+    protected Class<TDBTransactionException> getTransactionExceptionClass() {
         return TDBTransactionException.class ;
     }
 }
\ No newline at end of file


[2/6] jena git commit: Clean up.

Posted by an...@apache.org.
Clean up.

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/f9f2870e
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/f9f2870e
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/f9f2870e

Branch: refs/heads/master
Commit: f9f2870e29fd1ac51c49740a42f6fbb644b7616d
Parents: cc2c4bd
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Sep 17 17:02:50 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Sep 17 17:02:50 2016 +0100

----------------------------------------------------------------------
 .../tdb/store/nodetable/NodeTableReadonly.java  |  6 +--
 .../tdb/store/nodetable/NodeTableWrapper.java   | 44 ++++++++++----------
 2 files changed, 24 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/f9f2870e/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableReadonly.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableReadonly.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableReadonly.java
index 963c341..c09140f 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableReadonly.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableReadonly.java
@@ -24,14 +24,12 @@ import org.apache.jena.tdb.store.NodeId ;
 
 public class NodeTableReadonly extends NodeTableWrapper
 {
-    public NodeTableReadonly(NodeTable nodeTable)
-    {
+    public NodeTableReadonly(NodeTable nodeTable) {
         super(nodeTable) ;
     }
 
     @Override
-    public NodeId getAllocateNodeId(Node node)
-    {
+    public NodeId getAllocateNodeId(Node node) {
         NodeId nodeId = getNodeIdForNode(node) ;
         if ( NodeId.isDoesNotExist(nodeId) )
             throw new TDBException("Allocation attempt on NodeTableReadonly") ;

http://git-wip-us.apache.org/repos/asf/jena/blob/f9f2870e/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableWrapper.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableWrapper.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableWrapper.java
index 57b5182..c2378b0 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableWrapper.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableWrapper.java
@@ -30,30 +30,26 @@ public class NodeTableWrapper implements NodeTable
     protected final NodeTable nodeTable ;
     @Override
     public final NodeTable wrapped() { return nodeTable ; } 
-    
-    protected NodeTableWrapper(NodeTable nodeTable)
-    {
+
+    protected NodeTableWrapper(NodeTable nodeTable) {
         this.nodeTable = nodeTable ;
     }
-    
+
     @Override
-    public NodeId getAllocateNodeId(Node node)
-    {
+    public NodeId getAllocateNodeId(Node node) {
         return nodeTable.getAllocateNodeId(node) ;
     }
 
     @Override
-    public NodeId getNodeIdForNode(Node node)
-    {
+    public NodeId getNodeIdForNode(Node node) {
         return nodeTable.getNodeIdForNode(node) ;
     }
 
     @Override
-    public Node getNodeForNodeId(NodeId id)
-    {
+    public Node getNodeForNodeId(NodeId id) {
         return nodeTable.getNodeForNodeId(id) ;
     }
-    
+
     @Override
     public boolean containsNode(Node node) {
         return nodeTable.containsNode(node) ;
@@ -61,27 +57,31 @@ public class NodeTableWrapper implements NodeTable
 
     @Override
     public boolean containsNodeId(NodeId nodeId) {
-        return nodeTable.containsNodeId(nodeId) ;    }
+        return nodeTable.containsNodeId(nodeId) ;
+    }
 
     @Override
-    public NodeId allocOffset()
-    {
+    public NodeId allocOffset() {
         return nodeTable.allocOffset() ;
     }
 
     @Override
-    public Iterator<Pair<NodeId, Node>> all()
-    {
-        return nodeTable.all();
+    public Iterator<Pair<NodeId, Node>> all() {
+        return nodeTable.all() ;
     }
 
     @Override
-    public boolean isEmpty()    { return nodeTable.isEmpty() ; }
-    
+    public boolean isEmpty() {
+        return nodeTable.isEmpty() ;
+    }
+
     @Override
-    public void sync() { nodeTable.sync() ; } 
+    public void sync() {
+        nodeTable.sync() ;
+    }
 
     @Override
-    public void close()
-    { nodeTable.close() ; }
+    public void close() {
+        nodeTable.close() ;
+    }
 }


[6/6] jena git commit: JENA-1223: Merge commit 'refs/pull/170/head' of github.com:apache/jena

Posted by an...@apache.org.
JENA-1223: Merge commit 'refs/pull/170/head' of github.com:apache/jena

This closes #170.


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/fbb53efc
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/fbb53efc
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/fbb53efc

Branch: refs/heads/master
Commit: fbb53efccb59cf6596e7c4601653d8eb0470f36d
Parents: 0a60d38 779e85c
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Sep 27 21:10:51 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Sep 27 21:10:51 2016 +0100

----------------------------------------------------------------------
 .../sparql/core/mem/DatasetGraphInMemory.java   |  60 ++-
 .../jena/sparql/core/mem/PMapTupleTable.java    |   6 +-
 .../jena/sparql/core/mem/TS_DatasetTxnMem.java  |   4 +-
 .../mem/TestDatasetGraphInMemoryIsolation.java  |  30 ++
 .../mem/TestDatasetGraphInMemoryPromote.java    |  65 +++
 .../transaction/AbstractTestTransPromote.java   | 423 +++++++++++++++++++
 .../AbstractTestTransactionIsolation.java       |  51 +++
 .../AbstractTestTransactionLifecycle.java       |   2 -
 .../tdb/store/nodetable/NodeTableReadonly.java  |   6 +-
 .../tdb/store/nodetable/NodeTableWrapper.java   |  44 +-
 .../tdb/transaction/TransactionManager.java     |   2 +-
 .../jena/tdb/transaction/TS_TransactionTDB.java |   3 +-
 .../tdb/transaction/TestTransIsolation.java     |  32 ++
 .../jena/tdb/transaction/TestTransPromote.java  | 394 -----------------
 .../tdb/transaction/TestTransPromoteTDB.java    |  72 ++++
 15 files changed, 762 insertions(+), 432 deletions(-)
----------------------------------------------------------------------



[4/6] jena git commit: JENA-1223: Transaction promotion for TIM

Posted by an...@apache.org.
JENA-1223: Transaction promotion for TIM


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/26109087
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/26109087
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/26109087

Branch: refs/heads/master
Commit: 2610908744464e1247b2896f7b26e78cadf56d84
Parents: 51175d2
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Sep 20 19:24:27 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Sep 20 19:24:27 2016 +0100

----------------------------------------------------------------------
 .../sparql/core/mem/DatasetGraphInMemory.java   |  60 ++-
 .../jena/sparql/core/mem/TS_DatasetTxnMem.java  |   3 +-
 .../mem/TestDatasetGraphInMemoryPromote.java    |  65 +++
 .../transaction/AbstractTestTransPromote.java   | 422 +++++++++++++++++++
 .../jena/tdb/transaction/TS_TransactionTDB.java |   2 +-
 .../jena/tdb/transaction/TestTransPromote.java  | 391 -----------------
 .../tdb/transaction/TestTransPromoteTDB.java    |  72 ++++
 7 files changed, 617 insertions(+), 398 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/DatasetGraphInMemory.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/DatasetGraphInMemory.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/DatasetGraphInMemory.java
index 8af0734..d6dfdff 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/DatasetGraphInMemory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/mem/DatasetGraphInMemory.java
@@ -27,10 +27,12 @@ import static org.apache.jena.sparql.util.graph.GraphUtils.triples2quadsDftGraph
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicLong ;
 import java.util.concurrent.locks.ReentrantLock ;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
+import org.apache.jena.atlas.lib.InternalErrorException ;
 import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.Triple;
@@ -42,9 +44,8 @@ import org.apache.jena.sparql.core.* ;
 import org.slf4j.Logger;
 
 /**
- * A {@link DatasetGraph} backed by an {@link QuadTable}. By default, this is a {@link HexTable} designed for high-speed
- * in-memory operation.
- *
+ * A {@link DatasetGraph} backed by an {@link QuadTable}. By default, this is a
+ * {@link HexTable} designed for high-speed in-memory operation.
  */
 public class DatasetGraphInMemory extends DatasetGraphTriplesQuads implements Transactional {
 
@@ -63,6 +64,13 @@ public class DatasetGraphInMemory extends DatasetGraphTriplesQuads implements Tr
      * insures that they are made consistently.
      */
     private final ReentrantLock systemLock = new ReentrantLock(true);
+    
+    /**
+     * Dataset version.
+     * A write transaction increments this in commit.
+     */
+    private final AtomicLong generation = new AtomicLong(0) ;
+    private final ThreadLocal<Long> version = withInitial(() -> 0L);
 
     private final ThreadLocal<Boolean> isInTransaction = withInitial(() -> false);
 
@@ -133,6 +141,7 @@ public class DatasetGraphInMemory extends DatasetGraphTriplesQuads implements Tr
         withLock(systemLock, () ->{
             quadsIndex().begin(readWrite);
             defaultGraph().begin(readWrite);
+            version.set(generation.get());
         }) ;
     }
     
@@ -147,6 +156,7 @@ public class DatasetGraphInMemory extends DatasetGraphTriplesQuads implements Tr
     private void finishTransaction() {
         isInTransaction.remove();
         transactionType.remove();
+        version.remove();
         transactionLock.leaveCriticalSection();
     }
      
@@ -165,6 +175,12 @@ public class DatasetGraphInMemory extends DatasetGraphTriplesQuads implements Tr
             defaultGraph().commit();
             quadsIndex().end();
             defaultGraph().end();
+
+            if ( transactionType().equals(WRITE) ) {
+                if ( version.get() != generation.get() )
+                    throw new InternalErrorException(String.format("Version=%d, Generation=%d",version.get(),generation.get())) ;
+                generation.incrementAndGet() ;
+            }
         } ) ;
     }
     
@@ -306,8 +322,42 @@ public class DatasetGraphInMemory extends DatasetGraphTriplesQuads implements Tr
             } finally {
                 end();
             }
-        } else if (transactionType().equals(WRITE)) mutator.accept(payload);
-        else throw new JenaTransactionException("Tried to write inside a READ transaction!");
+            return ;
+        }
+        if ( !transactionType().equals(WRITE) ) {
+            if ( ! promotion )
+                throw new JenaTransactionException("Tried to write inside a READ transaction!");
+            promote(readCommittedPromotion) ;
+        }
+        mutator.accept(payload);
+    }
+
+    /*private*/public/*for development*/ static boolean promotion               = false ;
+    /*private*/public/*for development*/ static boolean readCommittedPromotion  = true ;
+    
+    private void promote(boolean readCommited) {
+        //System.err.printf("Promote: version=%d generation=%d\n", version.get() , generation.get()) ;
+        
+        // Outside lock.
+        if ( ! readCommited && version.get() != generation.get() )  {
+            // This tests for any commited writers since this transaction started.
+            // This does not catch the case of a currently active writer
+            // that has not gone to commit or abort yet.
+            // The final test is after we obtain the transactionLock.
+            throw new JenaTransactionException("Dataset changed - can't promote") ;
+        }
+       
+        // Blocking on other writers.
+        transactionLock.enterCriticalSection(false);
+        // Check again now we are inside the lock. 
+        if ( ! readCommited && version.get() != generation.get() )  {
+                // Can't promote - release the lock.
+                transactionLock.leaveCriticalSection();
+                throw new JenaTransactionException("Concurrent writer changed the dataset : can't promote") ;
+            }
+        // We have the lock and we have promoted!
+        transactionType(WRITE);
+        _begin(WRITE) ;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
index f3d795b..2fa0f60 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
@@ -40,6 +40,7 @@ import org.junit.runners.Suite.SuiteClasses;
     
     TestDatasetGraphInMemoryFind.class,
     TestDatasetGraphInMemoryFindPattern.class,
-    TestDatasetGraphInMemoryIsolation.class
+    TestDatasetGraphInMemoryIsolation.class,
+    TestDatasetGraphInMemoryPromote.class
  })
 public class TS_DatasetTxnMem {}

http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
new file mode 100644
index 0000000..dbcfde0
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryPromote.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.core.mem ;
+
+import org.apache.jena.sparql.JenaTransactionException ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.transaction.AbstractTestTransPromote ;
+import org.apache.log4j.Logger ;
+
+/** Tests for transactions that start read and then promote to write -- TIM */
+public class TestDatasetGraphInMemoryPromote extends AbstractTestTransPromote {
+    public TestDatasetGraphInMemoryPromote() {
+        super(getLoggers()) ;
+    }
+
+    @Override
+    protected DatasetGraph create() {
+        return new DatasetGraphInMemory() ;
+    }
+
+    private static Logger[] getLoggers() {
+        return new Logger[]{ Logger.getLogger(DatasetGraphInMemory.class) } ;
+    }
+
+    @Override
+    protected void setPromotion(boolean b) {
+        DatasetGraphInMemory.promotion = b ;
+    }
+
+    @Override
+    protected boolean getPromotion() {
+        return DatasetGraphInMemory.promotion ;
+    }
+
+    @Override
+    protected void setReadCommitted(boolean b) {
+        DatasetGraphInMemory.readCommittedPromotion = b ;
+    }
+
+    @Override
+    protected boolean getReadCommitted() {
+        return DatasetGraphInMemory.readCommittedPromotion ;
+    }
+
+    @Override
+    protected Class<?> getTransactionExceptionClass() {
+        return JenaTransactionException.class ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
new file mode 100644
index 0000000..f7c7fcb
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransPromote.java
@@ -0,0 +1,422 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.transaction ;
+
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.fail ;
+
+import java.util.concurrent.* ;
+import java.util.concurrent.atomic.AtomicInteger ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.Lib ;
+import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.shared.JenaException ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.sse.SSE ;
+import org.apache.jena.system.ThreadAction ;
+import org.apache.jena.system.ThreadTxn ;
+import org.apache.jena.system.Txn ;
+import org.apache.log4j.Level ;
+import org.apache.log4j.Logger ;
+import org.junit.After ;
+import org.junit.Before ;
+import org.junit.Test ;
+
+/** Tests for transactions that start read and then promote to write */
+public abstract class AbstractTestTransPromote {
+
+    // Currently,
+    // this feature is off and needs enabling via setPromotion.
+    // promotion is implicit when a write happens.
+
+    // See beforeClass / afterClass.
+
+    // Loggers.
+    private final Logger[] loggers ;
+    private Level[] levels ;
+    private boolean stdPromotion ;
+    private boolean stdReadCommitted ;
+    
+    @Before
+    public void beforeLoggersNoWarnings() {
+        int N = loggers.length ;
+        levels = new Level[N] ;
+        for ( int i = 0 ; i < N ; i++ ) {
+            levels[i] = loggers[i].getLevel() ;
+            loggers[i].setLevel(Level.ERROR) ;
+        }
+    }
+
+    @After
+    public void afterResetLoggers() {
+        int N = loggers.length ;
+        for ( int i = 0 ; i < N ; i++ ) {
+            loggers[i].setLevel(levels[i]) ;
+        }
+    }
+
+    protected abstract void setPromotion(boolean b) ;
+    protected abstract boolean getPromotion() ;
+    protected abstract void setReadCommitted(boolean b) ;
+    protected abstract boolean getReadCommitted() ;
+    
+    // The exact class used by exceptions of the system under test.
+    // TDB transctions are in the TDBException hierarchy
+    // so can't be JenaTransactionException.
+    protected abstract Class<?> getTransactionExceptionClass() ;
+    
+    @Before
+    public void before() {
+        stdPromotion = getPromotion() ;
+        stdReadCommitted = getReadCommitted() ;
+        setPromotion(true);
+        setReadCommitted(true);
+    }
+
+    @After
+    public void after() {
+        setPromotion(stdPromotion);
+        setReadCommitted(stdReadCommitted);
+    }
+    
+    protected AbstractTestTransPromote(Logger[] loggers) {
+        this.loggers = loggers ;
+    }
+    
+    
+    private static Quad q1 = SSE.parseQuad("(_ :s :p1 1)") ;
+    private static Quad q2 = SSE.parseQuad("(_ :s :p2 2)") ;
+    private static Quad q3 = SSE.parseQuad("(_ :s :p3 3)") ;
+
+    protected abstract DatasetGraph create() ;
+
+    protected static void assertCount(long expected, DatasetGraph dsg) {
+        dsg.begin(ReadWrite.READ) ;
+        long x = Iter.count(dsg.find()) ;
+        dsg.end() ;
+        assertEquals(expected, x) ;
+    }
+
+    // "strict" = don't see intermedioate changes.
+    // "readCommitted" = do see
+
+    // Subclass / parameterized
+    
+    @Test public void promote_snapshot_01()         { run_01(false) ; }
+    @Test public void promote_readCommitted_01()    { run_01(true) ; }
+    
+    // READ-add
+    private void run_01(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+        dsg.commit() ;
+        dsg.end() ;
+    }
+    
+    @Test public void promote_snapshot_02()         { run_02(false) ; }
+    @Test public void promote_readCommitted_02()    { run_02(true) ; }
+    
+    // Previous transaction then READ-add
+    private void run_02(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        
+        dsg.begin(ReadWrite.READ) ;dsg.end() ;
+        
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+        dsg.commit() ;
+        dsg.end() ;
+    }
+    
+    @Test public void promote_snapshot_03()         { run_03(false) ; }
+    @Test public void promote_readCommitted_03()    { run_03(true) ; }
+
+    private void run_03(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        
+        dsg.begin(ReadWrite.WRITE) ;dsg.commit() ; dsg.end() ;
+        
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+        dsg.commit() ;
+        dsg.end() ;
+    }
+    
+    @Test public void promote_snapshot_04()         { run_04(false) ; }
+    @Test public void promote_readCommitted_04()    { run_04(true) ; }
+
+    private void run_04(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        
+        dsg.begin(ReadWrite.WRITE) ;dsg.abort() ; dsg.end() ;
+        
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+        dsg.commit() ;
+        dsg.end() ;
+    }
+
+    @Test public void promote_snapshot_05()         { run_05(false) ; }
+    @Test public void promote_readCommitted_05()    { run_05(true) ; }
+    
+    private void run_05(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+
+        // bad - forced abort.
+        // Causes a WARN.
+        //logger1.setLevel(Level.ERROR) ;
+        dsg.end() ;
+        //logger1.setLevel(level1) ;
+
+        assertCount(0, dsg) ;
+    }
+
+    @Test public void promote_snapshot_06()         { run_06(false) ; }
+    @Test public void promote_readCommitted_06()    { run_06(true) ; }
+    
+    // Async writer after promotion.
+    private void run_06(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        AtomicInteger a = new AtomicInteger(0) ;
+
+        Semaphore sema = new Semaphore(0) ;
+        Thread t = new Thread(() -> {
+            sema.release() ;
+            Txn.executeWrite(dsg, () -> dsg.add(q3)) ;
+            sema.release() ;
+        }) ;
+
+        dsg.begin(ReadWrite.READ) ;
+        // Promote
+        dsg.add(q1) ;
+        t.start() ;
+        // First release.
+        sema.acquireUninterruptibly() ;
+        // Thread blocked.
+        dsg.add(q2) ;
+        dsg.commit() ;
+        dsg.end() ;
+
+        // Until thread exits.
+        sema.acquireUninterruptibly() ;
+        assertCount(3, dsg) ;
+    }
+
+    @Test public void promote_snapshot_07()         { run_07(false) ; }
+    @Test public void promote_readCommitted_07()    { run_07(true) ; }
+    
+    // Async writer after promotion.
+    private void run_07(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        // Start long running reader.
+        ThreadAction tt = ThreadTxn.threadTxnRead(dsg, () -> {
+            long x = Iter.count(dsg.find()) ;
+            if ( x != 0 )
+                throw new RuntimeException() ;
+        }) ;
+
+        // Start R->W here
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+        dsg.add(q2) ;
+        dsg.commit() ;
+        dsg.end() ;
+        tt.run() ;
+    }
+    
+    @Test public void promote_snapshot_08()         { run_08(false) ; }
+    @Test public void promote_readCommitted_08()    { run_08(true) ; }
+    
+    // Async writer after promotion trasnaction ends.
+    private void run_08(boolean allowReadCommitted) {
+        setReadCommitted(allowReadCommitted);
+        DatasetGraph dsg = create() ;
+        // Start R->W here
+        dsg.begin(ReadWrite.READ) ;
+        dsg.add(q1) ;
+        dsg.add(q2) ;
+        dsg.commit() ;
+        dsg.end() ;
+        Txn.executeRead(dsg, () -> {
+            long x = Iter.count(dsg.find()) ;
+            assertEquals(2, x) ;
+        }) ;
+    }
+
+    // Tests for XXX Read-committed yes/no (false = snapshot isolation, true = read committed),
+    // and whether the other transaction commits (true) or aborts (false).
+    
+    @Test
+    public void promote_10() { promote_readCommit_txnCommit(true, true) ; }
+
+    @Test
+    public void promote_11() { promote_readCommit_txnCommit(true, false) ; }
+    
+    @Test
+    public void promote_12() { 
+        expect(()->promote_readCommit_txnCommit(false, true) ,
+               getTransactionExceptionClass()) ;
+    }
+    
+    private void expect(Runnable runnable, Class<?>...classes) {
+        try {
+            runnable.run(); 
+            fail("Exception expected") ;
+        } catch (Exception e) {
+            for ( Class<?> c : classes) {
+                if ( e.getClass().equals(c) )
+                    return ;
+            }
+            throw e ;
+        }
+    }
+
+    @Test
+    public void promote_13() { promote_readCommit_txnCommit(false, false) ; }
+
+    private void promote_readCommit_txnCommit(boolean allowReadCommitted, boolean asyncCommit) {
+        setReadCommitted(allowReadCommitted) ;
+        DatasetGraph dsg = create() ;
+        
+        ThreadAction tt = asyncCommit?
+            ThreadTxn.threadTxnWrite(dsg, () -> dsg.add(q3) ) :
+            ThreadTxn.threadTxnWriteAbort(dsg, () -> dsg.add(q3)) ;
+
+        dsg.begin(ReadWrite.READ) ;
+        // Other runs
+        tt.run() ;
+        // Can promote if readCommited
+        // Can't promote if not readCommited
+        dsg.add(q1) ;
+        if ( ! allowReadCommitted && asyncCommit )
+            fail("Should not be here") ;
+        
+        assertEquals(asyncCommit, dsg.contains(q3)) ;
+        dsg.commit() ;
+        dsg.end() ;
+        //logger2.setLevel(level2);
+    }
+    
+    // Active writer commits -> no promotion.
+    @Test
+    public void promote_active_writer_1() throws InterruptedException, ExecutionException {
+        expect(()->promote_active_writer(true) ,
+               getTransactionExceptionClass()) ;
+    }
+    
+    // Active writer aborts -> promotion.
+    @Test
+    public void promote_active_writer_2() throws InterruptedException, ExecutionException {
+        // Active writer aborts -> promotion possible (but not implemented that way).
+        promote_active_writer(false) ;
+    }
+    
+    private void promote_active_writer(boolean activeWriterCommit) {
+        ExecutorService executor = Executors.newFixedThreadPool(2) ;
+        try {
+            promote_clash_active_writer(executor, activeWriterCommit) ;
+        }
+        finally {
+            executor.shutdown() ;
+        }
+    }
+    
+    private void promote_clash_active_writer(ExecutorService executor, boolean activeWriterCommit) {
+        setReadCommitted(false) ;
+        Semaphore semaActiveWriterStart     = new Semaphore(0) ;
+        Semaphore semaActiveWriterContinue  = new Semaphore(0) ;
+        Semaphore semaPromoteTxnStart       = new Semaphore(0) ;
+        Semaphore semaPromoteTxnContinue    = new Semaphore(0) ;
+
+        DatasetGraph dsg = create() ;
+
+        // The "active writer". 
+        Callable<Object> activeWriter = ()->{
+            dsg.begin(ReadWrite.WRITE) ;
+            semaActiveWriterStart.release(1) ;
+            // (*1)
+            semaActiveWriterContinue.acquireUninterruptibly(1) ;
+            if ( activeWriterCommit )
+                dsg.commit() ;
+            else
+                dsg.abort();
+            dsg.end() ;
+            return null ;
+        } ;
+
+        Future<Object> activeWriterFuture = executor.submit(activeWriter) ;
+        // Advance "active writer" to (*1), inside a write transaction and waiting.
+        // The transaction has been created and started.
+        semaActiveWriterStart.acquireUninterruptibly(); 
+
+        Callable<JenaException> attemptedPromote = ()->{
+            dsg.begin(ReadWrite.READ) ;
+            semaPromoteTxnStart.release(1) ;
+            // (*2)
+            semaPromoteTxnContinue.acquireUninterruptibly();
+            try { 
+                // (*3)
+                dsg.add(q1) ;
+                return null ;
+            } catch (JenaException e) {
+                Class<?> c = getTransactionExceptionClass() ;
+                if ( ! e.getClass().equals(c) ) 
+                    throw e ;
+                return e ;
+            }
+        } ;
+
+        Future<JenaException> attemptedPromoteFuture = executor.submit(attemptedPromote) ;
+        // Advance "attempted promote" to (*2), inside a read transaction, before attempting a promoting write.
+        // The transaction has been created and started.
+        semaPromoteTxnStart.acquireUninterruptibly();
+        
+        // Advance "attempted promote" allowing it to go (*3) where it blocks
+        // This may happen at any time - as soon as it does, the "attempted promote" blocks.
+        semaPromoteTxnContinue.release(1);
+        // I don't know of a better way to ensure "attempted promote" is blocked. 
+        
+        Lib.sleep(100) ;
+        // Let the active writer go.
+        semaActiveWriterContinue.release(1);
+        
+        try { 
+            // Collect the active writer.
+            activeWriterFuture.get();
+            
+            // (Ideal) and the attempted promotion should advance if the active writer aborts.
+            JenaException e = attemptedPromoteFuture.get() ;
+            if ( e != null )
+                throw e ;
+        } catch (InterruptedException | ExecutionException e1) { throw new RuntimeException(e1) ; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
index e1f8af4..87bbf1e 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
@@ -41,7 +41,7 @@ import org.junit.runners.Suite ;
     , TestTransactionUnionGraph.class
     , TestMiscTDB.class
     , TestTDBInternal.class
-    , TestTransPromote.class
+    , TestTransPromoteTDB.class
     , TestTransControl.class
     , TestTransIsolation.class
 })

http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
deleted file mode 100644
index 5e62924..0000000
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.jena.tdb.transaction ;
-
-import static org.junit.Assert.assertEquals ;
-import static org.junit.Assert.fail ;
-
-import java.util.concurrent.* ;
-import java.util.concurrent.atomic.AtomicInteger ;
-
-import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.lib.Lib ;
-import org.apache.jena.query.ReadWrite ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.Quad ;
-import org.apache.jena.sparql.sse.SSE ;
-import org.apache.jena.system.ThreadAction ;
-import org.apache.jena.system.ThreadTxn ;
-import org.apache.jena.system.Txn ;
-import org.apache.jena.tdb.TDB ;
-import org.apache.jena.tdb.TDBFactory ;
-import org.apache.jena.tdb.sys.SystemTDB ;
-import org.apache.log4j.Level ;
-import org.apache.log4j.Logger ;
-import org.junit.* ;
-
-/** Tests for transactions that start read and then promote to write */
-public class TestTransPromote {
-
-    // Currently,
-    // this feature is off and needs enabling via DatasetGraphTransaction.promotion
-    // promotion is implicit when a write happens.
-
-    // See beforeClass / afterClass.
-
-    private static Logger logger1 = Logger.getLogger(SystemTDB.errlog.getName()) ;
-    private static Level  level1 ;
-    private static Logger logger2 = Logger.getLogger(TDB.logInfoName) ;
-    private static Level  level2 ;
-    static boolean        stdPromotion ;
-    static boolean        stdReadCommitted ;
-
-    @BeforeClass
-    static public void beforeClass() {
-        stdPromotion = DatasetGraphTransaction.promotion ;
-        stdReadCommitted = DatasetGraphTransaction.readCommittedPromotion ;
-        level1 = logger1.getLevel() ;
-        level2 = logger2.getLevel() ;
-    }
-
-    @AfterClass
-    static public void afterClass() {
-        // Restore logging setting.
-        logger2.setLevel(level2) ;
-        logger1.setLevel(level1) ;
-        DatasetGraphTransaction.promotion = stdPromotion ;
-        DatasetGraphTransaction.readCommittedPromotion = stdReadCommitted ;
-    }
-
-    @Before
-    public void before() {
-        DatasetGraphTransaction.promotion = true ;
-        DatasetGraphTransaction.readCommittedPromotion = true ;
-    }
-
-    @After
-    public void after() {
-        DatasetGraphTransaction.promotion = true ;
-        DatasetGraphTransaction.readCommittedPromotion = true ;
-    }
-    
-    
-    private static Quad q1 = SSE.parseQuad("(_ :s :p1 1)") ;
-    private static Quad q2 = SSE.parseQuad("(_ :s :p2 2)") ;
-    private static Quad q3 = SSE.parseQuad("(_ :s :p3 3)") ;
-
-    protected DatasetGraph create() {
-        return TDBFactory.createDatasetGraph() ;
-    }
-
-    protected static void assertCount(long expected, DatasetGraph dsg) {
-        dsg.begin(ReadWrite.READ) ;
-        long x = Iter.count(dsg.find()) ;
-        dsg.end() ;
-        assertEquals(expected, x) ;
-    }
-
-    // "strict" = don't see intermedioate changes.
-    // "readCommitted" = do see
-
-    // Subclass / parameterized
-    
-    @Test public void promote_snapshot_01()         { run_01(false) ; }
-    @Test public void promote_readCommitted_01()    { run_01(true) ; }
-    
-    // READ-add
-    private void run_01(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-        dsg.commit() ;
-        dsg.end() ;
-    }
-    
-    @Test public void promote_snapshot_02()         { run_02(false) ; }
-    @Test public void promote_readCommitted_02()    { run_02(true) ; }
-    
-    // Previous transaction then READ-add
-    private void run_02(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        
-        dsg.begin(ReadWrite.READ) ;dsg.end() ;
-        
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-        dsg.commit() ;
-        dsg.end() ;
-    }
-    
-    @Test public void promote_snapshot_03()         { run_03(false) ; }
-    @Test public void promote_readCommitted_03()    { run_03(true) ; }
-
-    private void run_03(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        
-        dsg.begin(ReadWrite.WRITE) ;dsg.commit() ; dsg.end() ;
-        
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-        dsg.commit() ;
-        dsg.end() ;
-    }
-    
-    @Test public void promote_snapshot_04()         { run_04(false) ; }
-    @Test public void promote_readCommitted_04()    { run_04(true) ; }
-
-    private void run_04(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        
-        dsg.begin(ReadWrite.WRITE) ;dsg.abort() ; dsg.end() ;
-        
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-        dsg.commit() ;
-        dsg.end() ;
-    }
-
-    @Test public void promote_snapshot_05()         { run_05(false) ; }
-    @Test public void promote_readCommitted_05()    { run_05(true) ; }
-    
-    private void run_05(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-
-        // bad - forced abort.
-        // Causes a WARN.
-        logger1.setLevel(Level.ERROR) ;
-        dsg.end() ;
-        logger1.setLevel(level1) ;
-
-        assertCount(0, dsg) ;
-    }
-
-    @Test public void promote_snapshot_06()         { run_06(false) ; }
-    @Test public void promote_readCommitted_06()    { run_06(true) ; }
-    
-    // Async writer after promotion.
-    private void run_06(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        AtomicInteger a = new AtomicInteger(0) ;
-
-        Semaphore sema = new Semaphore(0) ;
-        Thread t = new Thread(() -> {
-            sema.release() ;
-            Txn.executeWrite(dsg, () -> dsg.add(q3)) ;
-            sema.release() ;
-        }) ;
-
-        dsg.begin(ReadWrite.READ) ;
-        // Promote
-        dsg.add(q1) ;
-        t.start() ;
-        // First release.
-        sema.acquireUninterruptibly() ;
-        // Thread blocked.
-        dsg.add(q2) ;
-        dsg.commit() ;
-        dsg.end() ;
-
-        // Until thread exits.
-        sema.acquireUninterruptibly() ;
-        assertCount(3, dsg) ;
-    }
-
-    @Test public void promote_snapshot_07()         { run_07(false) ; }
-    @Test public void promote_readCommitted_07()    { run_07(true) ; }
-    
-    // Async writer after promotion.
-    private void run_07(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        // Start long running reader.
-        ThreadAction tt = ThreadTxn.threadTxnRead(dsg, () -> {
-            long x = Iter.count(dsg.find()) ;
-            if ( x != 0 )
-                throw new RuntimeException() ;
-        }) ;
-
-        // Start R->W here
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-        dsg.add(q2) ;
-        dsg.commit() ;
-        dsg.end() ;
-        tt.run() ;
-    }
-    
-    @Test public void promote_snapshot_08()         { run_08(false) ; }
-    @Test public void promote_readCommitted_08()    { run_08(true) ; }
-    
-    // Async writer after promotion trasnaction ends.
-    private void run_08(boolean b) {
-        DatasetGraphTransaction.readCommittedPromotion = b ;
-        DatasetGraph dsg = create() ;
-        // Start R->W here
-        dsg.begin(ReadWrite.READ) ;
-        dsg.add(q1) ;
-        dsg.add(q2) ;
-        dsg.commit() ;
-        dsg.end() ;
-        Txn.executeRead(dsg, () -> {
-            long x = Iter.count(dsg.find()) ;
-            assertEquals(2, x) ;
-        }) ;
-    }
-
-    // Tests for XXX Read-committed yes/no (false = snapshot isolation, true = read committed),
-    // and whether the other transaction commits (true) or aborts (false).
-    
-    @Test
-    public void promote_10() { promote_readCommit_txnCommit(true, true) ; }
-
-    @Test
-    public void promote_11() { promote_readCommit_txnCommit(true, false) ; }
-    
-    @Test(expected = TDBTransactionException.class)
-    public void promote_12() { promote_readCommit_txnCommit(false, true) ; }
-
-    @Test
-    public void promote_13() { promote_readCommit_txnCommit(false, false) ; }
-
-    private void promote_readCommit_txnCommit(boolean allowReadCommitted, boolean asyncCommit) {
-        logger2.setLevel(Level.ERROR);
-        DatasetGraphTransaction.readCommittedPromotion = allowReadCommitted ;
-        DatasetGraph dsg = create() ;
-        
-        ThreadAction tt = asyncCommit?
-            ThreadTxn.threadTxnWrite(dsg, () -> dsg.add(q3) ) :
-            ThreadTxn.threadTxnWriteAbort(dsg, () -> dsg.add(q3)) ;
-
-        dsg.begin(ReadWrite.READ) ;
-        // Other runs
-        tt.run() ;
-        // Can promote if readCommited
-        // Can't promote if not readCommited
-        dsg.add(q1) ;
-        if ( ! allowReadCommitted && asyncCommit )
-            fail("Should not be here") ;
-        
-        assertEquals(asyncCommit, dsg.contains(q3)) ;
-        dsg.commit() ;
-        dsg.end() ;
-        logger2.setLevel(level2);
-    }
-    
-    // Active writer commits -> no promotion.
-    @Test(expected=TDBTransactionException.class)
-    public void promote_active_writer_1() throws InterruptedException, ExecutionException {
-        promote_active_writer(true) ;
-    }
-    
-    // Active writer aborts -> promotion.
-    @Test
-    public void promote_active_writer_2() throws InterruptedException, ExecutionException {
-        // Active writer aborts -> promotion possible (but not implemented that way).
-        promote_active_writer(false) ;
-    }
-    
-    private void promote_active_writer(boolean activeWriterCommit) {
-        ExecutorService executor = Executors.newFixedThreadPool(2) ;
-        try {
-            promote_clash_active_writer(executor, activeWriterCommit) ;
-        }
-        finally {
-            executor.shutdown() ;
-        }
-    }
-    
-    private void promote_clash_active_writer(ExecutorService executor, boolean activeWriterCommit) {
-        DatasetGraphTransaction.readCommittedPromotion = false ;
-        Semaphore semaActiveWriterStart     = new Semaphore(0) ;
-        Semaphore semaActiveWriterContinue  = new Semaphore(0) ;
-        Semaphore semaPromoteTxnStart       = new Semaphore(0) ;
-        Semaphore semaPromoteTxnContinue    = new Semaphore(0) ;
-
-        DatasetGraph dsg = create() ;
-
-        // The "active writer". 
-        Callable<Object> activeWriter = ()->{
-            dsg.begin(ReadWrite.WRITE) ;
-            semaActiveWriterStart.release(1) ;
-            // (*1)
-            semaActiveWriterContinue.acquireUninterruptibly(1) ;
-            if ( activeWriterCommit )
-                dsg.commit() ;
-            else
-                dsg.abort();
-            dsg.end() ;
-            return null ;
-        } ;
-
-        Future<Object> activeWriterFuture = executor.submit(activeWriter) ;
-        // Advance "active writer" to (*1), inside a write transaction and waiting.
-        // The transaction has been created and started.
-        semaActiveWriterStart.acquireUninterruptibly(); 
-
-        Callable<TDBTransactionException> attemptedPromote = ()->{
-            dsg.begin(ReadWrite.READ) ;
-            semaPromoteTxnStart.release(1) ;
-            // (*2)
-            semaPromoteTxnContinue.acquireUninterruptibly();
-            try { 
-                // (*3)
-                dsg.add(q1) ;
-                //System.err.println("PROMOTED");
-                return null ;
-            } catch (TDBTransactionException e) {
-                //System.err.println("NOT PROMOTED");
-                return e ;
-            }
-        } ;
-
-        Future<TDBTransactionException> attemptedPromoteFuture = executor.submit(attemptedPromote) ;
-        // Advance "attempted promote" to (*2), inside a read transaction, before attempting a promoting write.
-        // The transaction has been created and started.
-        semaPromoteTxnStart.acquireUninterruptibly();
-        
-        // Advance "attempted promote" allowing it to go (*3) where it blocks
-        // This may happen at any time - as soon as it does, the "attempted promote" blocks.
-        semaPromoteTxnContinue.release(1);
-        // I don't know of a better way to ensure "attempted promote" is blocked. 
-        
-        Lib.sleep(100) ;
-        // Let the active writer go.
-        semaActiveWriterContinue.release(1);
-        
-        try { 
-            // Collect the active writer.
-            activeWriterFuture.get();
-            
-            // (Ideal) and the attempted promotion should advance if the active writer aborts.
-            TDBTransactionException e = attemptedPromoteFuture.get() ;
-            if ( e != null )
-                throw e ;
-        } catch (InterruptedException | ExecutionException e1) { throw new RuntimeException(e1) ; }
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/26109087/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
new file mode 100644
index 0000000..61ba5f1
--- /dev/null
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromoteTDB.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.tdb.transaction ;
+
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.transaction.AbstractTestTransPromote ;
+import org.apache.jena.tdb.TDB ;
+import org.apache.jena.tdb.TDBFactory ;
+import org.apache.jena.tdb.sys.SystemTDB ;
+import org.apache.jena.tdb.transaction.DatasetGraphTransaction ;
+import org.apache.jena.tdb.transaction.TDBTransactionException ;
+import org.apache.log4j.Logger ;
+
+/** Tests for transactions that start read and then promote to write -- TDB */
+public class TestTransPromoteTDB extends AbstractTestTransPromote {
+    public TestTransPromoteTDB() {
+        super(getLoggers()) ;
+    }
+
+    @Override
+    protected DatasetGraph create() {
+        return TDBFactory.createDatasetGraph() ;
+    }
+
+    private static Logger[] getLoggers() {
+        return new Logger[]{
+            Logger.getLogger(SystemTDB.errlog.getName()),
+            Logger.getLogger(TDB.logInfoName)
+        } ;
+    }
+
+    @Override
+    protected void setPromotion(boolean b) {
+        DatasetGraphTransaction.promotion = b ;
+    }
+
+    @Override
+    protected boolean getPromotion() {
+        return DatasetGraphTransaction.promotion ;
+    }
+
+    @Override
+    protected void setReadCommitted(boolean b) {
+        DatasetGraphTransaction.readCommittedPromotion = b ;
+    }
+
+    @Override
+    protected boolean getReadCommitted() {
+        return DatasetGraphTransaction.readCommittedPromotion ;
+    }
+
+    @Override
+    protected Class<?> getTransactionExceptionClass() {
+        return TDBTransactionException.class ;
+    }
+}
\ No newline at end of file


[3/6] jena git commit: JENA-1237: Tests (TDB and TIM)

Posted by an...@apache.org.
JENA-1237: Tests (TDB and TIM)

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/51175d27
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/51175d27
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/51175d27

Branch: refs/heads/master
Commit: 51175d27768955ed1918b79ea7f046723e5c3173
Parents: f9f2870
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Sep 17 17:03:31 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Sep 17 17:11:31 2016 +0100

----------------------------------------------------------------------
 .../jena/sparql/core/mem/TS_DatasetTxnMem.java  |  3 +-
 .../mem/TestDatasetGraphInMemoryIsolation.java  | 30 +++++++++++
 .../AbstractTestTransactionIsolation.java       | 55 ++++++++++++++++++++
 .../AbstractTestTransactionLifecycle.java       |  2 -
 .../tdb/transaction/TransactionManager.java     |  2 +-
 .../jena/tdb/transaction/TS_TransactionTDB.java |  1 +
 .../tdb/transaction/TestTransIsolation.java     | 32 ++++++++++++
 .../jena/tdb/transaction/TestTransPromote.java  |  5 +-
 8 files changed, 122 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
index 815c8e5..f3d795b 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TS_DatasetTxnMem.java
@@ -39,6 +39,7 @@ import org.junit.runners.Suite.SuiteClasses;
     TestDatasetGraphInMemoryTransactions.class,
     
     TestDatasetGraphInMemoryFind.class,
-    TestDatasetGraphInMemoryFindPattern.class
+    TestDatasetGraphInMemoryFindPattern.class,
+    TestDatasetGraphInMemoryIsolation.class
  })
 public class TS_DatasetTxnMem {}

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryIsolation.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryIsolation.java b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryIsolation.java
new file mode 100644
index 0000000..12b0173
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/mem/TestDatasetGraphInMemoryIsolation.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.core.mem;
+
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.transaction.AbstractTestTransactionIsolation ;
+
+public class TestDatasetGraphInMemoryIsolation extends AbstractTestTransactionIsolation {
+
+    @Override
+    protected DatasetGraph create() {
+        return new DatasetGraphInMemory() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
new file mode 100644
index 0000000..85a574f
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionIsolation.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.transaction;
+
+import static org.apache.jena.query.ReadWrite.* ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.sse.SSE ;
+import org.apache.jena.system.ThreadAction ;
+import org.apache.jena.system.ThreadTxn ;
+import org.junit.Assert ;
+import org.junit.Test ;
+
+/** Isolation tests */
+public abstract class AbstractTestTransactionIsolation {
+    
+    protected abstract DatasetGraph create() ; 
+    static Quad q1 = SSE.parseQuad("(_ :s :p 111)") ;
+    
+    @Test
+    public void isolation_01() {
+        // Start a read transaction on another thread.
+        // The transaction has begin() by the time threadTxnRead
+        // returns but the action of the ThreadTxn is not triggered
+        // until other.run() is called.
+        DatasetGraph dsg = create() ;
+        ThreadAction other = ThreadTxn.threadTxnRead(dsg, ()-> {
+            long x = Iter.count(dsg.find()) ;
+            Assert.assertEquals(0, x) ;
+        }) ;
+        dsg.begin(WRITE) ;
+        dsg.add(q1) ;
+        dsg.commit() ;
+        dsg.end() ;
+        other.run() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionLifecycle.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionLifecycle.java b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionLifecycle.java
index d8b8567..32b8ca3 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionLifecycle.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/transaction/AbstractTestTransactionLifecycle.java
@@ -252,8 +252,6 @@ public abstract class AbstractTestTransactionLifecycle extends BaseTest
     @Test 
     public void transaction_err_12()    { testAbortCommit(WRITE) ; }
 
-    
-    
     private void read1(Dataset ds) {
         ds.begin(ReadWrite.READ) ;
         assertTrue(ds.isInTransaction()) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java
index 60c4d88..235f3b9 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java
@@ -380,7 +380,7 @@ public class TransactionManager
     synchronized
     private DatasetGraphTxn promote2$(DatasetGraphTxn dsgtxn, boolean readCommited) {
         Transaction txn = dsgtxn.getTransaction() ;
-        // Writers may have happened between the first check of  of the active writers may have committed.  
+        // Writers may have happened between the first check of the active writers may have committed.  
         if ( txn.getVersion() != version.get() ) {
             releaseWriterLock();
             throw new TDBTransactionException("Active writer changed the dataset - can't promote") ;

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
index 7a9d288..e1f8af4 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TS_TransactionTDB.java
@@ -43,6 +43,7 @@ import org.junit.runners.Suite ;
     , TestTDBInternal.class
     , TestTransPromote.class
     , TestTransControl.class
+    , TestTransIsolation.class
 })
 public class TS_TransactionTDB
 {

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransIsolation.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransIsolation.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransIsolation.java
new file mode 100644
index 0000000..ba2ff10
--- /dev/null
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransIsolation.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.tdb.transaction;
+
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.transaction.AbstractTestTransactionIsolation ;
+import org.apache.jena.tdb.TDBFactory ;
+
+public class TestTransIsolation extends AbstractTestTransactionIsolation {
+
+    @Override
+    protected DatasetGraph create() {
+        return TDBFactory.createDatasetGraph() ;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/51175d27/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
index 1d1d686..5e62924 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
@@ -45,7 +45,7 @@ public class TestTransPromote {
 
     // Currently,
     // this feature is off and needs enabling via DatasetGraphTransaction.promotion
-    // promotiion is implicit whe a write happens.
+    // promotion is implicit when a write happens.
 
     // See beforeClass / afterClass.
 
@@ -62,9 +62,6 @@ public class TestTransPromote {
         stdReadCommitted = DatasetGraphTransaction.readCommittedPromotion ;
         level1 = logger1.getLevel() ;
         level2 = logger2.getLevel() ;
-        
-        // logger1.setLevel(Level.ERROR) ;
-        // logger2.setLevel(Level.ERROR) ;
     }
 
     @AfterClass