All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jena.tdb.transaction.DatasetGraphTransaction Maven / Gradle / Ivy

Go to download

TDB is a storage subsystem for Jena and ARQ, it is a native triple store providing persistent storage of triples/quads.

There is a newer version: 4.10.0
Show newest version
/*
 * 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 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.
 * 
 * {@link DatasetGraphTxn} holds the {@link Transaction} object.
 *
 * This is analogous to a "connection" in JDBC. 
 * It is a holder of a {@link StoreConnection} combined with the machinary from
 * {@link DatasetGraphTrackActive}.  
 * 
 * Not considered to be in the public API.
 */

 public class DatasetGraphTransaction extends DatasetGraphTrackActive implements Sync {
    /*
     * Initially, the app can use this DatasetGraph non-transactionally. But as
     * soon as it starts a transaction, the dataset can only be used inside
     * transactions.
     * 
     * There are two per-thread state variables: txn: ThreadLocalTxn -- the
     * transactional , one time use dataset isInTransactionB: ThreadLocalBoolean
     * -- flags true between begin and commit/abort, and end for read
     * transactions.
     */

    // Transaction per thread per DatasetGraphTransaction object.
    private ThreadLocal txn           = withInitial(() -> null);
    private ThreadLocal         inTransaction = withInitial(() -> false);

    private final StoreConnection        sConn;
    private boolean                      isClosed      = false;

    public DatasetGraphTransaction(Location location) {
        sConn = StoreConnection.make(location) ;
    }

    public Location getLocation() {
        return sConn.getLocation() ;
    }

    // getCurrentTxnDSG
    public DatasetGraphTDB getDatasetGraphToQuery() {
        checkNotClosed() ;
        return get() ;
    }

    /** Access the base storage - use with care */
    public DatasetGraphTDB getBaseDatasetGraph() {
        checkNotClosed() ;
        return sConn.getBaseDataset() ;
    }

    /*private*/public/*for development*/ static boolean promotion               = false ; 
    /*private*/public/*for development*/ static boolean readCommittedPromotion   = true ;
    
    @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, readCommittedPromotion) ;
                    txn.set(dsgTxn2); 
                }
            }
        }
        return super.getW() ;
    }
    
    /** Get the current DatasetGraphTDB */
    @Override
    public DatasetGraphTDB get() {
        if ( isInTransaction() ) {
            DatasetGraphTxn dsgTxn = txn.get() ;
            if ( dsgTxn == null )
                throw new TDBTransactionException("In a transaction but no transactional DatasetGraph") ;
            return dsgTxn.getView() ;
        }

        if ( sConn.haveUsedInTransaction() )
            throw new TDBTransactionException("Not in a transaction") ;

        // Never used in a transaction - return underlying database for old
        // style (non-transactional) usage.
        return sConn.getBaseDataset() ;
    }

    @Override
    protected void checkActive() {
        checkNotClosed() ;
        if ( !isInTransaction() )
            throw new JenaTransactionException("Not in a transaction (" + getLocation() + ")") ;
    }

    @Override
    protected void checkNotActive() {
        checkNotClosed() ;
        if ( sConn.haveUsedInTransaction() && isInTransaction() )
            throw new JenaTransactionException("Currently in a transaction (" + getLocation() + ")") ;
    }

    protected void checkNotClosed() {
        if ( isClosed )
            throw new JenaTransactionException("Already closed") ;
    }

    @Override
    public boolean isInTransaction() {
        checkNotClosed() ;
        return inTransaction.get() ;
    }

    public boolean isClosed() {
        return isClosed ;
    }

    public void syncIfNotTransactional() {
        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) {
        checkNotClosed() ;
        DatasetGraphTxn dsgTxn = sConn.begin(readWrite) ;
        txn.set(dsgTxn) ;
        inTransaction.set(true) ;
    }

    @Override
    protected void _commit() {
        checkNotClosed() ;
        txn.get().commit() ;
        inTransaction.set(false) ;
    }

    @Override
    protected void _abort() {
        checkNotClosed() ;
        txn.get().abort() ;
        inTransaction.set(false) ;
    }

    @Override
    protected void _end() {
        checkNotClosed() ;
        DatasetGraphTxn dsg = txn.get() ;
        // It's null if end() already called.
        if ( dsg == null ) {
            TDB.logInfo.warn("Transaction already ended") ;
            return ;
        }
        try {
            // begin(W)..end() throws an exception.
            txn.get().end() ;
        } finally {
            // May already be false due to .commit/.abort.
            inTransaction.set(false) ;
            txn.set(null) ;
        }
    }

    @Override
    public boolean supportsTransactions()       { return true ; }
    
    @Override
    public boolean supportsTransactionAbort()   { return true ; }
    
    @Override
    public String toString() {
        try {
            if ( isInTransaction() )
                // Risky ...
                return get().toString() ;
            // Hence ...
            return getBaseDatasetGraph().toString() ;
        }
        catch (Throwable th) {
            return "DatasetGraphTransaction" ;
        }
    }

    @Override
    protected void _close() {
        if ( isClosed )
            return ;
        
        if ( !sConn.haveUsedInTransaction() ) {
            synchronized(this) {
                if ( isClosed ) return ;
                isClosed = true ;
                if ( ! sConn.isValid() ) {
                    // There may be another DatasetGraphTransaction using this location
                    // and that DatasetGraphTransaction has been closed, invalidating
                    // the StoreConnection.
                    return ;
                }
                DatasetGraphTDB dsg = sConn.getBaseDataset() ;
                dsg.sync() ;
                dsg.close() ;
                StoreConnection.release(getLocation()) ;
                return ;
            }
        }

        if ( isInTransaction() ) {
            TDB.logInfo.warn("Attempt to close a DatasetGraphTransaction while a transaction is active - ignored close (" + getLocation() + ")") ;
            return ;
        }
        txn.remove() ;
        inTransaction.remove() ;
        isClosed = true ;
    }

    @Override
    public Context getContext() {
        // Not the transactional dataset.
        return getBaseDatasetGraph().getContext() ;
    }

    public StoreConnection getStoreConnection() {
        return sConn ;
    }

    @Override
    public void sync() {
        if ( !sConn.haveUsedInTransaction() && get() != null )
            get().sync() ;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy