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/08/17 16:01:34 UTC

[01/11] jena git commit: JENA-1223: Have a data version and use to verify promotion.

Repository: jena
Updated Branches:
  refs/heads/master 244e0ace7 -> f4915e7f6


JENA-1223: Have a data version and use to verify promotion.

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

Branch: refs/heads/master
Commit: 39a8c3e1cf1f45caf5cc5557643f4cc64ead65b1
Parents: 0142c3b
Author: Andy Seaborne <an...@apache.org>
Authored: Fri Aug 12 21:18:42 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../jena/tdb/transaction/Transaction.java       |  5 +++-
 .../tdb/transaction/TransactionManager.java     | 25 ++++++++++++++------
 .../transaction/AbstractTestNodeTableTrans.java |  2 +-
 .../AbstractTestObjectFileTrans.java            |  2 +-
 .../jena/tdb/transaction/TestTransPromote.java  | 13 ++++++----
 5 files changed, 32 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/39a8c3e1/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
index 76262b0..309abf4 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
@@ -41,6 +41,7 @@ public class Transaction
     private final List<BlockMgrJournal> blkMgrs = new ArrayList<>() ;
     // The dataset this is a transaction over - may be a commited, pending dataset.
     private final DatasetGraphTDB   basedsg ;
+    private final long version ;
 
     private final List<Iterator<?>> iterators ;     // Tracking iterators 
     private DatasetGraphTxn         activedsg ;
@@ -52,7 +53,7 @@ public class Transaction
     
     private boolean changesPending ;
     
-    public Transaction(DatasetGraphTDB dsg, ReadWrite mode, long id, String label, TransactionManager txnMgr) {
+    public Transaction(DatasetGraphTDB dsg, long version, ReadWrite mode, long id, String label, TransactionManager txnMgr) {
         this.id = id ;
         if (label == null )
             label = "Txn" ;
@@ -65,6 +66,7 @@ public class Transaction
         this.label = label ;
         this.txnMgr = txnMgr ;
         this.basedsg = dsg ;
+        this.version = version ;
         this.mode = mode ;
         this.journal = ( txnMgr == null ) ? null : txnMgr.getJournal() ;
         activedsg = null ;      // Don't know yet.
@@ -268,6 +270,7 @@ public class Transaction
     public TransactionManager getTxnMgr()           { return txnMgr ; }
     
     public DatasetGraphTxn getActiveDataset()       { return activedsg ; }
+    public long getVersion()                        { return version ; }
 
     /*package*/ void setActiveDataset(DatasetGraphTxn activedsg) { 
         this.activedsg = activedsg ;

http://git-wip-us.apache.org/repos/asf/jena/blob/39a8c3e1/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 1a65277..efbc764 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
@@ -93,6 +93,11 @@ public class TransactionManager
     List<Transaction> commitedAwaitingFlush = new ArrayList<>() ;
     
     static AtomicLong transactionId = new AtomicLong(1) ;
+    // The version of the data starting at 1. The contract is that this is
+    // never the same for two version (it may not be monotonic increasing).
+    // Currently, it is sequentially increasing.
+    // Set on each commit.
+    private AtomicLong version = new AtomicLong(0) ;
     
     // Accessed by SysTxnState
     // These must be AtomicLong
@@ -342,13 +347,18 @@ public class TransactionManager
 //            // Would this block corrctly? ... drops the sync lock?
 //            acquireWriterLock(true) ;
 
-        // 2/ Check the database view has not moved on.
-        DatasetGraphTDB current  = determineBaseDataset() ;
-        DatasetGraphTDB starting = txn.getBaseDataset() ;
-        // Compare by object identity.
-        if ( current != starting )
-            throw new TDBTransactionException("Dataset changed - can't promote") ;
+        // 2/ Check the database view has not moved on. No active writers at the moment.
         
+        if ( txn.getVersion() != version.get() )
+            throw new TDBTransactionException("Dataset changed - can't promote") ;
+
+        // This is an equivalent test.
+//        // Compare by object identity.
+//        DatasetGraphTDB current  = determineBaseDataset() ;
+//        DatasetGraphTDB starting = txn.getBaseDataset() ;
+//        if ( current != starting )
+//            throw new TDBTransactionException("Dataset changed - can't promote") ;
+
         // Need to go through begin for the writers lock. 
         DatasetGraphTxn dsgtxn2 = begin( ReadWrite.WRITE, txn.getLabel()) ;
         return dsgtxn2 ;
@@ -409,7 +419,7 @@ public class TransactionManager
           return dsg ;
       }
     private Transaction createTransaction(DatasetGraphTDB dsg, ReadWrite mode, String label) {
-        Transaction txn = new Transaction(dsg, mode, transactionId.getAndIncrement(), label, this) ;
+        Transaction txn = new Transaction(dsg, version.get(), mode, transactionId.getAndIncrement(), label, this) ;
         return txn ;
     }
 
@@ -452,6 +462,7 @@ public class TransactionManager
         switch ( transaction.getMode() ) {
             case READ: break ;
             case WRITE:
+                version.incrementAndGet() ;
                 currentReaderView.set(null) ;       // Clear the READ transaction cache.
                 releaseWriterLock();
         }

http://git-wip-us.apache.org/repos/asf/jena/blob/39a8c3e1/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestNodeTableTrans.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestNodeTableTrans.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestNodeTableTrans.java
index bac63dd..c676c39 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestNodeTableTrans.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestNodeTableTrans.java
@@ -72,7 +72,7 @@ public abstract class AbstractTestNodeTableTrans extends BaseTest
     
     Transaction createTxn(long id) 
     {
-        return new Transaction(null, ReadWrite.WRITE, id, null, null) ; 
+        return new Transaction(null, 99, ReadWrite.WRITE, id, null, null) ; 
     }
     
     @Test public void nodetrans_01()

http://git-wip-us.apache.org/repos/asf/jena/blob/39a8c3e1/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestObjectFileTrans.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestObjectFileTrans.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestObjectFileTrans.java
index a1ca123..49dc7ee 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestObjectFileTrans.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/AbstractTestObjectFileTrans.java
@@ -49,7 +49,7 @@ public abstract class AbstractTestObjectFileTrans extends BaseTest
     @Before
     public void setup()
     {
-        txn = new Transaction(null, ReadWrite.WRITE, ++count, null, tm) ;
+        txn = new Transaction(null, 5, ReadWrite.WRITE, ++count, null, tm) ;
         file1 = createFile("base") ;
         file2 = createFile("log") ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/39a8c3e1/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 f843e76..a32ba30 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
@@ -259,7 +259,8 @@ public class TestTransPromote {
         }) ;
     }
 
-    // Tests for XXX Read-committed yes/no, and whether the other transaction commits or aborts.
+    // 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) ; }
@@ -297,8 +298,9 @@ public class TestTransPromote {
         logger2.setLevel(level2);
     }
     
-    // Test whether a writer casuses a snapshot isolation
-    // promotion to fail like it should
+    // Test whether an active writer causes a snapshot isolation
+    // promotion to fail like it should.
+    // No equivalent read commiter version - it would block. 
     @Test(expected=TDBTransactionException.class)
     public void promote_clash_1() { 
         DatasetGraphTransaction.readCommittedPromotion = false ;
@@ -318,8 +320,9 @@ public class TestTransPromote {
         sema1.acquireUninterruptibly(); 
         // The thread is in the write.
         dsg.begin(ReadWrite.READ) ;
-        // If read commited this will block.
-        // If snapshot, this will though an exception due to the active writer.
+        // ++ If read commited, the promotion will block. ++
+        // because the other-thread writer is blocked. 
+        // If snapshot, this will cause an exception due to the active writer.
         dsg.add(q1) ;
         fail("Should not be here") ;
         dsg.commit() ;


[08/11] jena git commit: Align to ThreadAction changes in Jena.

Posted by an...@apache.org.
Align to ThreadAction changes in Jena.


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

Branch: refs/heads/master
Commit: f0d389d5600f4a10ef6c10e352e13bb9de2dfe3c
Parents: 39a8c3e
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Aug 13 15:10:57 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sun Aug 14 20:22:12 2016 +0100

----------------------------------------------------------------------
 .../apache/jena/tdb/transaction/TransactionManager.java  | 11 ++++++-----
 .../apache/jena/tdb/transaction/TestTransPromote.java    |  5 +++--
 2 files changed, 9 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/f0d389d5/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 efbc764..da98a92 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
@@ -339,16 +339,17 @@ public class TransactionManager
         }           
         
         // Don't promote if the database has moved on.
+
         // 1/ No active writers.
-        //    Ideally, wiait to see if it aborts but abort is uncommon. 
+        //    Ideally, wait to see if it aborts but abort is uncommon.
+        //    We can not grab the write lock here - we have the TM sync lock
+        //    so an active writer can not commit.s
+        
         // Easy implementation -- if any active writers, don't promote.
         if ( activeWriters.get() > 0 )
-            throw new TDBTransactionException("Dataset may be changing - active writer - can't promote") ;
-//            // Would this block corrctly? ... drops the sync lock?
-//            acquireWriterLock(true) ;
+             throw new TDBTransactionException("Dataset may be changing - active writer - can't promote") ;
 
         // 2/ Check the database view has not moved on. No active writers at the moment.
-        
         if ( txn.getVersion() != version.get() )
             throw new TDBTransactionException("Dataset changed - can't promote") ;
 

http://git-wip-us.apache.org/repos/asf/jena/blob/f0d389d5/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 a32ba30..2ae1ad1 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
@@ -29,6 +29,7 @@ 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 ;
@@ -225,7 +226,7 @@ public class TestTransPromote {
         DatasetGraphTransaction.readCommittedPromotion = b ;
         DatasetGraph dsg = create() ;
         // Start long running reader.
-        ThreadTxn tt = ThreadTxn.threadTxnRead(dsg, () -> {
+        ThreadAction tt = ThreadTxn.threadTxnRead(dsg, () -> {
             long x = Iter.count(dsg.find()) ;
             if ( x != 0 )
                 throw new RuntimeException() ;
@@ -279,7 +280,7 @@ public class TestTransPromote {
         DatasetGraphTransaction.readCommittedPromotion = allowReadCommitted ;
         DatasetGraph dsg = create() ;
         
-        ThreadTxn tt = asyncCommit?
+        ThreadAction tt = asyncCommit?
             ThreadTxn.threadTxnWrite(dsg, () -> dsg.add(q3) ) :
             ThreadTxn.threadTxnWriteAbort(dsg, () -> dsg.add(q3)) ;
 


[10/11] jena git commit: Rename the writer lock. Tidy comments

Posted by an...@apache.org.
Rename the writer lock. Tidy comments


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

Branch: refs/heads/master
Commit: 711ab3e7affbfb35f0294ba993aaeb65c1248c7d
Parents: f972dde
Author: Andy Seaborne <an...@apache.org>
Authored: Sun Aug 14 21:10:50 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sun Aug 14 21:10:50 2016 +0100

----------------------------------------------------------------------
 .../jena/tdb/transaction/TransactionManager.java    | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/711ab3e7/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 da98a92..4753d78 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
@@ -119,8 +119,8 @@ public class TransactionManager
     // particular state creates the view datasetgraph and sets the  lastreader.
     private AtomicReference<DatasetGraphTDB> currentReaderView = new AtomicReference<>(null) ;
     
-    // Ensure single writer.
-    private Semaphore writersWaiting = new Semaphore(1, true) ;
+    // Ensure single writer. A writer calling begin(WRITE) blocks.  
+    private Semaphore writerPermits = new Semaphore(1, true) ;
     
     // All transactions need a "read" lock throughout their lifetime. 
     // Do not confuse with read/write transactions.  We need a 
@@ -485,23 +485,23 @@ public class TransactionManager
     }
     
     private void releaseWriterLock() {
-        int x = writersWaiting.availablePermits() ;
+        int x = writerPermits.availablePermits() ;
         if ( x != 0 )
-            throw new TDBTransactionException("TransactionCoordinator: Probably mismatch of enable/disableWriter calls") ;
-        writersWaiting.release() ;
+            throw new TDBTransactionException("TransactionCoordinator: Probably mismatch of enableWriters/blockWriters calls") ;
+        writerPermits.release() ;
     }
     
     private boolean acquireWriterLock(boolean canBlock) {
         if ( ! canBlock )
-            return writersWaiting.tryAcquire() ;
+            return writerPermits.tryAcquire() ;
         try { 
-            writersWaiting.acquire() ; 
+            writerPermits.acquire() ; 
             return true;
         } catch (InterruptedException e) { throw new TDBTransactionException(e) ; }
     }
     
     /** Block until no writers are active.
-     *  When this returns, yhis guarantees that the database is not changing
+     *  When this returns, it guarantees that the database is not changing
      *  and the jounral is flush to disk.
      * <p> 
      * The application must call {@link #enableWriters} later.


[06/11] jena git commit: JENA-1123: Promotable TDB transactions.

Posted by an...@apache.org.
JENA-1123: Promotable TDB transactions.

Graphs across transaction boundaries.
Do not cache default model. Assumes too much about the DatasetGraph.
Switchable promotion. Select txn/non-txn graph versions


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

Branch: refs/heads/master
Commit: a22323cc9e343855a9b1fd773ef33b8764570dfd
Parents: 37ae374
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Jul 16 20:58:00 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../apache/jena/sparql/core/DatasetImpl.java    |  10 +-
 .../src/main/java/tdb/cmdline/CmdTDBGraph.java  |   9 +-
 jena-cmds/src/main/java/tdb/tdbloader.java      |   6 +-
 .../java/org/apache/jena/tdb/TDBLoader.java     |  36 ++--
 .../apache/jena/tdb/solver/OpExecutorTDB1.java  |  20 +-
 .../apache/jena/tdb/store/DatasetGraphTDB.java  |  20 +-
 .../apache/jena/tdb/store/GraphNonTxnTDB.java   |  49 +++++
 .../org/apache/jena/tdb/store/GraphTDB.java     | 188 +++++--------------
 .../org/apache/jena/tdb/store/GraphTxnTDB.java  |  63 +++++++
 .../transaction/DatasetGraphTransaction.java    |  38 ++++
 .../tdb/transaction/TransactionManager.java     |  40 +++-
 .../jena/tdb/assembler/TestTDBAssembler.java    |   4 +-
 .../org/apache/jena/tdb/store/TestLoader.java   |   6 +-
 .../tdb/transaction/TestTransactionTDB.java     |  10 +
 14 files changed, 292 insertions(+), 207 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetImpl.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetImpl.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetImpl.java
index a8cf3f7..7c0e064 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetImpl.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetImpl.java
@@ -44,7 +44,6 @@ public class DatasetImpl implements Dataset
     protected DatasetGraph dsg = null ;
     // Allow for an external transactional. 
     private Transactional transactional = null ;
-    private Model dftModel = null ;
 
     /** Wrap an existing DatasetGraph */
     public static Dataset wrap(DatasetGraph datasetGraph) {
@@ -67,7 +66,6 @@ public class DatasetImpl implements Dataset
     {
         this.dsg = DatasetGraphFactory.create(model.getGraph()) ;
         this.transactional = dsg ;
-        dftModel = model ;
     }
 
     /** Create a Dataset with a copy of the structure of another one,
@@ -81,9 +79,7 @@ public class DatasetImpl implements Dataset
 
     @Override
     public Model getDefaultModel() { 
-        if ( dftModel == null )
-            dftModel = ModelFactory.createModelForGraph(dsg.getDefaultGraph()) ; 
-        return dftModel ;
+        return ModelFactory.createModelForGraph(dsg.getDefaultGraph()) ; 
     }
 
     @Override
@@ -121,21 +117,18 @@ public class DatasetImpl implements Dataset
     public void commit() {
         checkTransactional();
         transactional.commit();
-        dftModel = null;
     }
 
     @Override
     public void abort() {
         checkTransactional();
         transactional.abort();
-        dftModel = null;
     }
 
     @Override
     public void end() {
         checkTransactional();
         transactional.end();
-        dftModel = null;
     }
 
     private void checkTransactional() {
@@ -199,7 +192,6 @@ public class DatasetImpl implements Dataset
     @Override
     public void close() {
         dsg.close() ;
-        dftModel = null ;
     }
     
     protected Model graph2model(final Graph graph) {

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-cmds/src/main/java/tdb/cmdline/CmdTDBGraph.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/tdb/cmdline/CmdTDBGraph.java b/jena-cmds/src/main/java/tdb/cmdline/CmdTDBGraph.java
index c261831..2ec33a8 100644
--- a/jena-cmds/src/main/java/tdb/cmdline/CmdTDBGraph.java
+++ b/jena-cmds/src/main/java/tdb/cmdline/CmdTDBGraph.java
@@ -20,13 +20,12 @@ package tdb.cmdline;
 
 import jena.cmd.ArgDecl;
 import jena.cmd.CmdException;
-
 import org.apache.jena.atlas.lib.Lib ;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.graph.NodeFactory ;
 import org.apache.jena.query.Dataset ;
 import org.apache.jena.rdf.model.Model ;
-import org.apache.jena.tdb.store.GraphTDB ;
+import org.apache.jena.tdb.store.GraphNonTxnTDB ;
 
 public abstract class CmdTDBGraph extends CmdTDB
 {
@@ -64,12 +63,12 @@ public abstract class CmdTDBGraph extends CmdTDB
     
     public Node getGraphName()  { return graphName == null ? null : NodeFactory.createURI(graphName) ; } 
     
-    protected GraphTDB getGraph()
+    protected GraphNonTxnTDB getGraph()
     {
         if ( graphName != null )
-            return (GraphTDB)tdbDatasetAssembler.getDataset().getNamedModel(graphName).getGraph() ;
+            return (GraphNonTxnTDB)tdbDatasetAssembler.getDataset().getNamedModel(graphName).getGraph() ;
         else
-            return (GraphTDB)tdbDatasetAssembler.getDataset().getDefaultModel().getGraph() ;
+            return (GraphNonTxnTDB)tdbDatasetAssembler.getDataset().getDefaultModel().getGraph() ;
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-cmds/src/main/java/tdb/tdbloader.java
----------------------------------------------------------------------
diff --git a/jena-cmds/src/main/java/tdb/tdbloader.java b/jena-cmds/src/main/java/tdb/tdbloader.java
index 37ba0e4..2d6a5f8 100644
--- a/jena-cmds/src/main/java/tdb/tdbloader.java
+++ b/jena-cmds/src/main/java/tdb/tdbloader.java
@@ -22,14 +22,12 @@ import java.util.List ;
 
 import jena.cmd.ArgDecl;
 import jena.cmd.CmdException;
-
 import org.apache.jena.query.ARQ ;
 import org.apache.jena.riot.Lang ;
 import org.apache.jena.riot.RDFLanguages ;
 import org.apache.jena.tdb.TDB ;
 import org.apache.jena.tdb.TDBLoader ;
-import org.apache.jena.tdb.store.GraphTDB ;
-
+import org.apache.jena.tdb.store.GraphNonTxnTDB ;
 import tdb.cmdline.CmdTDB ;
 import tdb.cmdline.CmdTDBGraph ;
 
@@ -126,7 +124,7 @@ public class tdbloader extends CmdTDBGraph {
 //    }
 
     void loadNamedGraph(List<String> urls) {
-        GraphTDB graph = getGraph() ;
+        GraphNonTxnTDB graph = getGraph() ;
         TDBLoader.load(graph, urls, showProgress) ;
         return ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java b/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java
index a729db4..a9ef021 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java
@@ -26,7 +26,7 @@ import org.apache.jena.atlas.lib.Timer ;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.rdf.model.Model ;
 import org.apache.jena.tdb.store.DatasetGraphTDB ;
-import org.apache.jena.tdb.store.GraphTDB ;
+import org.apache.jena.tdb.store.GraphNonTxnTDB ;
 import org.apache.jena.tdb.store.bulkloader.BulkLoader ;
 import org.slf4j.Logger ;
 
@@ -36,7 +36,7 @@ import org.slf4j.Logger ;
 public class TDBLoader
 {
     /** Load the contents of URL into a dataset.  URL must name a quads format file (NQuads or TriG - NTriples is also accepted).
-     *  To a triples format, use {@link #load(GraphTDB, String)}
+     *  To a triples format, use {@link #load(GraphNonTxnTDB, String)}
      *  or {@link #load(DatasetGraphTDB, List, boolean, boolean)}
     */
     public static void load(DatasetGraphTDB dataset, String url)
@@ -45,7 +45,7 @@ public class TDBLoader
     }
 
     /** Load the contents of URL into a dataset.  URL must name a quads format file (NQuads or TriG - NTriples is also accepted).
-     *  To a triples format, use {@link #load(GraphTDB, String, boolean)} 
+     *  To a triples format, use {@link #load(GraphNonTxnTDB, String, boolean)} 
      *  or {@link #load(DatasetGraphTDB, List, boolean, boolean)}
     */
     public static void load(DatasetGraphTDB dataset, String url, boolean showProgress)
@@ -54,7 +54,7 @@ public class TDBLoader
     }
 
     /** Load the contents of URL into a dataset.  URL must name a quads format file (NQuads or TriG - NTriples is also accepted).
-     *  To load a triples format, use {@link #load(GraphTDB, List, boolean)} 
+     *  To load a triples format, use {@link #load(GraphNonTxnTDB, List, boolean)} 
      *  or {@link #load(DatasetGraphTDB, List, boolean, boolean)} 
     */
     public static void load(DatasetGraphTDB dataset, List<String> urls)
@@ -63,7 +63,7 @@ public class TDBLoader
     }
     
     /** Load the contents of URL into a dataset.  URL must name a quads format file (NQuads or TriG - NTriples is also accepted).
-     *  To load a triples format, use {@link #load(GraphTDB, List, boolean)} 
+     *  To load a triples format, use {@link #load(GraphNonTxnTDB, List, boolean)} 
      *  or {@link #load(DatasetGraphTDB, List, boolean, boolean)} 
     */
     public static void load(DatasetGraphTDB dataset, List<String> urls, boolean showProgress, boolean generateStats)
@@ -86,25 +86,25 @@ public class TDBLoader
     }
     
     /** Load the contents of URL into a graph */
-    public static void load(GraphTDB graph, String url)
+    public static void load(GraphNonTxnTDB graph, String url)
     {
         load(graph, url, false) ;
     }
     
     /** Load the contents of URL into a graph */
-    public static void load(GraphTDB graph, String url, boolean showProgress)
+    public static void load(GraphNonTxnTDB graph, String url, boolean showProgress)
     {
         load(graph, asList(url), showProgress) ;
     }
 
     /** Load the contents of URL into a graph */
-    public static void load(GraphTDB graph, List<String> urls)
+    public static void load(GraphNonTxnTDB graph, List<String> urls)
     {
         load(graph, urls, false) ;
     }
     
     /** Load the contents of URL into a graph */
-    public static void load(GraphTDB graph, List<String> urls, boolean showProgress)
+    public static void load(GraphNonTxnTDB graph, List<String> urls, boolean showProgress)
     {
         TDBLoader loader = new TDBLoader() ;
         loader.setShowProgress(showProgress) ;
@@ -163,19 +163,19 @@ public class TDBLoader
     public TDBLoader() {}
 
     /** Load a graph from a URL - assumes URL names a triples format document*/
-    public void loadGraph(GraphTDB graph, String url)
+    public void loadGraph(GraphNonTxnTDB graph, String url)
     {
         loadGraph(graph, asList(url)) ;
     }
     
     /** Load a graph from a list of URL - assumes the URLs name triples format documents */
-    public void loadGraph(GraphTDB graph, List<String> urls)
+    public void loadGraph(GraphNonTxnTDB graph, List<String> urls)
     {
         loadGraph$(graph, urls, showProgress, generateStats) ;
     }
     
     /** Load a graph from a list of URL - assumes the URLs name triples format documents */
-    public void loadGraph(GraphTDB graph, InputStream in)
+    public void loadGraph(GraphNonTxnTDB graph, InputStream in)
     {
         loadGraph$(graph, in, showProgress, generateStats) ;
     }
@@ -225,20 +225,20 @@ public class TDBLoader
 //    public final void setLogger(Logger log)
 //    { this.loaderLog = log ; }
     
-    private static void loadGraph$(GraphTDB graph, List<String> urls, boolean showProgress, boolean collectStats) {
+    private static void loadGraph$(GraphNonTxnTDB graph, List<String> urls, boolean showProgress, boolean collectStats) {
         if ( graph.getGraphName() == null )
-            loadDefaultGraph$(graph.getDSG(), urls, showProgress, collectStats) ;
+            loadDefaultGraph$(graph.getDatasetGraphTDB(), urls, showProgress, collectStats) ;
         else
-            loadNamedGraph$(graph.getDSG(), graph.getGraphName(), urls, showProgress, collectStats) ;
+            loadNamedGraph$(graph.getDatasetGraphTDB(), graph.getGraphName(), urls, showProgress, collectStats) ;
     }
 
     // These are the basic operations for TDBLoader.
 
-    private static void loadGraph$(GraphTDB graph, InputStream input, boolean showProgress, boolean collectStats) {
+    private static void loadGraph$(GraphNonTxnTDB graph, InputStream input, boolean showProgress, boolean collectStats) {
         if ( graph.getGraphName() == null )
-            loadDefaultGraph$(graph.getDSG(), input, showProgress, collectStats) ;
+            loadDefaultGraph$(graph.getDatasetGraphTDB(), input, showProgress, collectStats) ;
         else
-            loadNamedGraph$(graph.getDSG(), graph.getGraphName(), input, showProgress, collectStats) ;
+            loadNamedGraph$(graph.getDatasetGraphTDB(), graph.getGraphName(), input, showProgress, collectStats) ;
     }
 
     private static void loadDefaultGraph$(DatasetGraphTDB dataset, List<String> urls, boolean showProgress, boolean collectStats) {

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/solver/OpExecutorTDB1.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/solver/OpExecutorTDB1.java b/jena-tdb/src/main/java/org/apache/jena/tdb/solver/OpExecutorTDB1.java
index f039baa..11892c0 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/solver/OpExecutorTDB1.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/solver/OpExecutorTDB1.java
@@ -159,22 +159,22 @@ public class OpExecutorTDB1 extends OpExecutor
     private static QueryIterator executeBGP(GraphTDB graph, OpBGP opBGP, QueryIterator input, ExprList exprs, 
                                             ExecutionContext execCxt)
     {
+        DatasetGraphTDB dsgtdb = graph.getDatasetGraphTDB() ;
         // Is it the real default graph (normal route or explicitly named)?
         if ( ! isDefaultGraphStorage(graph.getGraphName()))
         {
             // Not default storage - it's a named graph in storage. 
-            DatasetGraphTDB ds = graph.getDSG() ;
-            return optimizeExecuteQuads(ds, input, graph.getGraphName(), opBGP.getPattern(), exprs, execCxt) ;
+            return optimizeExecuteQuads(dsgtdb, input, graph.getGraphName(), opBGP.getPattern(), exprs, execCxt) ;
         }
         
         // Execute a BGP on the real default graph
-        return optimizeExecuteTriples(graph, input, opBGP.getPattern(), exprs, execCxt) ;
+        return optimizeExecuteTriples(dsgtdb, input, opBGP.getPattern(), exprs, execCxt) ;
     }
 
     /** Execute, with optimization, a basic graph pattern on the default graph storage */
-    private static QueryIterator optimizeExecuteTriples(GraphTDB graph, QueryIterator input,
+    private static QueryIterator optimizeExecuteTriples(DatasetGraphTDB dsgtdb, QueryIterator input,
                                                         BasicPattern pattern, ExprList exprs,
-                                                        ExecutionContext execCxt)
+                                                        ExecutionContext execCxt) 
     {
         if ( ! input.hasNext() )
             return input ;
@@ -184,7 +184,7 @@ public class OpExecutorTDB1 extends OpExecutor
         if ( pattern.size() >= 2 )
         {
             // Must be 2 or triples to reorder. 
-            ReorderTransformation transform = graph.getDSG().getReorderTransform() ;
+            ReorderTransformation transform = dsgtdb.getReorderTransform() ;
             if ( transform != null )
             {
                 QueryIterPeek peek = QueryIterPeek.create(input, execCxt) ;
@@ -216,7 +216,7 @@ public class OpExecutorTDB1 extends OpExecutor
 
         gn = decideGraphNode(gn, execCxt) ;
         if ( gn == null )
-            return optimizeExecuteTriples(ds.getEffectiveDefaultGraph(), input, bgp, exprs, execCxt) ;
+            return optimizeExecuteTriples(ds, input, bgp, exprs, execCxt) ;
         
         // ---- Execute quads+filters
         if ( bgp.size() >= 2 )
@@ -306,8 +306,6 @@ public class OpExecutorTDB1 extends OpExecutor
 
         if ( Quad.isUnionGraph(gn) ) 
             return Node.ANY ;
-        boolean doingUnion = false ;
-        
         return gn ;
     }
 
@@ -374,7 +372,7 @@ public class OpExecutorTDB1 extends OpExecutor
                 //return SolverLib.execute((GraphTDB)g, bgp, input, filter, execCxt) ;
                 GraphTDB gtdb = (GraphTDB)g ;
                 Node gn = decideGraphNode(gtdb.getGraphName(), execCxt) ;
-                return SolverLib.execute(gtdb.getDSG(), gn, bgp, input, filter, execCxt) ;
+                return SolverLib.execute(gtdb.getDatasetGraphTDB(), gn, bgp, input, filter, execCxt) ;
             }
             Log.warn(this, "Non-GraphTDB passed to OpExecutorPlainTDB") ;
             return super.execute(opBGP, input) ;
@@ -402,7 +400,7 @@ public class OpExecutorTDB1 extends OpExecutor
                 BasicPattern bgp = opQuadPattern.getBasicPattern() ;
                 Explain.explain("Execute", bgp, execCxt.getContext()) ;
                 // Don't pass in G -- gn may be different.
-                return SolverLib.execute(((GraphTDB)g).getDSG(), gn, bgp, input, filter, execCxt) ;
+                return SolverLib.execute(((GraphTDB)g).getDatasetGraphTDB(), gn, bgp, input, filter, execCxt) ;
             }
             Log.warn(this, "Non-DatasetGraphTDB passed to OpExecutorPlainTDB") ;
             return super.execute(opQuadPattern, input) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/store/DatasetGraphTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/DatasetGraphTDB.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/DatasetGraphTDB.java
index ce1786e..d2a6127 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/store/DatasetGraphTDB.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/DatasetGraphTDB.java
@@ -61,7 +61,6 @@ public class DatasetGraphTDB extends DatasetGraphTriplesQuads
     private final ReorderTransformation transform ;
     private final StorageConfig config ;
     
-    private GraphTDB effectiveDefaultGraph ;
     private boolean closed = false ;
 
     public DatasetGraphTDB(TripleTable tripleTable, QuadTable quadTable, DatasetPrefixesTDB prefixes, 
@@ -71,7 +70,6 @@ public class DatasetGraphTDB extends DatasetGraphTriplesQuads
         this.prefixes = prefixes ;
         this.transform = transform ;
         this.config = config ;
-        this.effectiveDefaultGraph = getDefaultGraphTDB() ;
     }
 
     public QuadTable getQuadTable()         { return quadTable ; }
@@ -105,11 +103,11 @@ public class DatasetGraphTDB extends DatasetGraphTriplesQuads
     protected void deleteFromNamedGraph(Node g, Node s, Node p, Node o)
     { getQuadTable().delete(g, s, p, o) ; }
     
-    public GraphTDB getDefaultGraphTDB() 
-    { return (GraphTDB)getDefaultGraph() ; }
+    public GraphNonTxnTDB getDefaultGraphTDB() 
+    { return (GraphNonTxnTDB)getDefaultGraph() ; }
 
-    public GraphTDB getGraphTDB(Node graphNode)
-    { return (GraphTDB)getGraph(graphNode) ; }
+    public GraphNonTxnTDB getGraphTDB(Node graphNode)
+    { return (GraphNonTxnTDB)getGraph(graphNode) ; }
 
     @Override
     public void close() {
@@ -145,17 +143,15 @@ public class DatasetGraphTDB extends DatasetGraphTriplesQuads
         return result ;
     }
 
+    // When not yet transactional, these can be called??
+    
     @Override
     public Graph getDefaultGraph()
-    { return new GraphTDB(this, null) ; }
+    { return new GraphNonTxnTDB(this, null) ; }
 
     @Override
     public Graph getGraph(Node graphNode)
-    { return new GraphTDB(this, graphNode) ; }
-
-    //public void setEffectiveDefaultGraph(GraphTDB g)       { effectiveDefaultGraph = g ; }
-
-    public GraphTDB getEffectiveDefaultGraph()              { return effectiveDefaultGraph ; }
+    { return new GraphNonTxnTDB(this, graphNode) ; }
 
     public StorageConfig getConfig()                        { return config ; }
     

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphNonTxnTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphNonTxnTDB.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphNonTxnTDB.java
new file mode 100644
index 0000000..45457e5
--- /dev/null
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphNonTxnTDB.java
@@ -0,0 +1,49 @@
+/*
+ * 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.store ;
+
+import org.apache.jena.atlas.lib.Closeable ;
+import org.apache.jena.atlas.lib.Sync ;
+import org.apache.jena.graph.Node ;
+
+/**
+ * Non-transactional version of {@link GraphTDB}. Handed out by DatasetGraphTDB when used
+ * directly.
+ * 
+ * @see GraphTDB
+ * @see GraphTxnTDB
+ */
+public class GraphNonTxnTDB extends GraphTDB implements Closeable, Sync {
+    private final DatasetGraphTDB    dataset ;
+
+    public GraphNonTxnTDB(DatasetGraphTDB dataset, Node graphName) {
+        super(dataset, graphName) ;
+        this.dataset = dataset ;
+    }
+
+    @Override
+    public DatasetGraphTDB getDatasetGraphTDB() {
+        return dataset ;
+    }
+
+    @Override
+    protected DatasetGraphTDB getBaseDatasetGraphTDB() {
+        return dataset ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTDB.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTDB.java
index 200c99e..a60357b 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTDB.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTDB.java
@@ -26,95 +26,82 @@ import org.apache.jena.atlas.lib.Closeable ;
 import org.apache.jena.atlas.lib.Sync ;
 import org.apache.jena.atlas.lib.tuple.Tuple ;
 import org.apache.jena.atlas.lib.tuple.TupleFactory ;
-import org.apache.jena.graph.* ;
+import org.apache.jena.graph.Capabilities ;
+import org.apache.jena.graph.GraphEvents ;
+import org.apache.jena.graph.Node ;
+import org.apache.jena.graph.Triple ;
+import org.apache.jena.graph.impl.AllCapabilities ;
 import org.apache.jena.riot.other.GLib ;
 import org.apache.jena.shared.PrefixMapping ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.DatasetPrefixStorage ;
 import org.apache.jena.sparql.core.GraphView ;
 import org.apache.jena.sparql.core.Quad ;
 import org.apache.jena.tdb.TDBException ;
-import org.apache.jena.tdb.graph.TransactionHandlerTDB ;
 import org.apache.jena.tdb.store.nodetupletable.NodeTupleTable ;
 import org.apache.jena.util.iterator.ExtendedIterator ;
 import org.apache.jena.util.iterator.WrappedIterator ;
 
 /**
- * General operations for TDB graphs (free-standing graph, default graph and
- * named graphs)
+ * General operations for TDB graphs
+ * (free-standing graph, default graph and named graphs)
  */
-public class GraphTDB extends GraphView implements Closeable, Sync {
-    private final TransactionHandler transactionHandler = new TransactionHandlerTDB(this) ;
-
-    // Switch this to DatasetGraphTransaction
-    private final DatasetGraphTDB    dataset ;
-
-    public GraphTDB(DatasetGraphTDB dataset, Node graphName) {
+public abstract class GraphTDB extends GraphView implements Closeable, Sync {
+    public GraphTDB(DatasetGraph dataset, Node graphName) {
         super(dataset, graphName) ;
-        this.dataset = dataset ;
     }
 
-    /** get the current TDB dataset graph - changes for transactions */
-    public DatasetGraphTDB getDSG() {
-        return dataset ;
+    /** Return the associated DatasetGraphTDB.
+     * For non-transactional, that's the base storage.
+     * For transactional, it is the transactional view.
+     * <p>
+     * Immediate validity only.
+     * Not valid actoss transacion boundaries, nor non-transactional to transactional. 
+     */
+    public abstract DatasetGraphTDB getDatasetGraphTDB() ;
+    
+    /** Return the associated base DatasetGraphTDB storage.
+     * Use with great care.
+     * <p>
+     * Immediate validity only.
+     */
+    protected abstract DatasetGraphTDB getBaseDatasetGraphTDB() ;
+    
+    protected DatasetPrefixStorage getPrefixStorage() {
+        return getDatasetGraphTDB().getPrefixes() ;
     }
 
-    /** The NodeTupleTable for this graph */
+    /** The NodeTupleTable for this graph - valid only inside the transaction or non-transactional. */
     public NodeTupleTable getNodeTupleTable() {
-        return getDSG().chooseNodeTupleTable(getGraphName()) ;
+        return getDatasetGraphTDB().chooseNodeTupleTable(getGraphName()) ;
     }
 
     @Override
     protected PrefixMapping createPrefixMapping() {
+        // [TXN] Make transactional.
+        DatasetPrefixStorage dsgPrefixes = getDatasetGraphTDB().getPrefixes() ;
         if ( isDefaultGraph() )
-            return getDSG().getPrefixes().getPrefixMapping() ;
+            return dsgPrefixes.getPrefixMapping() ;
         if ( isUnionGraph() )
-            return getDSG().getPrefixes().getPrefixMapping() ;
-        return getDSG().getPrefixes().getPrefixMapping(getGraphName().getURI()) ;
+            return dsgPrefixes.getPrefixMapping() ;
+        return dsgPrefixes.getPrefixMapping(getGraphName().getURI()) ;
     }
 
     @Override
     public final void sync() {
-        dataset.sync() ;
+        getDatasetGraphTDB().sync();
     }
 
     @Override
     final public void close() {
         sync() ;
-        // Ignore - graphs are projections of the overlying database.
-        // "Close graph" is messy in this projection world. 
+        // Don't close the dataset.
         super.close() ;
     }
 
-    protected static ExtendedIterator<Triple> graphBaseFindDft(DatasetGraphTDB dataset, Triple triple) {
-        Iterator<Quad> iterQuads = dataset.find(Quad.defaultGraphIRI, triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
-        if ( iterQuads == null )
-            return org.apache.jena.util.iterator.NullIterator.instance() ;
-        // Can't be duplicates - fixed graph node..
-        Iterator<Triple> iterTriples = new ProjectQuadsToTriples(Quad.defaultGraphIRI, iterQuads) ;
-        return WrappedIterator.createNoRemove(iterTriples) ;
-    }
-
-    protected static ExtendedIterator<Triple> graphBaseFindNG(DatasetGraphTDB dataset, Node graphNode, Triple m) {
-        Node gn = graphNode ;
-        // Explicitly named union graph.
-        if ( isUnionGraph(gn) )
-            gn = Node.ANY ;
-
-        Iterator<Quad> iter = dataset.getQuadTable().find(gn, m.getMatchSubject(), m.getMatchPredicate(),
-                                                          m.getMatchObject()) ;
-        if ( iter == null )
-            return org.apache.jena.util.iterator.NullIterator.instance() ;
-
-        Iterator<Triple> iterTriples = new ProjectQuadsToTriples((gn == Node.ANY ? null : gn), iter) ;
-
-        if ( gn == Node.ANY )
-            iterTriples = Iter.distinct(iterTriples) ;
-        return WrappedIterator.createNoRemove(iterTriples) ;
-    }
-
     @Override
     protected ExtendedIterator<Triple> graphUnionFind(Node s, Node p, Node o) {
-        Node g = Quad.unionGraph ;
-        Iterator<Quad> iterQuads = getDSG().find(g, s, p, o) ;
+        Iterator<Quad> iterQuads = getDatasetGraphTDB().find(Quad.unionGraph, s, p, o) ;
         Iterator<Triple> iter = GLib.quads2triples(iterQuads) ;
         // Suppress duplicates after projecting to triples.
         // TDB guarantees that duplicates are adjacent.
@@ -131,7 +118,8 @@ public class GraphTDB extends GraphView implements Closeable, Sync {
         Node gn = getGraphName() ;
         boolean unionGraph = isUnionGraph(gn) ;
         gn = unionGraph ? Node.ANY : gn ;
-        Iterator<Tuple<NodeId>> iter = getDSG().getQuadTable().getNodeTupleTable().findAsNodeIds(gn, null, null, null) ;
+        QuadTable quadTable = getDatasetGraphTDB().getQuadTable() ;
+        Iterator<Tuple<NodeId>> iter = quadTable.getNodeTupleTable().findAsNodeIds(gn, null, null, null) ;
         if ( unionGraph ) {
             iter = Iter.map(iter, project4TupleTo3Tuple) ;
             iter = Iter.distinctAdjacent(iter) ;
@@ -145,101 +133,19 @@ public class GraphTDB extends GraphView implements Closeable, Sync {
 		return TupleFactory.tuple(item.get(1), item.get(2), item.get(3));
 	};
 
-    // Convert from Iterator<Quad> to Iterator<Triple>
-    static class ProjectQuadsToTriples implements Iterator<Triple> {
-        private final Iterator<Quad> iter ;
-        private final Node           graphNode ;
-
-        /**
-         * Project quads to triples - check the graphNode is as expected if not
-         * null
-         */
-        ProjectQuadsToTriples(Node graphNode, Iterator<Quad> iter) {
-            this.graphNode = graphNode ;
-            this.iter = iter ;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return iter.hasNext() ;
-        }
-
-        @Override
-        public Triple next() {
-            Quad q = iter.next() ;
-            if ( graphNode != null && !q.getGraph().equals(graphNode) )
-                throw new InternalError("ProjectQuadsToTriples: Quads from unexpected graph (expected=" + graphNode
-                                        + ", got=" + q.getGraph() + ")") ;
-            return q.asTriple() ;
-        }
-
-        @Override
-        public void remove() {
-            iter.remove() ;
-        }
-    }
-
     @Override
     public Capabilities getCapabilities() {
         if ( capabilities == null )
-            capabilities = new Capabilities() {
-                @Override
-                public boolean sizeAccurate() {
-                    return true ;
-                }
-
-                @Override
-                public boolean addAllowed() {
-                    return true ;
-                }
-
-                @Override
-                public boolean addAllowed(boolean every) {
-                    return true ;
-                }
-
-                @Override
-                public boolean deleteAllowed() {
-                    return true ;
-                }
-
-                @Override
-                public boolean deleteAllowed(boolean every) {
-                    return true ;
-                }
-
-                @Override
-                public boolean canBeEmpty() {
-                    return true ;
-                }
-
-                @Override
-                public boolean iteratorRemoveAllowed() {
-                    return false ;
-                } /* ** */
-
-                @Override
-                public boolean findContractSafe() {
-                    return true ;
-                }
-
-                @Override
-                public boolean handlesLiteralTyping() {
-                    return false ;
-                } /* ** */
+            capabilities = new AllCapabilities() {
+                @Override public boolean iteratorRemoveAllowed() { return false ; } 
+                @Override public boolean handlesLiteralTyping() { return false ; }
             } ;
-
         return super.getCapabilities() ;
     }
-
-    @Override
-    public TransactionHandler getTransactionHandler() {
-        return transactionHandler ;
-    }
-
+    
     @Override
     public void clear() {
-        dataset.deleteAny(getGraphName(), Node.ANY, Node.ANY, Node.ANY) ;
+        getDatasetGraphTDB().deleteAny(getGraphName(), Node.ANY, Node.ANY, Node.ANY) ;
         getEventManager().notifyEvent(this, GraphEvents.removeAll) ;
     }
 
@@ -251,7 +157,7 @@ public class GraphTDB extends GraphView implements Closeable, Sync {
             return ;
         }
 
-        dataset.deleteAny(getGraphName(), s, p, o) ;
+        getDatasetGraphTDB().deleteAny(getGraphName(), s, p, o) ;
         // We know no one is listening ...
         // getEventManager().notifyEvent(this, GraphEvents.remove(s, p, o) ) ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTxnTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTxnTDB.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTxnTDB.java
new file mode 100644
index 0000000..308a21c
--- /dev/null
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/GraphTxnTDB.java
@@ -0,0 +1,63 @@
+/*
+ * 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.store ;
+
+import org.apache.jena.atlas.lib.Closeable ;
+import org.apache.jena.atlas.lib.Sync ;
+import org.apache.jena.graph.Node ;
+import org.apache.jena.graph.TransactionHandler ;
+import org.apache.jena.tdb.graph.TransactionHandlerTDB ;
+import org.apache.jena.tdb.transaction.DatasetGraphTransaction ;
+
+/**
+ * Transaction version of {@link GraphTDB}.
+ * Valid across transactions excep where noted.
+ * 
+ * @see GraphTDB  
+ * @see GraphTxnTDB  
+
+ */
+public class GraphTxnTDB extends GraphTDB implements Closeable, Sync {
+    // [TXN] ??
+    private final TransactionHandler transactionHandler = new TransactionHandlerTDB(this) ;
+
+    private final DatasetGraphTransaction dataset ;
+
+    public GraphTxnTDB(DatasetGraphTransaction dataset, Node graphName) {
+        super(dataset, graphName) ;
+        this.dataset = dataset ;
+    }
+
+    @Override
+    public DatasetGraphTDB getDatasetGraphTDB() {
+        return dataset.getDatasetGraphToQuery() ;
+    }
+
+    // [TXN] Transaction prefixes.
+    
+    @Override
+    public TransactionHandler getTransactionHandler() {
+        return transactionHandler ;
+    }
+
+    @Override
+    protected DatasetGraphTDB getBaseDatasetGraphTDB() {
+        return dataset.getBaseDatasetGraph() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
index 07af449..7f3af90 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
@@ -21,14 +21,19 @@ package org.apache.jena.tdb.transaction ;
 import static java.lang.ThreadLocal.withInitial ;
 
 import org.apache.jena.atlas.lib.Sync ;
+import org.apache.jena.graph.Graph ;
+import org.apache.jena.graph.Node ;
 import org.apache.jena.query.ReadWrite ;
 import org.apache.jena.sparql.JenaTransactionException ;
+import org.apache.jena.sparql.core.DatasetGraph ;
 import org.apache.jena.sparql.core.DatasetGraphTrackActive ;
 import org.apache.jena.sparql.util.Context ;
 import org.apache.jena.tdb.StoreConnection ;
 import org.apache.jena.tdb.TDB ;
 import org.apache.jena.tdb.base.file.Location ;
 import org.apache.jena.tdb.store.DatasetGraphTDB ;
+import org.apache.jena.tdb.store.GraphNonTxnTDB ;
+import org.apache.jena.tdb.store.GraphTxnTDB ;
 
 /**
  * A transactional {@code DatasetGraph} that allows one active transaction per thread.
@@ -69,6 +74,7 @@ import org.apache.jena.tdb.store.DatasetGraphTDB ;
         return sConn.getLocation() ;
     }
 
+    // getCurrentTxnDSG
     public DatasetGraphTDB getDatasetGraphToQuery() {
         checkNotClosed() ;
         return get() ;
@@ -80,6 +86,22 @@ import org.apache.jena.tdb.store.DatasetGraphTDB ;
         return sConn.getBaseDataset() ;
     }
 
+    /*private*/public/*for development*/ static boolean promotion = false ; 
+    
+    @Override public DatasetGraph getW() {
+        if ( isInTransaction() ) {
+            if ( promotion ) {
+                DatasetGraphTxn dsgTxn = txn.get() ;
+                if ( dsgTxn.getTransaction().isRead() ) {
+                    TransactionManager txnMgr = dsgTxn.getTransaction().getTxnMgr() ;
+                    DatasetGraphTxn dsgTxn2 = txnMgr.promote(dsgTxn, true) ;
+                    txn.set(dsgTxn2); 
+                }
+            }
+        }
+        return super.getW() ;
+    }
+    
     /** Get the current DatasetGraphTDB */
     @Override
     public DatasetGraphTDB get() {
@@ -131,6 +153,22 @@ import org.apache.jena.tdb.store.DatasetGraphTDB ;
         if ( !sConn.haveUsedInTransaction() )
             sConn.getBaseDataset().sync() ;
     }
+    
+    @Override
+    public Graph getDefaultGraph() { 
+        if ( sConn.haveUsedInTransaction() )
+            return new GraphTxnTDB(this, null) ;
+        else
+            return new GraphNonTxnTDB(getBaseDatasetGraph(), null) ;
+    }
+
+    @Override
+    public Graph getGraph(Node graphNode) {      
+        if ( sConn.haveUsedInTransaction() )
+            return new GraphTxnTDB(this, graphNode) ;
+        else
+            return new GraphNonTxnTDB(getBaseDatasetGraph(), graphNode) ;
+    }
 
     @Override
     protected void _begin(ReadWrite readWrite) {

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/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 db091e7..e4dcfae 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
@@ -289,7 +289,7 @@ public class TransactionManager
         exclusivitylock.readLock().lock() ;
         
         // Not synchronized (else blocking on semaphore will never wake up
-        // because Semaphore.release is inside synchronized.
+        // because Semaphore.release is inside synchronized).
         // Allow only one active writer. 
         if ( mode == ReadWrite.WRITE ) {
             // Writers take a WRITE permit from the semaphore to ensure there
@@ -300,7 +300,45 @@ public class TransactionManager
         // entry synchronized part
         return begin$(mode, label) ;
     }
+    
+    /** Ensure a DatasetGraphTxn is for a write transaction.
+     * <p>
+     * If the transaction is already a write transaction, this is an efficient
+     * no-op.
+     * <p>
+     * If the transaction is a read transaction then promotion can either respect the transactions current
+     * view of the data where no changes from other writers that started after this transaction are visible
+     * ("serialized") or the promotion can include changes by other such writers ("read committed").
+     * <p>
+     * However, "serialized" can fail, in which case an exception {@link TDBTransactionException}
+     * is thrown. The transactions can continue as a read transaction.
+     * There is no point retrying - later committed changes have been made and will remain.
+     */
+    /*package*/ DatasetGraphTxn promote(DatasetGraphTxn dsgtxn, boolean readCommited) throws TDBTransactionException {
+        if ( dsgtxn.getTransaction().getMode() == ReadWrite.WRITE )
+            return dsgtxn ;
+        return promote$(dsgtxn.getTransaction(), readCommited) ;
+    }
         
+    synchronized
+    private DatasetGraphTxn promote$(Transaction txn, boolean readCommited) {
+        // check state
+        if ( txn.getState() != TxnState.ACTIVE )
+            throw new TDBTransactionException("promote: transaction is not active") ;
+        
+        DatasetGraphTDB basedsg = txn.getBaseDataset() ;
+        // if read commiter - pick up any currentReaderView (last commited transaction)
+        if ( ! readCommited ) {
+            // Compare by object identity.
+            if ( currentReaderView.get() != basedsg )
+                throw new TDBTransactionException("Dataset changed - can't promote") ;
+        }
+        
+        // Need to go through begin for the writers lock. 
+        DatasetGraphTxn dsgtxn2 = begin( ReadWrite.WRITE, txn.getLabel()) ;
+        return dsgtxn2 ;
+    }
+
     // If DatasetGraphTransaction has a sync lock on sConn, this
     // does not need to be sync'ed. But it's possible to use some
     // of the low level object directly so we'll play safe.  

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/test/java/org/apache/jena/tdb/assembler/TestTDBAssembler.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/assembler/TestTDBAssembler.java b/jena-tdb/src/test/java/org/apache/jena/tdb/assembler/TestTDBAssembler.java
index 191794b..2c3ddeb 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/assembler/TestTDBAssembler.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/assembler/TestTDBAssembler.java
@@ -103,7 +103,7 @@ public class TestTDBAssembler extends BaseTest
         Graph graph = ((Model)thing).getGraph() ;
         assertTrue(graph instanceof GraphTDB) ; 
 
-        DatasetGraphTDB ds = ((GraphTDB)graph).getDSG() ;
+        DatasetGraphTDB ds = ((GraphTDB)graph).getDatasetGraphTDB() ;
         if ( ds != null )
             ds.close();
     }
@@ -138,7 +138,7 @@ public class TestTDBAssembler extends BaseTest
         
         assertTrue(graph instanceof GraphTDB) ; 
         
-        DatasetGraphTDB ds = ((GraphTDB)graph).getDSG() ;
+        DatasetGraphTDB ds = ((GraphTDB)graph).getDatasetGraphTDB() ;
         if ( ds != null )
             ds.close();
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/test/java/org/apache/jena/tdb/store/TestLoader.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/store/TestLoader.java b/jena-tdb/src/test/java/org/apache/jena/tdb/store/TestLoader.java
index 6b1ca04..d2c1a14 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/store/TestLoader.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/store/TestLoader.java
@@ -34,8 +34,6 @@ import org.apache.jena.tdb.ConfigTest ;
 import org.apache.jena.tdb.TDB ;
 import org.apache.jena.tdb.TDBLoader ;
 import org.apache.jena.tdb.base.file.Location ;
-import org.apache.jena.tdb.store.DatasetGraphTDB ;
-import org.apache.jena.tdb.store.GraphTDB ;
 import org.apache.jena.tdb.sys.TDBMaker ;
 import org.junit.AfterClass ;
 import org.junit.BeforeClass ;
@@ -148,7 +146,7 @@ public class TestLoader extends BaseTest {
     @Test
     public void load_graph_05() {
         DatasetGraphTDB dsg = fresh() ;
-        GraphTDB graph = dsg.getDefaultGraphTDB() ;
+        GraphNonTxnTDB graph = dsg.getDefaultGraphTDB() ;
         TDBLoader.load(graph, DIR + "data-4.ttl", false) ;
         String uri = dsg.getDefaultGraph().getPrefixMapping().getNsPrefixURI("") ;
         assertEquals("http://example/", uri) ;
@@ -157,7 +155,7 @@ public class TestLoader extends BaseTest {
     @Test
     public void load_graph_06() {
         DatasetGraphTDB dsg = fresh() ;
-        GraphTDB graph = dsg.getGraphTDB(g) ;
+        GraphNonTxnTDB graph = dsg.getGraphTDB(g) ;
         TDBLoader.load(graph, DIR + "data-4.ttl", false) ;
         String uri1 = dsg.getGraph(g).getPrefixMapping().getNsPrefixURI("") ;
         assertEquals("http://example/", uri1) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/a22323cc/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionTDB.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionTDB.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionTDB.java
index bb0a1b8..e63cf66 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionTDB.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionTDB.java
@@ -20,10 +20,13 @@ package org.apache.jena.tdb.transaction;
 
 import static org.apache.jena.query.ReadWrite.READ ;
 import static org.apache.jena.query.ReadWrite.WRITE ;
+
 import org.apache.jena.atlas.lib.FileOps ;
 import org.apache.jena.atlas.logging.LogCtl ;
+import org.apache.jena.graph.Graph ;
 import org.apache.jena.graph.Triple ;
 import org.apache.jena.query.Dataset ;
+import org.apache.jena.sparql.core.DatasetGraph ;
 import org.apache.jena.sparql.sse.SSE ;
 import org.apache.jena.sparql.transaction.AbstractTestTransactionLifecycle ;
 import org.apache.jena.tdb.ConfigTest ;
@@ -78,6 +81,13 @@ public class TestTransactionTDB extends AbstractTestTransactionLifecycle
 
         ds2.begin(READ) ;
         // See ds1 updates
+        Graph g = ds2.getDefaultModel().getGraph() ;
+        DatasetGraph dsg = ds2.asDatasetGraph() ; 
+        g = dsg.getDefaultGraph() ;
+        
+        boolean b0 = g.isEmpty() ;
+        boolean b1 = ds2.getDefaultModel().isEmpty() ;
+        
         assertFalse(ds2.getDefaultModel().isEmpty()) ;
         assertEquals(1, ds2.getDefaultModel().size()) ;
         ds2.commit() ;


[02/11] jena git commit: Fix for snapshot-style promotion. With tests.

Posted by an...@apache.org.
Fix for snapshot-style promotion. With tests.

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

Branch: refs/heads/master
Commit: 0142c3bce60808f6d7d35b482e204bb891e7d115
Parents: af5c292
Author: Andy Seaborne <an...@apache.org>
Authored: Fri Aug 12 14:24:42 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../tdb/transaction/TransactionManager.java     |  55 ++--
 .../jena/tdb/transaction/TestTransPromote.java  | 307 ++++++++++++++-----
 2 files changed, 261 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/0142c3bc/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 e4dcfae..1a65277 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
@@ -326,19 +326,34 @@ public class TransactionManager
         if ( txn.getState() != TxnState.ACTIVE )
             throw new TDBTransactionException("promote: transaction is not active") ;
         
-        DatasetGraphTDB basedsg = txn.getBaseDataset() ;
-        // if read commiter - pick up any currentReaderView (last commited transaction)
-        if ( ! readCommited ) {
-            // Compare by object identity.
-            if ( currentReaderView.get() != basedsg )
-                throw new TDBTransactionException("Dataset changed - can't promote") ;
-        }
+        if ( readCommited ) {
+            // Read commit - pick up whatever is current at the point setup.  
+            // Need to go through begin for the writers lock. 
+            DatasetGraphTxn dsgtxn2 = begin( ReadWrite.WRITE, txn.getLabel()) ;
+            return dsgtxn2 ;
+        }           
+        
+        // Don't promote if the database has moved on.
+        // 1/ No active writers.
+        //    Ideally, wiait to see if it aborts but abort is uncommon. 
+        // Easy implementation -- if any active writers, don't promote.
+        if ( activeWriters.get() > 0 )
+            throw new TDBTransactionException("Dataset may be changing - active writer - can't promote") ;
+//            // Would this block corrctly? ... drops the sync lock?
+//            acquireWriterLock(true) ;
+
+        // 2/ Check the database view has not moved on.
+        DatasetGraphTDB current  = determineBaseDataset() ;
+        DatasetGraphTDB starting = txn.getBaseDataset() ;
+        // Compare by object identity.
+        if ( current != starting )
+            throw new TDBTransactionException("Dataset changed - can't promote") ;
         
         // Need to go through begin for the writers lock. 
         DatasetGraphTxn dsgtxn2 = begin( ReadWrite.WRITE, txn.getLabel()) ;
         return dsgtxn2 ;
     }
-
+    
     // If DatasetGraphTransaction has a sync lock on sConn, this
     // does not need to be sync'ed. But it's possible to use some
     // of the low level object directly so we'll play safe.  
@@ -355,16 +370,7 @@ public class TransactionManager
                 case WRITE : System.out.print("w") ; break ;
             }
         
-        DatasetGraphTDB dsg = baseDataset ;
-        // *** But, if there are pending, committed transactions, use latest.
-        if ( !commitedAwaitingFlush.isEmpty() ) {
-            if ( DEBUG )
-                System.out.print(commitedAwaitingFlush.size()) ;
-            dsg = commitedAwaitingFlush.get(commitedAwaitingFlush.size() - 1).getActiveDataset().getView() ;
-        } else {
-            if ( DEBUG )
-                System.out.print('_') ;
-        }
+        DatasetGraphTDB dsg = determineBaseDataset() ;
         Transaction txn = createTransaction(dsg, mode, label) ;
         
         log("begin$", txn) ;
@@ -389,6 +395,19 @@ public class TransactionManager
         return dsgTxn ;
     }
     
+    private DatasetGraphTDB determineBaseDataset() {
+    //      if ( DEBUG ) {
+    //          if ( !commitedAwaitingFlush.isEmpty() )
+    //              System.out.print(commitedAwaitingFlush.size()) ;
+    //      } else {
+    //          System.out.print('_') ;
+    //      }
+          DatasetGraphTDB dsg = baseDataset ;
+          // But, if there are pending, committed transactions, use latest.
+          if ( !commitedAwaitingFlush.isEmpty() )
+              dsg = commitedAwaitingFlush.get(commitedAwaitingFlush.size() - 1).getActiveDataset().getView() ;
+          return dsg ;
+      }
     private Transaction createTransaction(DatasetGraphTDB dsg, ReadWrite mode, String label) {
         Transaction txn = new Transaction(dsg, mode, transactionId.getAndIncrement(), label, this) ;
         return txn ;

http://git-wip-us.apache.org/repos/asf/jena/blob/0142c3bc/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 e51cc29..f843e76 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
@@ -16,9 +16,10 @@
  * limitations under the License.
  */
 
-package org.apache.jena.tdb.transaction;
+package org.apache.jena.tdb.transaction ;
 
-import static org.junit.Assert.* ;
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.fail ;
 
 import java.util.concurrent.Semaphore ;
 import java.util.concurrent.atomic.AtomicInteger ;
@@ -30,158 +31,298 @@ import org.apache.jena.sparql.core.Quad ;
 import org.apache.jena.sparql.sse.SSE ;
 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.jena.tdb.transaction.DatasetGraphTransaction ;
 import org.apache.log4j.Level ;
 import org.apache.log4j.Logger ;
-import org.junit.AfterClass ;
-import org.junit.BeforeClass ;
-import org.junit.Test ;
+import org.junit.* ;
 
-/** Tests for transactions that start read and then promote to write */ 
+/** 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
-    //    promotiion is implicit whe a write happens.  
-    
-    
-    
+    // this feature is off and needs enabling via DatasetGraphTransaction.promotion
+    // promotiion is implicit whe a write happens.
+
     // See beforeClass / afterClass.
-    
-    private static Logger logger = Logger.getLogger(SystemTDB.errlog.getName()) ;
-    private static Level  level ;
-    static boolean oldPromotion ;
-    
-    @BeforeClass static public void beforeClass() {
-        oldPromotion = DatasetGraphTransaction.promotion ;
-        DatasetGraphTransaction.promotion = true ;
-        level  = logger.getLevel() ;
-        //logger.setLevel(Level.ERROR) ;
+
+    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() ;
+        
+        // logger1.setLevel(Level.ERROR) ;
+        // logger2.setLevel(Level.ERROR) ;
     }
-    
-    @AfterClass static public void afterClass() {
+
+    @AfterClass
+    static public void afterClass() {
         // Restore logging setting.
-        logger.setLevel(level); 
-        DatasetGraphTransaction.promotion = oldPromotion ;
+        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 DatasetGraph create() {
+        return TDBFactory.createDatasetGraph() ;
+    }
+
     protected static void assertCount(long expected, DatasetGraph dsg) {
-        dsg.begin(ReadWrite.READ);
+        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_01() {
+    @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.begin(ReadWrite.READ) ;
         dsg.add(q1) ;
-        dsg.commit();
+        dsg.commit() ;
         dsg.end() ;
     }
     
-    @Test public void promote_02() {
+    @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.begin(ReadWrite.READ) ;dsg.end() ;
+        
+        dsg.begin(ReadWrite.READ) ;
         dsg.add(q1) ;
-        dsg.add(q2) ;
-        dsg.commit();
+        dsg.commit() ;
         dsg.end() ;
-        assertCount(2, dsg) ;
     }
+    
+    @Test public void promote_snapshot_03()         { run_03(false) ; }
+    @Test public void promote_readCommitted_03()    { run_03(true) ; }
 
-    // Causes the warning.
-    @Test public void promote_03() {
+    private void run_03(boolean b) {
+        DatasetGraphTransaction.readCommittedPromotion = b ;
         DatasetGraph dsg = create() ;
-        dsg.begin(ReadWrite.READ); 
+        
+        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.
-        logger.setLevel(Level.ERROR) ;
+        logger1.setLevel(Level.ERROR) ;
         dsg.end() ;
-        logger.setLevel(level)  ;
-        
+        logger1.setLevel(level1) ;
+
         assertCount(0, dsg) ;
     }
+
+    @Test public void promote_snapshot_06()         { run_06(false) ; }
+    @Test public void promote_readCommitted_06()    { run_06(true) ; }
     
-    @Test public void promote_04() {
+    // 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.execWrite(dsg, ()->dsg.add(q3)) ;   
-            sema.release();
+        Thread t = new Thread(() -> {
+            sema.release() ;
+            Txn.execWrite(dsg, () -> dsg.add(q3)) ;
+            sema.release() ;
         }) ;
-        
-        dsg.begin(ReadWrite.READ);
+
+        dsg.begin(ReadWrite.READ) ;
         // Promote
         dsg.add(q1) ;
-        t.start(); 
+        t.start() ;
         // First release.
-        sema.acquireUninterruptibly();
-        // Thread blocked. 
+        sema.acquireUninterruptibly() ;
+        // Thread blocked.
         dsg.add(q2) ;
-        dsg.commit();
+        dsg.commit() ;
         dsg.end() ;
-        
+
         // Until thread exits.
-        sema.acquireUninterruptibly();
+        sema.acquireUninterruptibly() ;
         assertCount(3, dsg) ;
     }
+
+    @Test public void promote_snapshot_07()         { run_07(false) ; }
+    @Test public void promote_readCommitted_07()    { run_07(true) ; }
     
-    @Test public void promote_05() {
+    // Async writer after promotion.
+    private void run_07(boolean b) {
+        DatasetGraphTransaction.readCommittedPromotion = b ;
         DatasetGraph dsg = create() ;
         // Start long running reader.
-        ThreadTxn tt = ThreadTxn.threadTxnRead(dsg, ()->{
+        ThreadTxn tt = ThreadTxn.threadTxnRead(dsg, () -> {
             long x = Iter.count(dsg.find()) ;
-            if ( x != 0 ) 
+            if ( x != 0 )
                 throw new RuntimeException() ;
         }) ;
-    
+
         // Start R->W here
-        dsg.begin(ReadWrite.READ); 
+        dsg.begin(ReadWrite.READ) ;
         dsg.add(q1) ;
         dsg.add(q2) ;
-        dsg.commit();
+        dsg.commit() ;
         dsg.end() ;
-        tt.run();
+        tt.run() ;
     }
     
-    @Test public void promote_06() {
-        promoteRC(true) ;
-    }
-        
-    @Test(expected=TDBTransactionException.class)
-    public void promote_07() {
-        promoteRC(false) ;
-    }
-     
-    private void promoteRC(boolean allowReadCommitted) {
-        DatasetGraphTransaction.readCommittedPromotion = allowReadCommitted ;    
+    @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.execRead(dsg, () -> {
+            long x = Iter.count(dsg.find()) ;
+            assertEquals(2, x) ;
+        }) ;
+    }
+
+    // Tests for XXX Read-committed yes/no, and whether the other transaction commits or aborts.
+    
+    @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) ; }
 
-        ThreadTxn tt = ThreadTxn.threadTxnWrite(dsg, ()->{dsg.add(q3) ;}) ;
+    private void promote_readCommit_txnCommit(boolean allowReadCommitted, boolean asyncCommit) {
+        logger2.setLevel(Level.ERROR);
+        DatasetGraphTransaction.readCommittedPromotion = allowReadCommitted ;
+        DatasetGraph dsg = create() ;
         
-        dsg.begin(ReadWrite.READ);
+        ThreadTxn 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
+        tt.run() ;
+        // Can promote if readCommited
         // Can't promote if not readCommited
         dsg.add(q1) ;
-        assertTrue(dsg.contains(q3)) ;
-        dsg.commit();
+        if ( ! allowReadCommitted && asyncCommit )
+            fail("Should not be here") ;
+        
+        assertEquals(asyncCommit, dsg.contains(q3)) ;
+        dsg.commit() ;
+        dsg.end() ;
+        logger2.setLevel(level2);
+    }
+    
+    // Test whether a writer casuses a snapshot isolation
+    // promotion to fail like it should
+    @Test(expected=TDBTransactionException.class)
+    public void promote_clash_1() { 
+        DatasetGraphTransaction.readCommittedPromotion = false ;
+        DatasetGraph dsg = create() ;
+        Semaphore sema1 = new Semaphore(0) ;
+        Semaphore sema2 = new Semaphore(0) ;
+        Runnable r = ()->{
+            dsg.begin(ReadWrite.WRITE) ; 
+            sema1.release(1); 
+            sema2.acquireUninterruptibly(1) ;
+            dsg.commit() ; 
+            dsg.end() ; 
+        } ;
+        
+        // Create a writer that waits.
+        new Thread(r).start(); 
+        sema1.acquireUninterruptibly(); 
+        // The thread is in the write.
+        dsg.begin(ReadWrite.READ) ;
+        // If read commited this will block.
+        // If snapshot, this will though an exception due to the active writer.
+        dsg.add(q1) ;
+        fail("Should not be here") ;
+        dsg.commit() ;
         dsg.end() ;
     }
-
 }


[11/11] jena git commit: JENA-1223. https://github.com/apache/jena/pull/161 This closes #161.

Posted by an...@apache.org.
JENA-1223. https://github.com/apache/jena/pull/161
This closes #161.


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

Branch: refs/heads/master
Commit: f4915e7f69a1fb93a31e42bc4b74cb44eb131996
Parents: 711ab3e
Author: Andy Seaborne <an...@apache.org>
Authored: Wed Aug 17 14:55:51 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Wed Aug 17 14:55:51 2016 +0100

----------------------------------------------------------------------

----------------------------------------------------------------------



[04/11] jena git commit: Split different categories of get() : R, W, G and T.

Posted by an...@apache.org.
Split different categories of get() : R, W, G and T.

Setup for JENA-1123 (txn promotion)

Remove pointless private constructor.
Make some methods package access.

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

Branch: refs/heads/master
Commit: 37ae374c1712db477625a2fa650f945c1ae0f15d
Parents: 244e0ac
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Jul 16 20:51:57 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../sparql/core/DatasetGraphTrackActive.java    |  2 +-
 .../jena/sparql/core/DatasetGraphWrapper.java   | 76 +++++++++++---------
 .../jena/sparql/core/TransactionalLock.java     |  5 --
 .../sparql/modify/TestUpdateOperations.java     |  4 +-
 .../jena/query/spatial/DatasetGraphSpatial.java | 16 ++---
 .../jena/tdb/transaction/DatasetGraphTxn.java   |  2 +-
 .../jena/tdb/transaction/Transaction.java       | 10 ++-
 .../jena/query/text/DatasetGraphText.java       | 12 ++--
 8 files changed, 66 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphTrackActive.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphTrackActive.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphTrackActive.java
index 705d64a..7e29034 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphTrackActive.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphTrackActive.java
@@ -29,7 +29,7 @@ public abstract class DatasetGraphTrackActive extends DatasetGraphWrapper
     protected DatasetGraphTrackActive() { super(null) ; }
 
     /** Check the transaction state from the point of view of the caller
-     *  (usuually, for the current thread).
+     *  (usually, for the current thread).
      */
     protected abstract void checkActive() ;
     protected abstract void checkNotActive() ;

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphWrapper.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphWrapper.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphWrapper.java
index d2d1435..3480fd4 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphWrapper.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphWrapper.java
@@ -57,130 +57,142 @@ public class DatasetGraphWrapper implements DatasetGraph, Sync
      */
     protected DatasetGraph get() { return dsg ; }
 
+    /** For operations that only read the DatasetGraph. */ 
+    protected DatasetGraph getR() { return get() ; }
+    
+    /** For operations that write the DatasetGraph. */ 
+    protected DatasetGraph getW() { return get() ; }
+    
+    /** For operations that get a handle on a graph. */
+    protected DatasetGraph getG() { return get() ; }
+    
+    /** For operations that pass on transaction actions. */
+    protected DatasetGraph getT() { return get() ; }
+
     public DatasetGraphWrapper(DatasetGraph dsg) {
         this.dsg = dsg ;
     }
 
     @Override
     public boolean containsGraph(Node graphNode)
-    { return get().containsGraph(graphNode) ; }
+    { return getR().containsGraph(graphNode) ; }
 
     @Override
     public Graph getDefaultGraph()
-    { return get().getDefaultGraph(); }
+    { return getG().getDefaultGraph(); }
 
     @Override
     public Graph getGraph(Node graphNode)
-    { return get().getGraph(graphNode) ; }
+    { return getG().getGraph(graphNode) ; }
 
     @Override
     public void addGraph(Node graphName, Graph graph)
-    { get().addGraph(graphName, graph) ; }
+    { getW().addGraph(graphName, graph) ; }
 
     @Override
     public void removeGraph(Node graphName)
-    { get().removeGraph(graphName) ; }
+    { getW().removeGraph(graphName) ; }
 
     @Override
     public void setDefaultGraph(Graph g)
-    { get().setDefaultGraph(g) ; }
+    { getW().setDefaultGraph(g) ; }
 
     @Override
     public Lock getLock()
-    { return get().getLock() ; }
+    { return getR().getLock() ; }
 
     @Override
     public Iterator<Node> listGraphNodes()
-    { return get().listGraphNodes() ; }
+    { return getR().listGraphNodes() ; }
 
     @Override
     public void add(Quad quad)
-    { get().add(quad) ; }
+    { getW().add(quad) ; }
 
     @Override
     public void delete(Quad quad)
-    { get().delete(quad) ; }
+    { getW().delete(quad) ; }
 
     @Override
     public void add(Node g, Node s, Node p, Node o)
-    { get().add(g, s, p, o) ; }
+    { getW().add(g, s, p, o) ; }
 
     @Override
     public void delete(Node g, Node s, Node p, Node o)
-    { get().delete(g, s, p, o) ; }
+    { getW().delete(g, s, p, o) ; }
     
     @Override
     public void deleteAny(Node g, Node s, Node p, Node o)
-    { get().deleteAny(g, s, p, o) ; }
+    { getW().deleteAny(g, s, p, o) ; }
 
     @Override
     public void clear()
-    { get().clear() ; }
+    { getW().clear() ; }
     
     @Override
     public boolean isEmpty()
-    { return get().isEmpty() ; }
+    { return getR().isEmpty() ; }
     
     @Override
     public Iterator<Quad> find()
-    { return get().find() ; }
+    { return getR().find() ; }
 
     @Override
     public Iterator<Quad> find(Quad quad)
-    { return get().find(quad) ; }
+    { return getR().find(quad) ; }
 
     @Override
     public Iterator<Quad> find(Node g, Node s, Node p, Node o)
-    { return get().find(g, s, p, o) ; }
+    { return getR().find(g, s, p, o) ; }
 
     @Override
     public Iterator<Quad> findNG(Node g, Node s, Node p, Node o)
-    { return get().findNG(g, s, p, o) ; }
+    { return getR().findNG(g, s, p, o) ; }
 
     @Override
     public boolean contains(Quad quad)
-    { return get().contains(quad) ; }
+    { return getR().contains(quad) ; }
 
     @Override
     public boolean contains(Node g, Node s, Node p, Node o)
-    { return get().contains(g, s, p, o) ; }
+    { return getR().contains(g, s, p, o) ; }
 
     @Override
     public Context getContext()
-    { return get().getContext() ; }
+    { return getR().getContext() ; }
 
     @Override
     public long size()
-    { return get().size() ; }
+    { return getR().size() ; }
 
     @Override
     public void close()
-    { get().close() ; }
+    { getW().close() ; }
     
     @Override
-    public String toString() { return get().toString() ; }
+    public String toString() { return getR().toString() ; }
 
     @Override
     public void sync() {
         // Pass down sync.
-        SystemARQ.sync(get()) ; 
+        SystemARQ.sync(getW()) ; 
     }
 
     @Override
     public void begin(ReadWrite readWrite) 
-    { get().begin(readWrite) ; }
+    { getT().begin(readWrite) ; }
 
     @Override
     public void commit() 
-    { get().commit() ; }
+    { getT().commit() ; }
 
     @Override
     public void abort() 
-    { get().abort() ; }
+    { getT().abort() ; }
 
     @Override
     public void end()
-    { get().end() ; }
+    { getT().end() ; }
 
     @Override
     public boolean isInTransaction() 
@@ -188,12 +200,12 @@ public class DatasetGraphWrapper implements DatasetGraph, Sync
 
     @Override
     public boolean supportsTransactions() {
-        return get().supportsTransactions() ;
+        return getT().supportsTransactions() ;
     }
 
     @Override
     public boolean supportsTransactionAbort() {
-        return get().supportsTransactionAbort() ;
+        return getT().supportsTransactionAbort() ;
     }
     
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalLock.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalLock.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalLock.java
index e65199b..dde8478 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalLock.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalLock.java
@@ -81,11 +81,6 @@ public class TransactionalLock implements Transactional {
         this.lock = lock ;
     }
 
-    /** Transactional MRSW */
-    private TransactionalLock() {
-        this(new LockMRSW()) ;
-    }
-
     @Override
     public void begin(ReadWrite readWrite) {
         if ( isInTransaction() )

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java
index 0c32872..02d83ac 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateOperations.java
@@ -113,13 +113,13 @@ public class TestUpdateOperations extends BaseTest
             @Override
             public void add(Quad quad) { 
                 counterIns.incrementAndGet() ;
-                get().add(quad) ;
+                super.add(quad) ;
             }
 
             @Override
             public void delete(Quad quad) {
                 counterDel.incrementAndGet() ;
-                get().delete(quad) ; 
+                super.delete(quad) ; 
             }
         } ;
         

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-spatial/src/main/java/org/apache/jena/query/spatial/DatasetGraphSpatial.java
----------------------------------------------------------------------
diff --git a/jena-spatial/src/main/java/org/apache/jena/query/spatial/DatasetGraphSpatial.java b/jena-spatial/src/main/java/org/apache/jena/query/spatial/DatasetGraphSpatial.java
index e32a672..e15f563 100644
--- a/jena-spatial/src/main/java/org/apache/jena/query/spatial/DatasetGraphSpatial.java
+++ b/jena-spatial/src/main/java/org/apache/jena/query/spatial/DatasetGraphSpatial.java
@@ -59,7 +59,7 @@ public class DatasetGraphSpatial extends DatasetGraphMonitor implements Transact
     @Override
     public void begin(ReadWrite readWrite)
     {
-        get().begin(readWrite) ;
+        super.begin(readWrite) ;
         //textIndex.begin(readWrite) ;
         if ( readWrite == ReadWrite.WRITE )
         {
@@ -82,10 +82,10 @@ public class DatasetGraphSpatial extends DatasetGraphMonitor implements Transact
             }
             needFinish = false ;
             //spatialIndex.commit() ;
-            get().commit() ;
+            super.commit() ;
         } catch (Throwable ex) { 
             log.warn("Exception in commit: "+ex.getMessage(), ex) ;
-            get().abort() ; 
+            super.abort() ; 
         }
     }
 
@@ -96,14 +96,14 @@ public class DatasetGraphSpatial extends DatasetGraphMonitor implements Transact
             if ( needFinish )
                 spatialIndex.abortIndexing() ;
             //spatialIndex.abort() ;
-            get().abort() ;
+            super.abort() ;
         } catch (Throwable ex) { log.warn("Exception in abort: "+ex.getMessage(), ex) ; }
     }
 
     @Override
     public boolean isInTransaction()
     {
-        return get().isInTransaction() ;
+        return super.isInTransaction() ;
     }
 
     @Override
@@ -111,13 +111,13 @@ public class DatasetGraphSpatial extends DatasetGraphMonitor implements Transact
     {
         try {
             //spatialIndex.end() ;
-            get().end() ;
+            super.end() ;
         } catch (Throwable ex) { log.warn("Exception in end: "+ex.getMessage(), ex) ; }
     }
     
     @Override
     public boolean supportsTransactions() {
-        return get().supportsTransactions() ;
+        return super.supportsTransactions() ;
     }
     
     /** Declare whether {@link #abort} is supported.
@@ -125,7 +125,7 @@ public class DatasetGraphSpatial extends DatasetGraphMonitor implements Transact
      */
     @Override
     public boolean supportsTransactionAbort() {
-        return get().supportsTransactionAbort() ;
+        return super.supportsTransactionAbort() ;
     }
 }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTxn.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTxn.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTxn.java
index e17e155..98d9ec2 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTxn.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTxn.java
@@ -25,7 +25,7 @@ import org.apache.jena.tdb.store.DatasetGraphTDB;
 /**
  * A DatasetGraph that is a single transaction.
  * It does not support transactions.
- * It is the DatasetGraph apsect of a Transaction (single use).
+ * It is the DatasetGraph aspect of a Transaction (single use).
  */
 public class DatasetGraphTxn extends DatasetGraphWrapper {
     

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
index b0b656f..76262b0 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/Transaction.java
@@ -269,16 +269,14 @@ public class Transaction
     
     public DatasetGraphTxn getActiveDataset()       { return activedsg ; }
 
-    public void setActiveDataset(DatasetGraphTxn activedsg) { 
+    /*package*/ void setActiveDataset(DatasetGraphTxn activedsg) { 
         this.activedsg = activedsg ;
         if ( activedsg.getTransaction() != this )
             Log.warn(this, "Active DSG does not point to this transaction; "+this) ;
     }
 
-    public Journal getJournal()                     { return journal ; }
+    /*package*/ Journal getJournal()                     { return journal ; }
 
-//    public List<Iterator<?>> iterators()            { return Collections.unmodifiableList(iterators) ; }
-//    
     private int count = 0 ;
     private int peekCount = 0 ;
 
@@ -307,11 +305,11 @@ public class Transaction
         return x ;
     }
     
-    public void addComponent(NodeTableTrans ntt) {
+    /*package*/ void addComponent(NodeTableTrans ntt) {
         nodeTableTrans.add(ntt) ;
     }
 
-    public void addComponent(BlockMgrJournal blkMgr) {
+    /*package*/ void addComponent(BlockMgrJournal blkMgr) {
         blkMgrs.add(blkMgr) ;
     }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/37ae374c/jena-text/src/main/java/org/apache/jena/query/text/DatasetGraphText.java
----------------------------------------------------------------------
diff --git a/jena-text/src/main/java/org/apache/jena/query/text/DatasetGraphText.java b/jena-text/src/main/java/org/apache/jena/query/text/DatasetGraphText.java
index 4ed96a0..462a8ec 100644
--- a/jena-text/src/main/java/org/apache/jena/query/text/DatasetGraphText.java
+++ b/jena-text/src/main/java/org/apache/jena/query/text/DatasetGraphText.java
@@ -101,7 +101,7 @@ public class DatasetGraphText extends DatasetGraphMonitor implements Transaction
     @Override
     public void begin(ReadWrite readWrite) {
         readWriteMode.set(readWrite);
-        get().begin(readWrite) ;
+        super.begin(readWrite) ;
         super.getMonitor().start() ;
     }
     
@@ -111,7 +111,7 @@ public class DatasetGraphText extends DatasetGraphMonitor implements Transaction
     @Override
     public void abort() {
         // Roll back all both objects, discarding any exceptions that occur
-        try { get().abort(); } catch (Throwable t) { log.warn("Exception in abort: " + t.getMessage(), t); }
+        try { super.abort(); } catch (Throwable t) { log.warn("Exception in abort: " + t.getMessage(), t); }
         try { textIndex.rollback(); } catch (Throwable t) { log.warn("Exception in abort: " + t.getMessage(), t); }
         readWriteMode.set(null) ;
         super.getMonitor().finish() ;
@@ -146,7 +146,7 @@ public class DatasetGraphText extends DatasetGraphMonitor implements Transaction
         
         // Phase 2
         try {
-            get().commit();
+            super.commit();
             if (readWriteMode.get() == ReadWrite.WRITE) {
                 textIndex.commit();
             }
@@ -177,7 +177,7 @@ public class DatasetGraphText extends DatasetGraphMonitor implements Transaction
         }
         
         try {
-            get().end() ;
+            super.end() ;
         }
         catch (Throwable t) {
             log.warn("Exception in end: " + t.getMessage(), t) ;
@@ -189,7 +189,7 @@ public class DatasetGraphText extends DatasetGraphMonitor implements Transaction
     
     @Override
     public boolean supportsTransactions() {
-        return get().supportsTransactions() ;
+        return super.supportsTransactions() ;
     }
     
     /** Declare whether {@link #abort} is supported.
@@ -197,7 +197,7 @@ public class DatasetGraphText extends DatasetGraphMonitor implements Transaction
      */
     @Override
     public boolean supportsTransactionAbort() {
-        return get().supportsTransactionAbort() ;
+        return super.supportsTransactionAbort() ;
     }
     
     @Override


[07/11] jena git commit: JENA-1123: Settable promotion mode (development).

Posted by an...@apache.org.
JENA-1123: Settable promotion mode (development).

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

Branch: refs/heads/master
Commit: 19ad899bbe490ecafbba8a5956ceaaa65945770a
Parents: a22323c
Author: Andy Seaborne <an...@apache.org>
Authored: Thu Aug 11 12:41:23 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../apache/jena/tdb/transaction/DatasetGraphTransaction.java    | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/19ad899b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
index 7f3af90..0c8a8f7 100644
--- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
+++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetGraphTransaction.java
@@ -86,7 +86,8 @@ import org.apache.jena.tdb.store.GraphTxnTDB ;
         return sConn.getBaseDataset() ;
     }
 
-    /*private*/public/*for development*/ static boolean promotion = false ; 
+    /*private*/public/*for development*/ static boolean promotion               = false ; 
+    /*private*/public/*for development*/ static boolean readCommittedPromotion   = true ;
     
     @Override public DatasetGraph getW() {
         if ( isInTransaction() ) {
@@ -94,7 +95,7 @@ import org.apache.jena.tdb.store.GraphTxnTDB ;
                 DatasetGraphTxn dsgTxn = txn.get() ;
                 if ( dsgTxn.getTransaction().isRead() ) {
                     TransactionManager txnMgr = dsgTxn.getTransaction().getTxnMgr() ;
-                    DatasetGraphTxn dsgTxn2 = txnMgr.promote(dsgTxn, true) ;
+                    DatasetGraphTxn dsgTxn2 = txnMgr.promote(dsgTxn, readCommittedPromotion) ;
                     txn.set(dsgTxn2); 
                 }
             }


[09/11] jena git commit: Tests for active writer when promote happens

Posted by an...@apache.org.
Tests for active writer when promote happens


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

Branch: refs/heads/master
Commit: f972dde69beccefad2e01cf97cc7708917a309ab
Parents: f0d389d
Author: Andy Seaborne <an...@apache.org>
Authored: Sun Aug 14 20:54:52 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sun Aug 14 20:54:52 2016 +0100

----------------------------------------------------------------------
 .../jena/tdb/transaction/TestTransPromote.java  | 99 +++++++++++++++++++-
 1 file changed, 96 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/f972dde6/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 2ae1ad1..43bc02a 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
@@ -21,10 +21,11 @@ package org.apache.jena.tdb.transaction ;
 import static org.junit.Assert.assertEquals ;
 import static org.junit.Assert.fail ;
 
-import java.util.concurrent.Semaphore ;
+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 ;
@@ -301,9 +302,10 @@ public class TestTransPromote {
     
     // Test whether an active writer causes a snapshot isolation
     // promotion to fail like it should.
-    // No equivalent read commiter version - it would block. 
+    // The promtion is on the test's thread.
+    // No equivalent "read commited" version - it would block. 
     @Test(expected=TDBTransactionException.class)
-    public void promote_clash_1() { 
+    public void promote_active_writer_0() { 
         DatasetGraphTransaction.readCommittedPromotion = false ;
         DatasetGraph dsg = create() ;
         Semaphore sema1 = new Semaphore(0) ;
@@ -326,7 +328,98 @@ public class TestTransPromote {
         // If snapshot, this will cause an exception due to the active writer.
         dsg.add(q1) ;
         fail("Should not be here") ;
+        sema2.release(1);
         dsg.commit() ;
         dsg.end() ;
     }
+    
+    @Test(expected=TDBTransactionException.class)
+    public void promote_active_writer_1() throws InterruptedException, ExecutionException {
+        // Active writer commits -> no promotion.
+        promote_active_writer(true) ;
+    }
+    
+    // Current implementation in TDB - the active writer causes "no promotion" even though it will abort.   
+    @Test(expected=TDBTransactionException.class)
+    public void promote_active_writer_2() throws InterruptedException, ExecutionException {
+        // Active writer aborts -> promotion possible (but not ipleemtned that way).
+        promote_active_writer(false) ;
+    }
+    private void promote_active_writer(boolean activeWriterCommit) {
+        ExecutorService executor = Executors.newFixedThreadPool(2) ;
+        try {
+            promote_clash_active_writer(executor, false) ;
+        } 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) ; }
+    }
 }


[05/11] jena git commit: JENA-1123: Tests for transaction promotion in TDB.

Posted by an...@apache.org.
JENA-1123: Tests for transaction promotion in TDB.

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

Branch: refs/heads/master
Commit: f376803841e81f70a546226a09b37c57598bda91
Parents: 19ad899
Author: Andy Seaborne <an...@apache.org>
Authored: Thu Aug 11 12:41:49 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../jena/tdb/transaction/TS_TransactionTDB.java |   1 +
 .../jena/tdb/transaction/TestTransPromote.java  | 187 +++++++++++++++++++
 2 files changed, 188 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/f3768038/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 4fd3510..61fc96e 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,6 +41,7 @@ import org.junit.runners.Suite ;
     , TestTransactionUnionGraph.class
     , TestMiscTDB.class
     , TestTDBInternal.class
+    , TestTransPromote.class
 })
 public class TS_TransactionTDB
 {

http://git-wip-us.apache.org/repos/asf/jena/blob/f3768038/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
new file mode 100644
index 0000000..e51cc29
--- /dev/null
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransPromote.java
@@ -0,0 +1,187 @@
+/*
+ * 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.* ;
+
+import java.util.concurrent.Semaphore ;
+import java.util.concurrent.atomic.AtomicInteger ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+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.ThreadTxn ;
+import org.apache.jena.system.Txn ;
+import org.apache.jena.tdb.TDBFactory ;
+import org.apache.jena.tdb.sys.SystemTDB ;
+import org.apache.jena.tdb.transaction.DatasetGraphTransaction ;
+import org.apache.log4j.Level ;
+import org.apache.log4j.Logger ;
+import org.junit.AfterClass ;
+import org.junit.BeforeClass ;
+import org.junit.Test ;
+
+/** 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
+    //    promotiion is implicit whe a write happens.  
+    
+    
+    
+    // See beforeClass / afterClass.
+    
+    private static Logger logger = Logger.getLogger(SystemTDB.errlog.getName()) ;
+    private static Level  level ;
+    static boolean oldPromotion ;
+    
+    @BeforeClass static public void beforeClass() {
+        oldPromotion = DatasetGraphTransaction.promotion ;
+        DatasetGraphTransaction.promotion = true ;
+        level  = logger.getLevel() ;
+        //logger.setLevel(Level.ERROR) ;
+    }
+    
+    @AfterClass static public void afterClass() {
+        // Restore logging setting.
+        logger.setLevel(level); 
+        DatasetGraphTransaction.promotion = oldPromotion ;
+    }
+    
+    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) ;
+    }
+    
+    @Test public void promote_01() {
+        DatasetGraph dsg = create() ;
+        dsg.begin(ReadWrite.READ); 
+        dsg.add(q1) ;
+        dsg.commit();
+        dsg.end() ;
+    }
+    
+    @Test public void promote_02() {
+        DatasetGraph dsg = create() ;
+        dsg.begin(ReadWrite.READ); 
+        dsg.add(q1) ;
+        dsg.add(q2) ;
+        dsg.commit();
+        dsg.end() ;
+        assertCount(2, dsg) ;
+    }
+
+    // Causes the warning.
+    @Test public void promote_03() {
+        DatasetGraph dsg = create() ;
+        dsg.begin(ReadWrite.READ); 
+        dsg.add(q1) ;
+        
+        // bad - forced abort.
+        // Causes a WARN.
+        logger.setLevel(Level.ERROR) ;
+        dsg.end() ;
+        logger.setLevel(level)  ;
+        
+        assertCount(0, dsg) ;
+    }
+    
+    @Test public void promote_04() {
+        DatasetGraph dsg = create() ;
+        AtomicInteger a = new AtomicInteger(0) ;
+        
+        Semaphore sema = new Semaphore(0) ;
+        Thread t = new Thread(()->{
+            sema.release();
+            Txn.execWrite(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_05() {
+        DatasetGraph dsg = create() ;
+        // Start long running reader.
+        ThreadTxn 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_06() {
+        promoteRC(true) ;
+    }
+        
+    @Test(expected=TDBTransactionException.class)
+    public void promote_07() {
+        promoteRC(false) ;
+    }
+     
+    private void promoteRC(boolean allowReadCommitted) {
+        DatasetGraphTransaction.readCommittedPromotion = allowReadCommitted ;    
+        DatasetGraph dsg = create() ;
+
+        ThreadTxn tt = ThreadTxn.threadTxnWrite(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) ;
+        assertTrue(dsg.contains(q3)) ;
+        dsg.commit();
+        dsg.end() ;
+    }
+
+}


[03/11] jena git commit: Fix up testAPI1() to test by value, not identity

Posted by an...@apache.org.
Fix up testAPI1() to test by value, not identity


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

Branch: refs/heads/master
Commit: af5c29278b1ce801ce4c26a9d18e58433fbbbce0
Parents: f376803
Author: Andy Seaborne <an...@apache.org>
Authored: Thu Aug 11 13:11:16 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Aug 13 15:08:01 2016 +0100

----------------------------------------------------------------------
 .../org/apache/jena/sparql/api/TestAPI.java     | 23 ++++++++++++++------
 1 file changed, 16 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/af5c2927/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java b/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
index 9d387fc..c25a28f 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
@@ -19,6 +19,7 @@
 package org.apache.jena.sparql.api;
 
 import java.util.Iterator;
+import java.util.Set ;
 
 import org.apache.jena.atlas.iterator.Iter ;
 import org.apache.jena.atlas.junit.BaseTest;
@@ -95,13 +96,18 @@ public class TestAPI extends BaseTest
         }
     }
 
-    // This test is slightly dubious. It is testing that the model for the
-    // resource in the result is the same object as the model supplied ot the
-    // query.
-    //
-    // It happens to be true for DatasetImpl and the default model but that's
-    // about it. It is not part of the contract of query/datasets.
+    // The original test (see commented out "assertSame) is test is now bogus.
+    // DatasetImpl no longer caches the default model as that caused problems.
     //
+    // This is testing that the model for the resource in the result is the
+    // same object as the model supplied to the query.
+    // "Same" here means "same contents" includign blank nodes.
+    // 
+    // it used to be that this tested whether they were the same object. 
+    // That is dubious and no longer true even for DatasetImpl (teh default mode
+    // is not cached but recreated on demand so theer are no problems with
+    // transaction boundaries).    
+    // 
     // Left as an active test so the assumption is tested (it has been true for
     // many years). 
     //
@@ -115,7 +121,10 @@ public class TestAPI extends BaseTest
             assertTrue("No results", rs.hasNext()) ;
             QuerySolution qs = rs.nextSolution() ;
             Resource qr = qs.getResource("s") ;
-            assertSame("Not the same model as queried", qr.getModel(), m) ;
+            //assertSame("Not the same model as queried", qr.getModel(), m) ;
+            Set<Statement> s1 = qr.getModel().listStatements().toSet() ;
+            Set<Statement> s2 = m.listStatements().toSet() ;
+            assertEquals(s1,s2) ;
         }
     }