TransactionHelper.java :  » GWT » jstm4gwt » jstm4gwt » core » Java Open Source

Java Open Source » GWT » jstm4gwt 
jstm4gwt » jstm4gwt » core » TransactionHelper.java
/**
 * JSTM (http://xstm.net)
 * Distributed under the Apache License Version 2.0
 * Copyright  xstm.net
 */

package jstm4gwt.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import jstm4gwt.misc.ConcurrentHashMap;
import jstm4gwt.misc.AtomicInteger;

import com.google.gwt.user.client.rpc.AsyncCallback;
import jstm4gwt.misc.Debug;
import jstm4gwt.misc.GWTAdapter;
import jstm4gwt.misc.Log;

final class TransactionHelper {

    public static boolean ValidateOnce = true;

    public static boolean ValidateOnceFailed;

    public static boolean AbortRandom, AbortAlways;
    
    public static final AtomicInteger ActiveVisitors = new AtomicInteger();

    private final TransactionManager _manager;

    private final ConcurrentHashMap<Thread, Thread> _allowedThreads = new ConcurrentHashMap<Thread, Thread>();

    private final HashMap<TransactionCommit, ArrayList<Object>> _watchers;

    private final ConcurrentHashMap<Transaction, ConcurrentHashMap<TransactionCommit, TransactionCommit>> _validated;

    public TransactionHelper(TransactionManager manager) {
        if (!Debug.ENABLED)
            throw new IllegalStateException();

        _manager = manager;
        _watchers = new HashMap<TransactionCommit, ArrayList<Object>>();
        _validated = new ConcurrentHashMap<Transaction, ConcurrentHashMap<TransactionCommit, TransactionCommit>>();
    }

    public boolean idle() {
        synchronized (_watchers) {
            if (_watchers.size() != 1)
                return false;

            Debug.assertion(_manager.getSnapshot().getCommits().length == 1);
            TransactionCommit last = _manager.getSnapshot().getLast();
            Debug.assertion(_watchers.containsKey(last));
        }

        if (_validated.size() > 0)
            return false;

        return true;
    }

    public static TransactionCommit[] insertCommit(TransactionCommit[] commits, TransactionCommit commit, int index) {
        TransactionCommit[] newCommits = new TransactionCommit[commits.length + 1];

        // Copy commits already acknowledged

        GWTAdapter.copy(commits, 0, newCommits, 0, index);

        // Insert new commit after last acknowledged one

        newCommits[index] = commit;

        // Copy remaining with offset 1

        int length = commits.length - index;

        if (length > 0) { // Only if there is an interceptor
            if (Debug.ENABLED)
                Debug.assertion(length == newCommits.length - (index + 1));

            GWTAdapter.copy(commits, index, newCommits, index + 1, length);

            if (Debug.ENABLED) {
                Debug.assertion(newCommits[newCommits.length - 1] != null);
                Debug.assertion(newCommits[newCommits.length - 1] == commits[commits.length - 1]);
            }
        }

        // Search nulls to assert indexes, races etc...

        if (Debug.ENABLED)
            Debug.assertion(!Arrays.asList(newCommits).contains(null));

        return newCommits;
    }

    public static TransactionEntry[][] insertDelta(TransactionEntry[][] deltas, TransactionEntry[] delta, int index) {
        TransactionEntry[][] newDeltas = new TransactionEntry[deltas.length + 1][];

        // Copy commits already acknowledged

        GWTAdapter.copy(deltas, 0, newDeltas, 0, index);

        // Insert new commit after last acknowledged one

        newDeltas[index] = delta;

        // Copy remaining with offset 1

        int length = deltas.length - index;

        if (length > 0) { // Only if there is an interceptor
            if (Debug.ENABLED)
                Debug.assertion(length == newDeltas.length - (index + 1));

            GWTAdapter.copy(deltas, index, newDeltas, index + 1, length);

            if (Debug.ENABLED) {
                Debug.assertion(newDeltas[newDeltas.length - 1] != null);
                Debug.assertion(newDeltas[newDeltas.length - 1] == deltas[deltas.length - 1]);
            }
        }

        // Search nulls to assert indexes, races etc...

        if (Debug.ENABLED) {
            Debug.assertion(newDeltas[TransactionManager.OBJECTS_VERSIONS_INDEX] == TransactionManager.OBJECTS_DELTA);
            Debug.assertion(!Arrays.asList(newDeltas).contains(null));
        }

        return newDeltas;
    }

    public static TransactionCommit[] moveCommit(TransactionCommit[] commits, int index, int newIndex) {
        TransactionCommit[] newCommits;

        if (newIndex == index)
            newCommits = commits;
        else if (newIndex < index) {
            newCommits = new TransactionCommit[commits.length];
            GWTAdapter.copy(commits, 0, newCommits, 0, newIndex);
            newCommits[newIndex] = commits[index];
            GWTAdapter.copy(commits, newIndex, newCommits, newIndex + 1, index - newIndex);
            GWTAdapter.copy(commits, index + 1, newCommits, index + 1, commits.length - 1 - index);
        } else
            throw new UnsupportedOperationException();

        // Search nulls to assert indexes, races etc...

        if (Debug.ENABLED)
            Debug.assertion(!Arrays.asList(newCommits).contains(null));

        return newCommits;
    }

    public static TransactionEntry[][] moveDelta(TransactionEntry[][] deltas, int index, int newIndex) {
        TransactionEntry[][] newDeltas;

        if (newIndex == index)
            newDeltas = deltas;
        else if (newIndex < index) {
            newDeltas = new TransactionEntry[deltas.length][];
            GWTAdapter.copy(deltas, 0, newDeltas, 0, newIndex);
            newDeltas[newIndex] = deltas[index];
            GWTAdapter.copy(deltas, newIndex, newDeltas, newIndex + 1, index - newIndex);
            GWTAdapter.copy(deltas, index + 1, newDeltas, index + 1, deltas.length - 1 - index);
        } else
            throw new UnsupportedOperationException();

        // Search nulls to assert indexes, races etc...

        if (Debug.ENABLED) {
            Debug.assertion(newDeltas[TransactionManager.OBJECTS_VERSIONS_INDEX] == TransactionManager.OBJECTS_DELTA);
            Debug.assertion(!Arrays.asList(newDeltas).contains(null));
        }

        return newDeltas;
    }

    public static TransactionCommit[] removeCommit(TransactionCommit[] commits, int index) {
        TransactionCommit[] newCommits = new TransactionCommit[commits.length - 1];
        GWTAdapter.copy(commits, 0, newCommits, 0, index);

        int remaining = commits.length - 1 - index;

        if (remaining > 0)
            GWTAdapter.copy(commits, index + 1, newCommits, index, remaining);

        // Search nulls to assert indexes, races etc...

        if (Debug.ENABLED)
            Debug.assertion(!Arrays.asList(newCommits).contains(null));

        return newCommits;
    }

    public static TransactionEntry[][] removeDelta(TransactionEntry[][] deltas, int index) {
        TransactionEntry[][] newDeltas = new TransactionEntry[deltas.length - 1][];
        GWTAdapter.copy(deltas, 0, newDeltas, 0, index);

        int remaining = deltas.length - 1 - index;

        if (remaining > 0)
            GWTAdapter.copy(deltas, index + 1, newDeltas, index, remaining);

        // Search nulls to assert indexes, races etc...

        if (Debug.ENABLED)
            Debug.assertion(!Arrays.asList(newDeltas).contains(null));

        return newDeltas;
    }

    /**
     * TODO: hash or sort?
     */
    public static int getIndex(Snapshot snapshot, TransactionCommit commit) {
        for (int i = 0; i < snapshot.getCommits().length; i++)
            if (snapshot.getCommits()[i] == commit)
                return i;

        throw new IllegalStateException();
    }

    public static boolean valid(Transaction transaction, Snapshot snapshot, int lastValidated) {
        int minInclusive = lastValidated + 1;
        int maxInclusive = snapshot.getLastAcknowledgedIndex();

        for (int index = minInclusive; index <= maxInclusive; index++) {
            // Check we do not validate twice against the same commit

            if (Debug.ENABLED) {
                for (Transaction current : Site.getLocal().getManager().getHelper()._validated.keySet()) {
                    TransactionCommit.Status aborted = TransactionCommit.Status.ABORTED;
                    Debug.assertion(current.getCommit().getStatus() != aborted);
                }

                ConcurrentHashMap<TransactionCommit, TransactionCommit> commits = Site.getLocal().getManager().getHelper()._validated.get(transaction);

                if (commits == null) {
                    commits = new ConcurrentHashMap<TransactionCommit, TransactionCommit>();
                    Debug.assertion(Site.getLocal().getManager().getHelper()._validated.put(transaction, commits) == null);
                }

                TransactionCommit commit = snapshot.getCommits()[index];

                if (commits.put(commit, commit) != null)
                    ValidateOnceFailed = true;
            }

            // Validate

            if (!valid(transaction, snapshot.getDeltas()[index]))
                return false;
        }

        return true;
    }

    public void removeValidated(Transaction transaction) {
        _validated.remove(transaction);
    }

    public static boolean valid(Transaction transaction, TransactionEntry[] writes) {
        TransactionEntry[] reads = transaction.getDelta();

        if (reads != null) {
            for (int i = 0; i < reads.length; i++) {
                for (TransactionEntry entry = reads[i]; entry != null; entry = entry.getNext()) {
                    TObject object = entry.getKey();
                    TObject.Version write = TransactionCommit.get(writes, object);

                    if (write != null) {
                        if (write.invalidates(entry.getValue(), transaction))
                            return false;
                    }
                }
            }
        }

        return true;
    }

    //

    public void allowThread() {
        Thread thread = Thread.currentThread();
        _allowedThreads.put(thread, thread);
    }

    public void assertThreadIsAllowed() {
        if (!Debug.THREADS)
            throw new IllegalStateException();

        boolean ok = false;

        Thread currentThread = Thread.currentThread();

        for (Thread thread : _allowedThreads.keySet()) {
            if (thread == currentThread)
                ok = true;

            if (false)
                _allowedThreads.remove(thread);
        }

        Debug.assertion(ok);
    }

    //

    public void addWatcher(TransactionCommit commit, Object watcher, int previousCount, int newCount, String reason) {
        if (!Debug.ENABLED)
            throw new IllegalStateException();

        if (Debug.STM) {
            String change = previousCount + " -> " + newCount;
            Log.write("+ on commit " + commit + " " + change + " (" + reason + " by " + watcher + ")");
        }

        synchronized (_watchers) {
            ArrayList<Object> forCommit = _watchers.get(commit);

            if (forCommit == null) {
                forCommit = new ArrayList<Object>();
                Object previous = _watchers.put(commit, forCommit);
                Debug.assertion(previous == null);
            }

            forCommit.add(watcher);
        }
    }

    public void removeWatcher(TransactionCommit commit, Object watcher, int previousCount, int newCount, String reason) {
        if (!Debug.ENABLED)
            throw new IllegalStateException();

        if (Debug.STM) {
            String change = previousCount + " -> " + newCount;
            Log.write("- on commit " + commit + " " + change + " (" + reason + " by " + watcher + ")");
        }

        synchronized (_watchers) {
            ArrayList<Object> transactions = _watchers.get(commit);
            boolean removed = transactions.remove(watcher);
            Debug.assertion(removed);

            if (transactions.size() == 0)
                _watchers.remove(commit);
        }
    }

    public List<Object> getWatchers(TransactionCommit commit) {
        if (!Debug.ENABLED)
            throw new IllegalStateException();

        List<Object> list = new ArrayList<Object>();

        synchronized (_watchers) {
            ArrayList<Object> forCommit = _watchers.get(commit);

            if (forCommit != null)
                list.addAll(forCommit);
        }

        return list;
    }

    //

    public static final class RunTransactedCallback implements AsyncCallback<Void> {

        private final jstm4gwt.misc.Runnable _runnable;

        private final AsyncCallback<Void> _callback;

        public RunTransactedCallback(jstm4gwt.misc.Runnable runnable, AsyncCallback<Void> callback) {
            _runnable = runnable;
            _callback = callback;
        }

        public void onSuccess(Void result) {
            if (_callback != null)
                _callback.onSuccess(result);
        }

        public void onFailure(Throwable t) {
            Site.getLocal().runTransacted(_runnable, _callback);
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.