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

com.bigdata.journal.AbstractLocalTransactionManager Maven / Gradle / Ivy

package com.bigdata.journal;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;

import com.bigdata.counters.CounterSet;
import com.bigdata.counters.Instrument;
import com.bigdata.resources.StoreManager;
import com.bigdata.service.IBigdataFederation;
import com.bigdata.service.IDataService;
import com.bigdata.service.ITxState;

/**
 * Manages the client side of a transaction either for a standalone
 * {@link Journal} or for an {@link IDataService} in an
 * {@link IBigdataFederation}.
 * 
 * @author Bryan Thompson
 */
abstract public class AbstractLocalTransactionManager implements
        ILocalTransactionManager {

    /**
     * Logger.
     */
	private static final Logger log = Logger
			.getLogger(AbstractLocalTransactionManager.class);

    public AbstractLocalTransactionManager() {

    }

    /*
     * ILocalTransactionManager
     */

    /**
     * A hash map containing all active transactions. A transaction that is
     * preparing will remain in this collection until it has either successfully
     * prepared or aborted.
     * 
     * TODO Configure the initial capacity and concurrency. For example, this
     * should be sized to the #of client connections for both the
     * initialCapacity and the concurrency level.
     */
    final private ConcurrentHashMap activeTx = new ConcurrentHashMap();

    @Override
    public ITxState[] getActiveTx() {
       
      return activeTx.values().toArray(new ITxState[] {});
       
    }
    
    /**
     * Notify the journal that a new transaction is being activated (starting on
     * the journal).
     * 
     * @param localState
     *            The transaction.
     * 
     * @throws IllegalStateException
     */
    public void activateTx(final Tx localState) throws IllegalStateException {

        if (localState == null)
            throw new IllegalArgumentException();

        localState.lock.lock();

        try {

            if (activeTx
                    .putIfAbsent(localState.getStartTimestamp(), localState) != null) {

                throw new IllegalStateException("Already in local table: tx="
                        + localState);

            }

        } finally {

            localState.lock.unlock();

        }

    }

    /**
     * Removes the transaction from the local tables.
     * 
     * @param localState
     *            The transaction.
     */
    protected void deactivateTx(final Tx localState)
            throws IllegalStateException {

        if (localState == null)
            throw new IllegalArgumentException();

        localState.lock.lock();

        try {

            if (!localState.isReadOnly() && !localState.isComplete())
                throw new IllegalStateException("Not complete: "+localState);

            // release any local resources.
            localState.releaseResources();

            if (activeTx.remove(localState.getStartTimestamp()) == null) {

                throw new IllegalStateException("Not in local tables: tx="
                        + localState);

            }
            
        } finally {

            localState.lock.unlock();
            
        }

    }

    /**
     * Return the local state for a transaction.
     * 
     * @param tx
     *            The transaction identifier.
     * 
     * @return The local state for the identified transaction -or-
     *         null if the start time is not mapped to either an
     *         active or prepared transaction.
     */
    public Tx getTx(final long tx) {

        return activeTx.get(tx);

    }

    public boolean isOpen() {
        
        return open;
        
    }
    
    private volatile boolean open = true;
    
    synchronized public void shutdown() {
        
        if(!open) return;
        
        open = false;
        
    }

    synchronized public void shutdownNow() {

        // Note: currently a NOP.
        
        if(!open) return;
        
        open = false;
        
    }

    /**
     * Delay between attempts reach the remote service (ms).
     */
    final long delay = 10L;

	/**
	 * #of attempts to reach the remote service.
	 * 

* Note: delay*maxtries == 1000ms of trying before we give up, plus however * long we are willing to wait for service discovery if the problem is * locating the {@link ITransactionService}. *

* If this is not enough, then consider adding an optional parameter giving * the time the caller will wait and letting the {@link StoreManager} wait * longer during startup to discover the timestamp service. */ final int maxtries = 100; /** * Note: The reason for all this retry logic is to work around race * conditions during service startup (and possibly during service failover) * when the {@link ITimestampService} has not been discovered yet. */ public long nextTimestamp() { final long begin = System.currentTimeMillis(); IOException cause = null; int ntries; for (ntries = 1; ntries <= maxtries; ntries++) { try { final ITransactionService transactionService = getTransactionService(); if (transactionService == null) { log.warn("Service not discovered yet?"); try { Thread.sleep(delay/* ms */); continue; } catch (InterruptedException e2) { throw new RuntimeException( "Interrupted awaiting timestamp service discovery: " + e2); } } return transactionService.nextTimestamp(); } catch (IOException e) { log.warn("Problem with timestamp service? : ntries=" + ntries + ", " + e, e); cause = e; } } final long elapsed = System.currentTimeMillis() - begin; final String msg = "Could not get timestamp after " + ntries + " tries and " + elapsed + "ms"; log.error(msg, cause); throw new RuntimeException(msg, cause); } public void notifyCommit(final long commitTime) { final long begin = System.currentTimeMillis(); IOException cause = null; int ntries; for (ntries = 1; ntries <= maxtries; ntries++) { try { final ITransactionService transactionService = getTransactionService(); if (transactionService == null) { log.warn("Service not discovered?"); try { Thread.sleep(delay/* ms */); } catch (InterruptedException e2) { throw new RuntimeException( "Interrupted awaiting timestamp service discovery: " + e2); } continue; } transactionService.notifyCommit(commitTime); return; } catch (IOException e) { log.warn("Problem with timestamp service? : ntries=" + ntries + ", " + e, e); cause = e; } } final long elapsed = System.currentTimeMillis() - begin; final String msg = "Could not notify timestamp service after " + ntries + " tries and " + elapsed + "ms"; log.error(msg, cause); throw new RuntimeException(msg, cause); } /** * Return interesting statistics about the transaction manager. */ public CounterSet getCounters() { final CounterSet countersRoot = new CounterSet(); countersRoot.addCounter("#active", new Instrument() { protected void sample() { setValue(activeTx.size()); } }); return countersRoot; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy