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/07/12 18:16:28 UTC

[1/6] jena git commit: JENA-1090 : Txn - a java8-centric transaction API

Repository: jena
Updated Branches:
  refs/heads/master 3bbe2d8d7 -> e42090549


JENA-1090 : Txn - a java8-centric transaction API


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

Branch: refs/heads/master
Commit: 952aebd0ac8f2d5d590811f0ac97d3c17c9bea5a
Parents: 1accb0e
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Jul 9 22:40:03 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Jul 9 22:40:03 2016 +0100

----------------------------------------------------------------------
 .../java/org/apache/jena/system/ThreadTxn.java  | 148 ++++++++++++
 .../main/java/org/apache/jena/system/Txn.java   | 112 +++++++++
 .../java/org/apache/jena/system/TxnCounter.java | 240 +++++++++++++++++++
 .../org/apache/jena/sparql/ARQTestSuite.java    |   2 +
 .../apache/jena/system/ExceptionFromTest.java   |  21 ++
 .../java/org/apache/jena/system/TS_System.java  |  32 +++
 .../org/apache/jena/system/TestCounter.java     | 145 +++++++++++
 .../java/org/apache/jena/system/TestTxn.java    | 238 ++++++++++++++++++
 .../apache/jena/system/TestTxnLifecycle.java    | 167 +++++++++++++
 .../org/apache/jena/system/TestTxnThread.java   |  92 +++++++
 10 files changed, 1197 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java b/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
new file mode 100644
index 0000000..ada55b5
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
@@ -0,0 +1,148 @@
+/*
+ * 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.system;
+
+import java.util.Objects ;
+import java.util.concurrent.Executor ;
+import java.util.concurrent.Executors ;
+import java.util.concurrent.Semaphore ;
+import java.util.concurrent.atomic.AtomicReference ;
+
+import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.sparql.core.Transactional ;
+
+/**
+ * An action that will happen on a different thread later when {@link #run} is
+ * called. A thread is created and the transaction started during a call to the
+ * creation operations {@link #threadTxnRead} or {@link #threadTxnWrite}.
+ * The associated Runnable is called and the transaction completed when
+ * {@link #run} is called. Being on a thread, the state of the world the
+ * forked transaction sees is outside the creating thread which may itself be in a
+ * transaction. Warning: creating a write transaction inside a write transaction
+ * will cause deadlock.
+ */ 
+public class ThreadTxn {
+    // ---- Thread
+
+    /** Create a thread-backed delayed READ transaction action. 
+     * Call {@link ThreadTxn#run} to perform the read transaction.
+     */
+    public static ThreadTxn threadTxnRead(Transactional trans, Runnable action) {
+        return ThreadTxn.create(trans, ReadWrite.READ, action, false) ;
+    }
+
+    /** Create a thread-backed delayed WRITE  action.
+     * Call {@link ThreadTxn#run} to perform the write transaction.
+     * (If called from inside a write transaction on the {@code trans},
+     * this will deadlock.)
+     */
+    public static ThreadTxn threadTxnWrite(Transactional trans, Runnable action) {
+        return ThreadTxn.create(trans, ReadWrite.WRITE, action, true) ;
+    }
+   
+    /** Create a thread-backed delayed WRITE-abort action (mainly for testing). */
+    public static ThreadTxn threadTxnWriteAbort(Transactional trans, Runnable action) {
+        return ThreadTxn.create(trans, ReadWrite.WRITE, action, false) ;
+    }
+    
+    private final Semaphore semaStart ;
+    private final Semaphore semaFinish ;
+    private final AtomicReference<RuntimeException> thrownRuntimeException = new AtomicReference<>(null) ; 
+    private final AtomicReference<Error> thrownError = new AtomicReference<>(null) ;
+    private final Runnable action ;
+    
+    private ThreadTxn(Runnable action) {
+        this.action = action ;
+        this.semaStart = new Semaphore(0, true) ;
+        this.semaFinish = new Semaphore(0, true) ;
+    }
+    
+    /**
+     * Perform the Runnable, reporting any 
+     * {@link java.lang.RuntimeException} or {@link java.lang.Error}
+     */
+    public void run() { 
+        semaStart.release();
+        semaFinish.acquireUninterruptibly() ;
+        if ( thrownError.get() != null )
+            throw thrownError.get() ;
+        if ( thrownRuntimeException.get() != null )
+            throw thrownRuntimeException.get() ;
+    }
+    
+    // Called on the async thread.
+    private void trigger() {
+        try { action.run(); }
+        catch (Error error) { thrownError.set(error) ; throw error  ;}
+        catch (RuntimeException ex) { thrownRuntimeException.set(ex) ; throw ex ; }
+    }
+    
+    // System-shared executor better.
+    private static Executor executor = Executors.newCachedThreadPool() ;
+    
+    /*package*/ static ThreadTxn create(Transactional trans, ReadWrite mode, Runnable action, boolean isCommit) {
+        Objects.requireNonNull(trans) ;
+        Objects.requireNonNull(mode) ;
+        Objects.requireNonNull(action) ;
+        
+        ThreadTxn threadAction = new ThreadTxn(action) ;
+        // Startup semaphore so that the thread has started by the
+        // time we exit this setup function. 
+        Semaphore semaStartup = new Semaphore(0, true) ;
+        executor.execute( ()-> {
+            // NB. trans.begin then semaStartup.release() ;
+            // This ensures that the transaction has really started.
+            trans.begin(mode) ;
+            
+            // Signal the creator (see below) that the transaction has started.
+            semaStartup.release() ;
+            
+            // Wait for the signal to run the action.
+            threadAction.semaStart.acquireUninterruptibly();
+            
+            try {
+                // Performane the action, catch and record any RuntimeException or Error. 
+                threadAction.trigger() ;
+                
+                // Finish transaction (if no throwable)
+                if ( mode == ReadWrite.WRITE ) {
+                    if ( isCommit )
+                        trans.commit();
+                    else
+                        trans.abort() ;
+                    trans.end() ;
+                } else {
+                    // Read
+                    if ( isCommit )
+                        trans.commit();
+                    trans.end() ;
+                }
+            } 
+            catch (Throwable ex) { 
+                       // Surpress now it has trigger transaction mechanism in
+                       // the presence of an unchecked exception.
+                       // Passed to the main thread via ThreadTxn
+            }
+            finally { threadAction.semaFinish.release() ; }
+        }) ;
+        // Don't return until the transaction has started.
+        semaStartup.acquireUninterruptibly();
+        return threadAction ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/main/java/org/apache/jena/system/Txn.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/system/Txn.java b/jena-arq/src/main/java/org/apache/jena/system/Txn.java
new file mode 100644
index 0000000..c422fc4
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/system/Txn.java
@@ -0,0 +1,112 @@
+/*
+ * 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.system;
+
+import java.util.function.Supplier ;
+
+import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.sparql.JenaTransactionException ;
+import org.apache.jena.sparql.core.Transactional ;
+
+/** Application utilities for transactions.
+ *  <ul> 
+ *  <li>"Autocommit" provided. 
+ *  <li>Nested transaction are not supported but calling inside an existing transaction, 
+ *      which must be compatible, (i.e. a write needs a WRITE transaction).
+ *      causes the transaction to be used.
+ *  </ul>  
+ */
+
+public class Txn {
+    /** Execute the Runnable in a read transaction. */
+    public static <T extends Transactional> void execRead(T txn, Runnable r) {
+        boolean b = txn.isInTransaction() ;
+        if ( !b )
+            txn.begin(ReadWrite.READ) ;
+        try { r.run() ; }
+        catch (Throwable th) {
+            onThrowable(txn);
+            throw th ;
+        }
+        if ( ! b )
+            txn.end() ;
+    }
+    
+    /** Execute and return a value in a read transaction */
+    public static <T extends Transactional, X> X execReadRtn(T txn, Supplier<X> r) {
+        boolean b = txn.isInTransaction() ;
+        if ( !b )
+            txn.begin(ReadWrite.READ) ;
+        try {
+            X x = r.get() ;
+            if ( !b )
+                txn.end() ;
+            return x ;
+        } catch (Throwable th) {
+            onThrowable(txn);
+            throw th ;
+        }
+    }
+
+    /** Execute the Runnable in a write transaction */
+    public static <T extends Transactional> void execWrite(T txn, Runnable r) {
+        boolean b = txn.isInTransaction() ;
+        if ( !b )
+            txn.begin(ReadWrite.WRITE) ;
+        try { r.run() ; }
+        catch (Throwable th) {
+            onThrowable(txn);
+            throw th ;
+        }
+        if ( !b ) {
+            if ( txn.isInTransaction() )
+                // May have been explicit commit or abort.
+                txn.commit() ;
+            txn.end() ;
+        }
+    }
+
+    /** Execute and return a value in a write transaction. */
+    public static <T extends Transactional, X> X execWriteRtn(Transactional txn, Supplier<X> r) {
+        boolean b = txn.isInTransaction() ;
+        if ( !b )
+            txn.begin(ReadWrite.WRITE) ;
+        X x = null ;
+        try { x = r.get() ; } 
+        catch (Throwable th) {
+            onThrowable(txn);
+            throw th ;
+        }
+        if ( !b ) {
+            if ( txn.isInTransaction() )
+                // May have been explicit commit or abort.
+                txn.commit() ;
+            txn.end() ;
+        }
+        return x ;
+    }
+    
+    // Attempt some kind of cleanup.
+    private static <T extends Transactional> void onThrowable(T txn) {
+        try {
+            txn.abort() ;
+            txn.end() ;
+        } catch (JenaTransactionException ex) { }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/main/java/org/apache/jena/system/TxnCounter.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/system/TxnCounter.java b/jena-arq/src/main/java/org/apache/jena/system/TxnCounter.java
new file mode 100644
index 0000000..1477e6b
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/system/TxnCounter.java
@@ -0,0 +1,240 @@
+/*
+ * 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.system;
+
+import static org.apache.jena.query.ReadWrite.WRITE ;
+
+import java.util.concurrent.Semaphore ;
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.apache.jena.atlas.lib.Lib ;
+import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.sparql.JenaTransactionException ;
+import org.apache.jena.sparql.core.Transactional ;
+
+/** A MR+SW transactional Counter */ 
+public class TxnCounter implements Transactional {
+    
+    // ---- TransactionCoordinator.
+    
+    // Semaphore to implement "Single Active Writer" - independent of readers
+    // This is not reentrant.
+    private Semaphore writersWaiting = new Semaphore(1, true) ;
+    
+    private void releaseWriterLock() {
+        int x = writersWaiting.availablePermits() ;
+        if ( x != 0 )
+            throw new JenaTransactionException("TransactionCoordinator: Probably mismatch of enable/disableWriter calls") ;
+        writersWaiting.release() ;
+    }
+    
+    private boolean acquireWriterLock(boolean canBlock) {
+        if ( ! canBlock )
+            return writersWaiting.tryAcquire() ;
+        try { 
+            writersWaiting.acquire() ; 
+            return true;
+        } catch (InterruptedException e) { throw new JenaTransactionException(e) ; }
+    }
+    // ---- TransactionCoordinator.
+    
+    // Transaction state.
+    static class IntegerState {
+        long txnValue ;
+        public IntegerState(long v) { this.txnValue = v ; }
+    }
+    
+    // Global state - the exterally visible value and the starting point for any
+    // transaction. This is set to a new value when a write trasnaction commits.
+    
+    private final AtomicLong value = new AtomicLong(-1712) ; 
+
+    // ---- Transaction state.
+    
+    // The per-transaction state (inside a transaction). Null outside a transaction
+    // cleared by commit or abort in a write transaction.
+    private ThreadLocal<IntegerState> txnValue = ThreadLocal.withInitial(()->null) ;
+    // The kind of transaction.
+    private ThreadLocal<ReadWrite>    txnMode  = ThreadLocal.withInitial(()->null) ;
+    
+    // Syncrhonization for making changes.  
+    private Object txnLifecycleLock   = new Object() ; 
+    
+    public TxnCounter(long x) {
+        value.set(x) ;
+    }
+    
+    @Override
+    public void begin(ReadWrite readWrite) {
+        begin(readWrite, true) ;
+    }
+    
+    public void begin(ReadWrite readWrite, boolean canBlock) {
+        // Ensure a single writer. 
+        // (Readers never block at this point.)
+        if ( readWrite == WRITE ) {
+            // Writers take a WRITE permit from the semaphore to ensure there
+            // is at most one active writer, else the attempt to start the
+            // transaction blocks.
+            // Released by in commit/abort.
+            acquireWriterLock(canBlock) ;
+        }
+        // at this point, 
+        // One writer or one of many readers. 
+        
+        synchronized(txnLifecycleLock) {
+            if ( txnMode.get() != null )
+                throw new JenaTransactionException("Already in a transaction") ;
+            IntegerState state = new IntegerState(value.get()) ;
+            txnValue.set(state) ;
+            txnMode.set(readWrite);
+        }
+    }
+
+    @Override
+    public void commit() {
+        checkTxn(); 
+        if ( isWriteTxn() ) {
+            // Set global.
+            value.set(getDataState().txnValue) ;
+            txnValue.set(null); 
+            releaseWriterLock();
+        }
+        endOnce() ;
+    }
+
+    @Override
+    public void abort() {
+        checkTxn(); 
+        if ( isWriteTxn() ) {
+            txnValue.set(null); 
+            releaseWriterLock();
+        }
+        endOnce() ;
+    }
+
+    @Override
+    public boolean isInTransaction() {
+        ReadWrite mode = txnMode.get() ;
+        if ( mode == null )
+            // Remove it - avoid holding the memory.
+            txnMode.remove();
+        return mode != null ;
+    }
+
+    @Override
+    public void end() {
+        if ( ! isInTransaction() ) 
+            return ;
+        if ( isWriteTxn() && txnValue.get() != null )
+            throw new JenaTransactionException("No commit or abort before end for a write transaction") ;
+        endOnce() ;
+    }
+
+    private void endOnce() {
+        if ( isActiveTxn() ) {
+            synchronized(txnLifecycleLock) {
+                txnValue.remove();
+                txnMode.remove();
+            }
+        }
+    }
+
+    /** Increment the value inside a write transaction */ 
+    public void inc() {
+        checkWriteTxn() ;
+        IntegerState ts = getDataState() ;
+        ts.txnValue++ ;
+    }
+    
+    /** Decrement the value inside a write transaction */ 
+    public void dec() {
+        checkWriteTxn() ;
+        IntegerState ts = getDataState() ;
+        ts.txnValue-- ;
+    }
+
+    /** Set the value inside a write transaction, return the old value*/ 
+    public long set(long x) {
+        checkWriteTxn() ;
+        IntegerState ts = getDataState() ;
+        long v = ts.txnValue ;
+        ts.txnValue = x ;
+        return v ;
+    }
+    
+
+    /** Return the current value in a transaction. 
+     * Must be inside a transaction. 
+     * @see #get
+     */
+    public long read() {
+        checkTxn();
+        return getDataState().txnValue ;
+    }
+
+    /** Return the current value.
+     * If inside a transaction, return the transaction view of the value.
+     * If not in a transaction return the state value (effectively
+     * a read transaction, optimized by the fact that reading the
+     * {@code TransInteger} state is atomic).
+     */
+    public long get() {
+        if ( isActiveTxn() )
+            return getDataState().txnValue ;
+        else
+            return value.get() ;
+    }
+
+    /** Read the current global state (that is, the last committed value) outside a transaction. */
+    public long value() {
+        return value.get() ;
+    }
+
+    // These two operations not clear the thread local if we are not in a transaction.
+    // This is a potential memory leak.
+    // Use "isInTransaction" to read and clear.
+
+    /** Is this a write transaction? Shoudl be called inside a transaction. */
+    private boolean isWriteTxn() {
+        ReadWrite rw = txnMode.get() ;
+        if ( rw == null )
+            throw new JenaTransactionException(Lib.classShortName(this.getClass())+".isWriteTxn called outside a transaction") ;
+        return txnMode.get() == ReadWrite.WRITE ;
+    }
+
+    private boolean isActiveTxn() {
+        ReadWrite rw = txnMode.get() ;
+        return rw != null ;
+    }
+
+    private IntegerState getDataState() {
+        return txnValue.get() ;
+    }
+
+    private void checkWriteTxn() {
+        if ( ! isWriteTxn() )
+            throw new JenaTransactionException("Not in a write transaction") ;
+    }
+
+    private void checkTxn() {
+        if ( ! isActiveTxn() )
+            throw new JenaTransactionException("Not in a transaction") ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/sparql/ARQTestSuite.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/ARQTestSuite.java b/jena-arq/src/test/java/org/apache/jena/sparql/ARQTestSuite.java
index f40d8eb..23f3e66 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/ARQTestSuite.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/ARQTestSuite.java
@@ -29,6 +29,7 @@ import org.apache.jena.sparql.engine.ref.QueryEngineRef ;
 import org.apache.jena.sparql.expr.E_Function ;
 import org.apache.jena.sparql.expr.NodeValue ;
 import org.apache.jena.system.JenaSystem ;
+import org.apache.jena.system.TS_System ;
 import org.apache.jena.web.TS_Web ;
 
 /**
@@ -60,6 +61,7 @@ public class ARQTestSuite extends TestSuite
         ts.addTest(new JUnit4TestAdapter(TC_Riot.class)) ;
 
         ts.addTest(new JUnit4TestAdapter(TS_Web.class)) ;
+        ts.addTest(new JUnit4TestAdapter(TS_System.class)) ;
         
         // Main ARQ internal test suite.
         ts.addTest(new JUnit4TestAdapter(TC_General.class)) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/system/ExceptionFromTest.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/system/ExceptionFromTest.java b/jena-arq/src/test/java/org/apache/jena/system/ExceptionFromTest.java
new file mode 100644
index 0000000..42efda6
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/ExceptionFromTest.java
@@ -0,0 +1,21 @@
+/*
+ * 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.system;
+
+class ExceptionFromTest extends RuntimeException {}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/system/TS_System.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TS_System.java b/jena-arq/src/test/java/org/apache/jena/system/TS_System.java
new file mode 100644
index 0000000..e8c6f05
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/TS_System.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.system;
+
+import org.junit.runner.RunWith ;
+import org.junit.runners.Suite ;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses( {
+    TestCounter.class
+    , TestTxnLifecycle.class
+    , TestTxn.class
+    , TestTxnThread.class
+})
+    
+public class TS_System {}

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/system/TestCounter.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TestCounter.java b/jena-arq/src/test/java/org/apache/jena/system/TestCounter.java
new file mode 100644
index 0000000..5eb1591
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/TestCounter.java
@@ -0,0 +1,145 @@
+/*
+ * 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.system;
+
+import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.sparql.JenaTransactionException ;
+import org.apache.jena.system.TxnCounter ;
+import org.junit.Test ;
+
+import static org.junit.Assert.* ;
+
+// TestTxn also tests counters.
+public class TestCounter {
+    private TxnCounter counter = new TxnCounter(0) ;
+    
+    @Test
+    public void counter_lifecycle_1() {
+        counter.begin(ReadWrite.WRITE) ;
+        counter.inc() ;
+        counter.commit();
+        counter.end() ;
+    }
+
+    @Test
+    public void counter_lifecycle_2() {
+        counter.begin(ReadWrite.WRITE) ;
+        counter.abort() ;
+        counter.end() ;
+    }
+
+    @Test
+    public void counter_lifecycle_3() {
+        counter.begin(ReadWrite.READ) ;
+        counter.end() ;
+    }
+
+    @Test
+    public void counter_lifecycle_4() {
+        counter.begin(ReadWrite.READ) ;
+        counter.commit() ;
+        counter.end() ;
+    }
+    
+    @Test
+    public void counter_lifecycle_5() {
+        counter.begin(ReadWrite.READ) ;
+        counter.abort() ;
+        counter.end() ;
+    }
+    
+    @Test
+    public void counter_lifecycle_6() {
+        counter.end() ;
+    }
+
+    @Test
+    public void counter_01() {
+        assertEquals(0, counter.get());
+        assertEquals(0, counter.value());
+        
+        counter.begin(ReadWrite.WRITE) ;
+        
+        assertEquals(0, counter.get());
+        assertEquals(0, counter.value());
+        
+        counter.inc() ;
+        long x = counter.get() ;
+        assertEquals(1, counter.get());
+        assertEquals(0, counter.value());
+        
+        counter.commit();
+        assertEquals(1, counter.value());
+        
+        counter.end() ;
+        assertEquals(1, counter.value());
+    }
+
+    @Test
+    public void counter_02() {
+        assertEquals(0, counter.get());
+        assertEquals(0, counter.value());
+        
+        counter.begin(ReadWrite.WRITE) ;
+        
+        assertEquals(0, counter.get());
+        assertEquals(0, counter.value());
+        
+        counter.inc() ;
+        long x = counter.get() ;
+        assertEquals(1, counter.get());
+        assertEquals(0, counter.value());
+        
+        counter.abort();
+        assertEquals(0, counter.value());
+        counter.end() ;
+        assertEquals(0, counter.value());
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void counter_bad_01() {
+        counter.inc() ;
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void counter_bad_02() {
+        counter.begin(ReadWrite.WRITE) ;
+        counter.end() ;
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void counter_bad_03() {
+        counter.begin(ReadWrite.READ) ;
+        counter.inc() ;
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void counter_bad_04() {
+        counter.begin(ReadWrite.READ) ;
+        counter.end() ;
+        counter.commit() ;
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void counter_bad_05() {
+        counter.begin(ReadWrite.WRITE) ;
+        counter.end() ;
+        counter.commit() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/system/TestTxn.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TestTxn.java b/jena-arq/src/test/java/org/apache/jena/system/TestTxn.java
new file mode 100644
index 0000000..d9a9546
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/TestTxn.java
@@ -0,0 +1,238 @@
+/*
+ * 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.system;
+
+import static org.junit.Assert.assertEquals ;
+
+import org.apache.jena.system.Txn ;
+import org.apache.jena.system.TxnCounter ;
+import org.junit.Test ;
+
+public class TestTxn {
+
+    TxnCounter counter = new TxnCounter(0) ; 
+
+    @Test public void txn_basic_01() {
+        long v1 = counter.get() ;
+        assertEquals(0, v1) ;
+        Txn.execRead(counter, () -> {
+            assertEquals(0, counter.get()) ;
+        }) ;
+    }
+
+    @Test public void txn_basic_02() {
+        long x = 
+            Txn.execReadRtn(counter, () -> {
+                assertEquals("In R, value()", 0, counter.value()) ;
+                assertEquals("In R, get()", 0, counter.get()) ;
+                return counter.get() ;
+            }) ;
+        assertEquals("Outside R", 0, x) ;
+    }
+
+    @Test public void txn_basic_03() {
+        Txn.execWrite(counter, counter::inc) ;
+        long x = 
+            Txn.execReadRtn(counter, () -> {
+                assertEquals("In R, value()", 1, counter.value()) ;
+                assertEquals("In R, get()", 1, counter.get()) ;
+                return counter.get() ;
+            }) ;
+        assertEquals("Outside R", 1, x) ;
+    }
+
+    @Test public void txn_basic_05() {
+        long x = 
+            Txn.execWriteRtn(counter, () -> {
+                counter.inc() ;
+                assertEquals("In W, value()", 0, counter.value()) ;
+                assertEquals("In W, get()",1, counter.get()) ;
+                return counter.get() ;
+            }) ;
+        assertEquals("Outside W",1, x) ;
+    }
+
+    @Test public void txn_write_01() {
+        long x = 
+            Txn.execWriteRtn(counter, () -> {
+                counter.inc() ;
+                assertEquals("In W, value()", 0, counter.value()) ;
+                assertEquals("In W, get()",1, counter.get()) ;
+                long z = counter.get() ;
+                counter.commit() ;
+                return z ;
+            }) ;
+        assertEquals("Outside W",1, x) ;
+    }
+
+    @Test public void txn_write_02() {
+        long x = 
+            Txn.execWriteRtn(counter, () -> {
+                counter.inc() ;
+                assertEquals("In W, value()", 0, counter.value()) ;
+                assertEquals("In W, get()",1, counter.get()) ;
+                long z = counter.get() ;
+                counter.abort() ;
+                return z ;
+            }) ;
+        assertEquals("Outside W",1, x) ;
+    }
+    
+    @Test public void txn_write_03() {
+        Txn.execWrite(counter, () -> {
+            counter.inc() ;
+            assertEquals("In W, value()", 0, counter.value()) ;
+            assertEquals("In W, get()",1, counter.get()) ;
+            counter.commit() ;
+        }) ;
+        assertEquals("Outside W",1, counter.value()) ;
+    }
+
+    @Test public void txn_write_04() {
+        Txn.execWrite(counter, () -> {
+            counter.inc() ;
+            assertEquals("In W, value()", 0, counter.value()) ;
+            assertEquals("In W, get()",1, counter.get()) ;
+            counter.abort() ;
+        }) ;
+        assertEquals("Outside W", 0, counter.value()) ;
+    }
+
+    @Test public void txn_rw_1() {
+        assertEquals(0, counter.get()) ;
+        
+        Txn.execWrite(counter, () -> {
+            counter.inc() ;
+            assertEquals("In W, value()", 0, counter.value()) ;
+            assertEquals("In W, get()",1, counter.get()) ;
+        }) ;
+        
+        assertEquals("Direct value()", 1, counter.value()) ;
+        assertEquals("Direct get()", 1, counter.get()) ;
+
+        Txn.execRead(counter, () -> {
+            assertEquals("In R, value()", 1, counter.value()) ;
+            assertEquals("In R, get()", 1, counter.get()) ;
+        }) ;
+    }
+    
+    @Test public void txn_rw_2() {
+        Txn.execRead(counter, () -> {
+            assertEquals("In R, value()", 0, counter.value()) ;
+            assertEquals("In R, get()", 0, counter.get()) ;
+        }) ;
+
+        Txn.execWrite(counter, () -> {
+            counter.inc() ;
+            assertEquals("In W, value()", 0, counter.value()) ;
+            assertEquals("In W, get()",1, counter.get()) ;
+        }) ;
+        
+        assertEquals("Direct value()", 1, counter.get()) ;
+        assertEquals("Direct get()", 1, counter.get()) ;
+
+        Txn.execRead(counter, () -> {
+            assertEquals("In R, value()", 1, counter.value()) ;
+            assertEquals("In R, get()", 1, counter.get()) ;
+        }) ;
+    }
+    
+    @Test public void txn_continue_1() {
+        Txn.execWrite(counter, ()->counter.set(91)) ;
+        
+        Txn.execWrite(counter, ()-> {
+            assertEquals("In txn, value()", 91, counter.value()) ;
+            assertEquals("In txn, read()", 91, counter.read()) ;
+            counter.inc(); 
+            Txn.execWrite(counter, ()->{
+                assertEquals("In txn, value()", 91, counter.value()) ;
+                assertEquals("In txn, get()", 92, counter.read()) ;
+                }) ;
+            });
+        assertEquals(92,counter.value()) ;
+    }
+    
+    @Test public void txn_continue_2() {
+        Txn.execWrite(counter, ()->counter.set(91)) ;
+        
+        Txn.execWrite(counter, ()-> {
+            assertEquals("In txn, value()", 91, counter.value()) ;
+            assertEquals("In txn, read()", 91, counter.read()) ;
+            counter.inc(); 
+            Txn.execWrite(counter, ()->{
+                assertEquals("In txn, value()", 91, counter.value()) ;
+                assertEquals("In txn, get()", 92, counter.read()) ;
+                counter.inc();
+                }) ;
+            assertEquals("In txn, value()", 91, counter.value()) ;
+            assertEquals("In txn, read()", 93, counter.read()) ;
+            counter.inc();
+            });
+        assertEquals(94,counter.value()) ;
+    }
+    
+    @Test(expected=ExceptionFromTest.class)
+    public void txn_exception_01() {
+        Txn.execWrite(counter, counter::inc) ;
+        
+        Txn.execWrite(counter, () -> {
+            counter.inc() ;
+            assertEquals("In W, value()", 1, counter.value()) ;
+            assertEquals("In W, get()",2, counter.get()) ;
+            throw new ExceptionFromTest() ;
+        }) ;
+    }
+    
+    @Test
+    public void txn_exception_02() {
+        Txn.execWrite(counter, ()->counter.set(8)) ;
+    
+        try {
+            Txn.execWrite(counter, () -> {
+                counter.inc();
+                assertEquals("In W, value()", 8, counter.value());
+                assertEquals("In W, get()", 9, counter.get());
+                throw new ExceptionFromTest();
+            });
+        }
+        catch (ExceptionFromTest ex) {}
+        assertEquals("After W/abort, get()", 8, counter.get());
+    }
+
+    @Test
+    public void txn_exception_03() {
+        Txn.execWrite(counter, ()->counter.set(9)) ;
+    
+        try {
+            Txn.execRead(counter, () -> {
+                assertEquals("In W, value()", 9, counter.value());
+                assertEquals("In W, get()", 9, counter.get());
+                throw new ExceptionFromTest();
+            });
+        }
+        catch (ExceptionFromTest ex) {}
+        assertEquals("After W/abort, get()", 9, counter.get());
+    }
+    
+    // Tests for thread transactions.
+
+
+}
+
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/system/TestTxnLifecycle.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TestTxnLifecycle.java b/jena-arq/src/test/java/org/apache/jena/system/TestTxnLifecycle.java
new file mode 100644
index 0000000..3cfa82b
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/TestTxnLifecycle.java
@@ -0,0 +1,167 @@
+/*
+ * 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.system;
+
+import static org.junit.Assert.* ;
+
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.apache.jena.sparql.core.Transactional ;
+import org.apache.jena.sparql.core.TransactionalLock ;
+import org.apache.jena.system.Txn ;
+import org.junit.Test ;
+
+/** Lifecycle tests - apply tests to a provided Transactional
+ *  but modify separate state.   
+ */
+public class TestTxnLifecycle {
+    private AtomicLong counter = new AtomicLong(0) ;
+
+    // Not MR+SW (See TestTxn for fully transactional tests)
+    private Transactional trans = TransactionalLock.createMRSW() ;
+ 
+    @Test public void txn_lifecycle_01() {
+        Txn.execRead(trans, ()->{}) ;
+    }
+    
+    @Test public void txn_lifecycle_02() {
+        Txn.execWrite(trans, ()->{}) ;
+    }
+
+    @Test public void txn_lifecycle_03() {
+        int x = Txn.execReadRtn(trans, ()->4) ;
+        assertEquals(4,x) ;
+    }
+
+    @Test public void txn_lifecycle_04() {
+        int x = Txn.execWriteRtn(trans, ()->5) ;
+        assertEquals(5,x) ;
+    }
+    
+    @Test public void txn_lifecycle_05() {
+        int x = Txn.execWriteRtn(trans, ()-> {
+            // Continues outer transaction.
+            return Txn.execWriteRtn(trans, ()->56) ;
+        });
+        assertEquals(56,x) ;
+    }
+    
+    @Test(expected=ExceptionFromTest.class)
+    public void txn_lifecycle_06() {
+        int x = Txn.execWriteRtn(trans, ()-> {
+            Txn.execWriteRtn(trans, ()-> {throw new ExceptionFromTest() ; }) ;
+            return 45 ;
+        });
+        fail("Should not be here!") ;
+    }
+    
+    @Test public void txn_lifecycle_07() {
+        Txn.execWrite(trans, ()->trans.commit()) ; 
+    }
+    
+    @Test public void txn_lifecycle_08() {
+        Txn.execWrite(trans, ()->trans.abort()) ; 
+    }
+    
+    @Test public void txn_lifecycle_09() {
+        Txn.execRead(trans, ()->trans.commit()) ; 
+    }
+    @Test public void txn_lifecycle_10() {
+        Txn.execRead(trans, ()->trans.abort()) ; 
+    }
+
+    static void async(Runnable runnable) {
+        Thread thread = new Thread(runnable);
+        thread.start(); 
+    }
+    
+    static void debug(String message) {
+        //System.out.println(message) ;
+    }
+    
+    // Tests of isolation. Hard.
+    
+    // Is this a real test?
+//    @Test public void txn_lifecycle_isolation_01() {
+//        Semaphore semaStep = new Semaphore(0) ;
+//        Semaphore sema = new Semaphore(0) ;
+//        
+//        counter.set(15) ;
+//        long x1 = counter.get() ;
+//        
+//        Runnable r = ()->{
+//            Txn.executeWrite(trans, ()->{
+//                debug("Thread 1");
+//                // Start step.
+//                semaStep.release();
+//                
+//                debug("Thread 2");
+//                //Wait for test 
+//                sema.acquireUninterruptibly();
+//                
+//                debug("Thread 3");
+//                // Make a change.
+//                counter.incrementAndGet() ;
+//                
+//                debug("Thread 4");
+//                // End step.
+//                semaStep.release();
+//                
+//                debug("Thread 5");
+//                // End change.
+//                sema.release();
+//                
+//                debug("Thread 6");
+//            });
+//        } ;
+//        
+//        long x2 = counter.get() ;
+//        assertEquals("x2", x1, x2) ;
+//
+//        debug("Main 1");
+//
+//        // Run!
+//        async(r) ; 
+//
+//        debug("Main 2");
+//
+//        // Let thread step
+//        semaStep.acquireUninterruptibly();
+//
+//        debug("Main 3");
+//        // See what the state is (before change)
+//        assertEquals(x1, counter.get()) ;
+//        // Allow change
+//        sema.release();
+//
+//        debug("Main 4");
+//        // Wait for change.
+//        semaStep.acquireUninterruptibly();
+//
+//        debug("Main 5");
+//        // See what the state is (after change)
+//        assertEquals(x1+1,counter.get()) ;
+//        sema.acquireUninterruptibly();
+//
+//        // Final state.
+//        debug("Main 6");
+//        long x3 = counter.get() ;
+//        assertEquals(x1+1, x3) ;
+//    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/952aebd0/jena-arq/src/test/java/org/apache/jena/system/TestTxnThread.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TestTxnThread.java b/jena-arq/src/test/java/org/apache/jena/system/TestTxnThread.java
new file mode 100644
index 0000000..2af8db9
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/TestTxnThread.java
@@ -0,0 +1,92 @@
+/*
+ * 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.system;
+
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.fail;
+
+import org.apache.jena.system.ThreadTxn ;
+import org.apache.jena.system.Txn ;
+import org.apache.jena.system.TxnCounter ;
+import org.junit.Test ;
+
+public class TestTxnThread {
+
+    TxnCounter counter = new TxnCounter(0) ; 
+
+    
+    
+    // Tests for thread transactions.
+    
+    @Test public void txnThread_1() {
+        ThreadTxn t = ThreadTxn.threadTxnRead(counter, ()->{}) ;
+        t.run();
+    }
+    
+    @Test public void txnThread_2() {
+        ThreadTxn t = ThreadTxn.threadTxnWrite(counter, ()-> fail("")) ;
+    }
+
+    @Test(expected=AssertionError.class)
+    public void txnThread_3() {
+        ThreadTxn t = ThreadTxn.threadTxnWrite(counter, ()-> fail("")) ;
+        t.run() ;
+    }
+
+    @Test public void txnThread_10() {
+        long x1 = counter.get() ;  
+        ThreadTxn t = ThreadTxn.threadTxnWrite(counter, ()->{ counter.inc() ;}) ;
+        long x2 = counter.get() ;
+        assertEquals("x2", x1, x2) ;
+        t.run() ;
+        long x3 = counter.get() ;
+        assertEquals("x3", x1+1, x3) ;
+    }
+    
+    @Test public void txnThread_11() {
+        long x1 = counter.get() ;  
+        Txn.execWrite(counter, ()->{
+            counter.inc();
+            // Read the "before" state
+            ThreadTxn t = ThreadTxn.threadTxnRead(counter, ()->{ 
+                long z1 = counter.get() ; 
+                assertEquals("Thread read", x1, z1) ;
+            }) ;
+            counter.inc();
+            t.run(); 
+        }) ;
+        long x2 = counter.get() ;
+        assertEquals("after", x1+2, x2) ;
+    }
+
+    @Test public void txnThread_12() {
+        long x1 = counter.get() ;  
+        ThreadTxn t = ThreadTxn.threadTxnRead(counter, () -> {
+            long z1 = counter.get() ;
+            assertEquals("Thread", x1, z1) ;
+        }) ;
+        Txn.execWrite(counter, ()->counter.inc()) ;
+        t.run() ;
+        long x2 = counter.get() ;
+        assertEquals("after", x1+1, x2) ;
+    }
+
+}
+
+ 
\ No newline at end of file


[5/6] jena git commit: Minor cleanup

Posted by an...@apache.org.
Minor cleanup

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

Branch: refs/heads/master
Commit: 44784c627bb05355f2457cf0ece7dace63920ffe
Parents: 58b6b0e
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Jul 12 17:29:00 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Jul 12 17:29:00 2016 +0100

----------------------------------------------------------------------
 .../tdb/transaction/TestTransactionUnionGraph.java   | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/44784c62/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionUnionGraph.java
----------------------------------------------------------------------
diff --git a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionUnionGraph.java b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionUnionGraph.java
index 8c29f3f..2cbd310 100644
--- a/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionUnionGraph.java
+++ b/jena-tdb/src/test/java/org/apache/jena/tdb/transaction/TestTransactionUnionGraph.java
@@ -18,6 +18,9 @@
 
 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.junit.BaseTest ;
 import org.apache.jena.atlas.lib.StrUtils ;
 import org.apache.jena.query.* ;
@@ -27,20 +30,12 @@ import org.apache.jena.tdb.TDB ;
 import org.apache.jena.tdb.TDBFactory ;
 import org.apache.jena.update.* ;
 import org.junit.* ;
-import static org.apache.jena.query.ReadWrite.* ;
 
-/** Tests of transactions and the TDG union graph */
+/** Tests of transactions and the TDB union graph */
 public class TestTransactionUnionGraph extends BaseTest
 {
     private Dataset ds ;
     
-//    @BeforeClass public static void beforeClass()
-//    { 
-//        ds = TDBFactory.createDataset() ;
-//        ds.asDatasetGraph().add(SSE.parseQuad("(<g> <s> <p> 1)")) ;
-//    }
-//    @AfterClass public static void afterClass() { ds = null ; }
-
     @Before
     public void before()
     {
@@ -48,7 +43,7 @@ public class TestTransactionUnionGraph extends BaseTest
         ds.asDatasetGraph().add(SSE.parseQuad("(<g> <s> <p> 1)")) ;
     }
     
-    @After public void after() {} 
+    @After public void after() { } 
     
     @Test public void uniontxn_global_r()
     {


[3/6] jena git commit: Improve the explanation.

Posted by an...@apache.org.
Improve the explanation.

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

Branch: refs/heads/master
Commit: 7dc5b25ae1855d6becfe1f8720f4bee9f9ace070
Parents: 52ff200
Author: Andy Seaborne <an...@apache.org>
Authored: Sun Jul 10 15:39:44 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sun Jul 10 15:39:44 2016 +0100

----------------------------------------------------------------------
 .../java/org/apache/jena/system/ThreadTxn.java  | 59 ++++++++++----------
 1 file changed, 31 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/7dc5b25a/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java b/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
index ada55b5..06e735e 100644
--- a/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
+++ b/jena-arq/src/main/java/org/apache/jena/system/ThreadTxn.java
@@ -47,7 +47,7 @@ public class ThreadTxn {
         return ThreadTxn.create(trans, ReadWrite.READ, action, false) ;
     }
 
-    /** Create a thread-backed delayed WRITE  action.
+    /** Create a thread-backed delayed WRITE action.
      * Call {@link ThreadTxn#run} to perform the write transaction.
      * (If called from inside a write transaction on the {@code trans},
      * this will deadlock.)
@@ -61,16 +61,16 @@ public class ThreadTxn {
         return ThreadTxn.create(trans, ReadWrite.WRITE, action, false) ;
     }
     
-    private final Semaphore semaStart ;
-    private final Semaphore semaFinish ;
+    private final Semaphore semaStart   = new Semaphore(0, true) ;
+    private final Semaphore semaFinish  = new Semaphore(0, true) ;
+    
+    // Catch the two kinds that do not need a "throws" clause. 
     private final AtomicReference<RuntimeException> thrownRuntimeException = new AtomicReference<>(null) ; 
     private final AtomicReference<Error> thrownError = new AtomicReference<>(null) ;
     private final Runnable action ;
     
     private ThreadTxn(Runnable action) {
         this.action = action ;
-        this.semaStart = new Semaphore(0, true) ;
-        this.semaFinish = new Semaphore(0, true) ;
     }
     
     /**
@@ -78,6 +78,8 @@ public class ThreadTxn {
      * {@link java.lang.RuntimeException} or {@link java.lang.Error}
      */
     public void run() { 
+        // Signal the thread, which is already running and inside
+        // the transaction, can now call the action.
         semaStart.release();
         semaFinish.acquireUninterruptibly() ;
         if ( thrownError.get() != null )
@@ -102,47 +104,48 @@ public class ThreadTxn {
         Objects.requireNonNull(action) ;
         
         ThreadTxn threadAction = new ThreadTxn(action) ;
-        // Startup semaphore so that the thread has started by the
-        // time we exit this setup function. 
-        Semaphore semaStartup = new Semaphore(0, true) ;
+        // Startup semaphore so that the thread has started and entered the
+        // transaction by the time we exit this setup function. 
+        Semaphore semaCreateStart = new Semaphore(0, true) ;
         executor.execute( ()-> {
-            // NB. trans.begin then semaStartup.release() ;
+            // NB. trans.begin then semaCreateStartup.release() ;
             // This ensures that the transaction has really started.
             trans.begin(mode) ;
             
             // Signal the creator (see below) that the transaction has started.
-            semaStartup.release() ;
+            semaCreateStart.release() ;
             
             // Wait for the signal to run the action.
             threadAction.semaStart.acquireUninterruptibly();
             
             try {
-                // Performane the action, catch and record any RuntimeException or Error. 
+                // Perform the action, catching and recording any RuntimeException or Error. 
                 threadAction.trigger() ;
                 
                 // Finish transaction (if no throwable)
-                if ( mode == ReadWrite.WRITE ) {
-                    if ( isCommit )
-                        trans.commit();
-                    else
-                        trans.abort() ;
-                    trans.end() ;
-                } else {
-                    // Read
-                    if ( isCommit )
-                        trans.commit();
-                    trans.end() ;
+                switch (mode) {
+                    case WRITE : {
+                        if ( isCommit )
+                            trans.commit() ;
+                        else
+                            trans.abort() ;
+                        trans.end() ;
+                    }
+                    case READ : {
+                        if ( isCommit )
+                            trans.commit() ;
+                        trans.end() ;
+                    }
                 }
-            } 
-            catch (Throwable ex) { 
-                       // Surpress now it has trigger transaction mechanism in
-                       // the presence of an unchecked exception.
-                       // Passed to the main thread via ThreadTxn
+            }
+            catch (Throwable ex) {
+                // Surpress. trigger() recorded it and it is passed
+                // to the caller in run(). 
             }
             finally { threadAction.semaFinish.release() ; }
         }) ;
         // Don't return until the transaction has started.
-        semaStartup.acquireUninterruptibly();
+        semaCreateStart.acquireUninterruptibly();
         return threadAction ;
     }
 }


[4/6] jena git commit: Deal with a service URL with query string

Posted by an...@apache.org.
Deal with a service URL with query string


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

Branch: refs/heads/master
Commit: 58b6b0e34e02cd204329a6e1377967b6b1b4c326
Parents: 3bbe2d8
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Jul 12 13:33:57 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Jul 12 13:33:57 2016 +0100

----------------------------------------------------------------------
 jena-fuseki2/apache-jena-fuseki/bin/s-delete      | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-get         | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-head        | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-post        | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-put         | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-query       | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-update      | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/s-update-form | 9 ++++++++-
 jena-fuseki2/apache-jena-fuseki/bin/soh           | 9 ++++++++-
 9 files changed, 72 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-delete
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-delete b/jena-fuseki2/apache-jena-fuseki/bin/s-delete
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-delete
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-delete
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-get
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-get b/jena-fuseki2/apache-jena-fuseki/bin/s-get
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-get
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-get
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-head
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-head b/jena-fuseki2/apache-jena-fuseki/bin/s-head
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-head
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-head
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-post
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-post b/jena-fuseki2/apache-jena-fuseki/bin/s-post
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-post
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-post
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-put
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-put b/jena-fuseki2/apache-jena-fuseki/bin/s-put
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-put
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-put
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-query
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-query b/jena-fuseki2/apache-jena-fuseki/bin/s-query
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-query
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-query
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-update
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-update b/jena-fuseki2/apache-jena-fuseki/bin/s-update
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-update
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-update
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/s-update-form
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/s-update-form b/jena-fuseki2/apache-jena-fuseki/bin/s-update-form
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/s-update-form
+++ b/jena-fuseki2/apache-jena-fuseki/bin/s-update-form
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results

http://git-wip-us.apache.org/repos/asf/jena/blob/58b6b0e3/jena-fuseki2/apache-jena-fuseki/bin/soh
----------------------------------------------------------------------
diff --git a/jena-fuseki2/apache-jena-fuseki/bin/soh b/jena-fuseki2/apache-jena-fuseki/bin/soh
index 16cb44c..dcafe62 100755
--- a/jena-fuseki2/apache-jena-fuseki/bin/soh
+++ b/jena-fuseki2/apache-jena-fuseki/bin/soh
@@ -462,7 +462,14 @@ def SPARQL_query_GET(service, query, args2)
   args = { "query" => query }
   args.merge!(args2)
   qs=args.collect { |k,v| "#{k}=#{uri_escape(v)}" }.join('&')
-  action="#{service}?#{qs}"
+
+  if service.include? "?"
+  then
+    action="#{service}&#{qs}"
+  else
+    action="#{service}?#{qs}"
+  end
+
   headers={}
   headers.merge!($headers)
   headers[$hAccept]=$accept_results


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

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

This closes #153.


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

Branch: refs/heads/master
Commit: e420905490cd6c8986b3276f89a372ea330f6448
Parents: 44784c6 7dc5b25
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Jul 12 19:10:20 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Jul 12 19:10:20 2016 +0100

----------------------------------------------------------------------
 .../java/org/apache/jena/system/ThreadTxn.java  | 151 ++++++++++++
 .../main/java/org/apache/jena/system/Txn.java   | 112 +++++++++
 .../java/org/apache/jena/system/TxnCounter.java | 240 +++++++++++++++++++
 .../org/apache/jena/sparql/ARQTestSuite.java    |   2 +
 .../apache/jena/system/ExceptionFromTest.java   |  21 ++
 .../java/org/apache/jena/system/TS_System.java  |  32 +++
 .../org/apache/jena/system/TestCounter.java     | 145 +++++++++++
 .../java/org/apache/jena/system/TestTxn.java    | 238 ++++++++++++++++++
 .../apache/jena/system/TestTxnLifecycle.java    | 167 +++++++++++++
 .../org/apache/jena/system/TestTxnThread.java   |  92 +++++++
 10 files changed, 1200 insertions(+)
----------------------------------------------------------------------



[2/6] jena git commit: Merge branch 'master' of https://github.com/apache/jena into txn

Posted by an...@apache.org.
Merge branch 'master' of https://github.com/apache/jena into txn


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

Branch: refs/heads/master
Commit: 52ff200c2756c9844b4346ffa1bff2a09081b649
Parents: 952aebd 1028413
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Jul 9 22:41:01 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Jul 9 22:41:01 2016 +0100

----------------------------------------------------------------------
 .../apache/jena/sparql/engine/main/VarFinder.java   |  9 +++++++--
 .../java/org/apache/jena/sparql/util/ExprUtils.java |  3 ++-
 .../java/org/apache/jena/atlas/logging/LogCtl.java  | 16 +++++++++++++---
 3 files changed, 22 insertions(+), 6 deletions(-)
----------------------------------------------------------------------