<commit_before>/*
 * 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.dboe.storage.system;

import java.util.Objects;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.jena.dboe.transaction.txn.TransactionException;
import org.apache.jena.dboe.transaction.txn.TransactionalSystemControl;
import org.apache.jena.query.ReadWrite;
import org.apache.jena.query.TxnType;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.DatasetGraphWrapper;
import org.apache.jena.sparql.util.Context;

/**
 * DatasetGraph wrapper controls entry and exit of transactions.
 * <ul>
 * <li>Exclusive access (no transactions active)
 * <li>Read only database - No possible writers (write and promotable transactions)
 * </ul>
 */

public class DatasetGraphTxnCtl extends DatasetGraphWrapper implements TransactionalSystemControl {

    // ---- Controls

    // Multiple state X or single state Y.
    // Do not confuse with read/write transactions. We need a "one exclusive, or many
    // other" lock which happens to be called {@code ReadWriteLock}.

    // All transactions need "read" state X through out their lifetime.
    // The "write" state Y is used for exclusive mode.
    private ReadWriteLock exclusivitylock = new ReentrantReadWriteLock();

    // Lock to guarantee only readers are present.
    // Writers and promote transaction need to take a lock on entry.
    // This is not reentrant.
    private ReadWriteLock writeableDatabase = new ReentrantReadWriteLock();

    // Better Lock naming?
    //  MultipleOrSingle (MOS) == MRSW
    //  MultipleAndSingle (MAS) == MR+SW

    public DatasetGraphTxnCtl(DatasetGraph dsg) {
        super(dsg);
    }

    public DatasetGraphTxnCtl(DatasetGraph dsg, Context context) {
        super(dsg, context);
    }

    @Override
    public void begin(TxnType txnType) {
        Objects.nonNull(txnType);
        checkNotActive();
        enterTransaction(txnType, true);
        super.begin(txnType);
    }

    final
    protected void checkNotActive() {
        if ( isInTransaction() )
            throw new TransactionException(label("Currently in an active transaction"));
    }

    private String label(String msg) {
        // Optional labelling
        return msg;
    }

    final
    protected void checkActive() {
        // Check no transaction on this thread.
        if ( ! isInTransaction() )
            throw new TransactionException(label("Not in an active transaction"));
    }

    @Override
    public void begin(ReadWrite readWrite) {
        Objects.nonNull(readWrite);
        begin(TxnType.convert(readWrite));
    }

    /*
     * Admission policy.
     * - exclusive mode (no transactions running)
     * - possibleWriters
     */
    private void enterTransaction(TxnType txnType, boolean canBlock) {
        boolean canBlockWriters = canBlock; // false => "bounce writers mode"

        boolean bExclusive = tryNonExclusiveMode(canBlock);
        if ( !bExclusive )
            throw new TransactionException("Can't start transaction at the moment.");

        // Readers never block.
        // Writers admitted one at a time (provided by TransactionCoordinator presently)
        // Promotes are readers until they promote.
        switch(txnType) {
            case READ :
                break;
            case READ_COMMITTED_PROMOTE :
            case READ_PROMOTE :
            case WRITE : {
                startPossibleWriter();
                break;
            }
        }
    }

    private void exitTransaction(TxnType txnType) {
        switch(txnType) {
            case READ :
                break;
            case READ_COMMITTED_PROMOTE :
            case READ_PROMOTE :
            case WRITE : {
                finishPossibleWriter();
                break;
            }
        }
    }

    @Override
    public void commit() {
        TxnType txnType = transactionType();
        super.commit();
        exitTransaction(txnType);
    }

    @Override
    public void abort() {
        TxnType txnType = transactionType();
        super.abort();
        exitTransaction(txnType);
    }

    @Override
    public void end() {
        TxnType txnType = transactionType();
        super.end();
        if ( isInTransaction() )
            exitTransaction(txnType);
    }

    /**<commit_msg>GH-1499: Release non-exclusive mode at the end of transaction.<commit_after>/*
 * 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.dboe.storage.system;

import java.util.Objects;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.jena.dboe.transaction.txn.TransactionException;
import org.apache.jena.dboe.transaction.txn.TransactionalSystemControl;
import org.apache.jena.query.ReadWrite;
import org.apache.jena.query.TxnType;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.DatasetGraphWrapper;
import org.apache.jena.sparql.util.Context;

/**
 * DatasetGraph wrapper controls entry and exit of transactions.
 * <ul>
 * <li>Exclusive access (no transactions active)
 * <li>Read only database - No possible writers (write and promotable transactions)
 * </ul>
 */

public class DatasetGraphTxnCtl extends DatasetGraphWrapper implements TransactionalSystemControl {

    // ---- Controls

    // Multiple state X or single state Y.
    // Do not confuse with read/write transactions. We need a "one exclusive, or many
    // other" lock which happens to be called {@code ReadWriteLock}.

    // All transactions need "read" state X through out their lifetime.
    // The "write" state Y is used for exclusive mode.
    private ReadWriteLock exclusivitylock = new ReentrantReadWriteLock();

    // Lock to guarantee only readers are present.
    // Writers and promote transaction need to take a lock on entry.
    // This is not reentrant.
    private ReadWriteLock writeableDatabase = new ReentrantReadWriteLock();

    // Better Lock naming?
    //  MultipleOrSingle (MOS) == MRSW
    //  MultipleAndSingle (MAS) == MR+SW

    public DatasetGraphTxnCtl(DatasetGraph dsg) {
        super(dsg);
    }

    public DatasetGraphTxnCtl(DatasetGraph dsg, Context context) {
        super(dsg, context);
    }

    @Override
    public void begin(TxnType txnType) {
        Objects.nonNull(txnType);
        checkNotActive();
        enterTransaction(txnType, true);
        super.begin(txnType);
    }

    final
    protected void checkNotActive() {
        if ( isInTransaction() )
            throw new TransactionException(label("Currently in an active transaction"));
    }

    private String label(String msg) {
        // Optional labelling
        return msg;
    }

    final
    protected void checkActive() {
        // Check no transaction on this thread.
        if ( ! isInTransaction() )
            throw new TransactionException(label("Not in an active transaction"));
    }

    @Override
    public void begin(ReadWrite readWrite) {
        Objects.nonNull(readWrite);
        begin(TxnType.convert(readWrite));
    }

    /*
     * Admission policy.
     * - exclusive mode (no transactions running)
     * - possibleWriters
     */
    private void enterTransaction(TxnType txnType, boolean canBlock) {
        boolean canBlockWriters = canBlock; // false => "bounce writers mode"

        boolean bExclusive = tryNonExclusiveMode(canBlock);
        if ( !bExclusive )
            throw new TransactionException("Can't start transaction at the moment.");

        // Readers never block.
        // Writers admitted one at a time (provided by TransactionCoordinator presently)
        // Promotes are readers until they promote.
        switch(txnType) {
            case READ :
                break;
            case READ_COMMITTED_PROMOTE :
            case READ_PROMOTE :
            case WRITE : {
                startPossibleWriter();
                break;
            }
        }
    }

    private void exitTransaction(TxnType txnType) {
        switch(txnType) {
            case READ :
                break;
            case READ_COMMITTED_PROMOTE :
            case READ_PROMOTE :
            case WRITE : {
                finishPossibleWriter();
                break;
            }
        }
        finishNonExclusiveMode();
    }

    @Override
    public void commit() {
        TxnType txnType = transactionType();
        super.commit();
        exitTransaction(txnType);
    }

    @Override
    public void abort() {
        TxnType txnType = transactionType();
        super.abort();
        exitTransaction(txnType);
    }

    @Override
    public void end() {
        TxnType txnType = transactionType();
        super.end();
        if ( isInTransaction() )
            exitTransaction(txnType);
    }

    /**
{'fraction_non_alphanumeric': 0.08372584831298664, 'fraction_numerical': 0.0011535134095933864, 'mean_word_length': 2.5231967490687435, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6725821', 'n_tokens_mistral': 2845, 'n_tokens_neox': 2733, 'n_words': 879}