diff src/org/dancres/blitz/EntryViewImpl.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/dancres/blitz/EntryViewImpl.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,249 @@
+package org.dancres.blitz;
+
+import java.io.IOException;
+
+import net.jini.core.transaction.Transaction;
+import net.jini.core.transaction.TransactionException;
+import net.jini.core.transaction.UnknownTransactionException;
+
+import org.dancres.blitz.entry.*;
+import org.dancres.blitz.mangler.MangledEntry;
+import org.dancres.blitz.txn.TxnManager;
+import org.dancres.blitz.txn.TxnState;
+import org.dancres.blitz.txnlock.LockMgr;
+import org.dancres.blitz.txnlock.TxnLock;
+import org.dancres.blitz.txnlock.TxnLocks;
+import org.dancres.blitz.notify.EventQueue;
+
+/**
+   <p>This class supports both iteration using the old JavaSpaceAdmin interface
+   and the new JavaSpace05 interface.  The key differences amount to the
+   the number of templates that can be passed and whether or not locks are
+   held on the transaction.</p>
+
+   <p>For JavaSpace05, there are multiple templates and we hold locks on the
+   transaction.</p>
+ */
+class EntryViewImpl implements EntryView {
+    private TxnState theTxn;
+
+    private TransactionException theException;
+    private int theStatus = ACTIVE;
+
+    private static final int ACTIVE = -1;
+    private static final int DECEASED = -2;
+
+    private UIDSet theUIDs;
+
+    private NewView theDynamicView;
+
+    private EntryRx theBuffer;
+
+    private boolean shouldUpdate;
+
+    EntryViewImpl(Transaction aTxn, MangledEntry[] aTemplates,
+                  boolean holdLocks, boolean doUpdate, long aLimit)
+            throws TransactionException, IOException {
+
+        shouldUpdate = doUpdate;
+
+        theTxn = TxnManager.get().resolve(aTxn);
+
+        /*
+          Basic process is to assemble a set of fully matching Entry UID's which we
+          then step through ascertaining whether these UID's are still valid and possibly
+          asserting locks transactionally.
+
+          Full matching is done in each view and the matching tuples are then
+          logged/merged in the UIDSet
+
+          These tuple ids are then scanned through using EntryReposImpl::find to load
+          the entry, verify it's valid etc after which we may or may not maintain a
+          transaction lock (these steps are done in EntryRx).
+         */
+        theUIDs = new UIDSet(aLimit);
+
+        theBuffer = new EntryRx(theTxn, holdLocks);
+        theDynamicView = new NewView(this, aTemplates, theUIDs);
+
+        if (shouldUpdate)
+            EventQueue.get().insert(theDynamicView.getSearchTask());
+
+        /*
+          For each template do a full tree search and assemble all matches
+         */
+        for (int i = 0; i < aTemplates.length; i++) {
+            if (theUIDs.isFull())
+                break;
+
+            DiskView myFixedView = new DiskView(aTemplates[i], theUIDs);
+
+            EntryRepository myRepos =
+                    EntryRepositoryFactory.get().find(aTemplates[i].getType());
+
+            if (myRepos != null) {
+                myRepos.find(aTemplates[i], myFixedView);
+
+                // Try subtypes
+                String[] mySubtypes = myRepos.getSubtypes();
+            
+                for (int j = 0; j < mySubtypes.length; j++) {
+                    myRepos = EntryRepositoryFactory.get().find(mySubtypes[j]);
+
+                    if (myRepos != null) {
+                        myRepos.find(aTemplates[i], myFixedView);
+                    }
+                }
+            }
+        }
+    }
+
+    TxnState getTxn() {
+        return theTxn;
+    }
+    
+    void resolved() {
+        setStatus(DECEASED, 
+                new TransactionException(
+                "Transaction closed with view active"));
+    }
+
+    private void setStatus(int aStatus, TransactionException aTE) {
+        // Make sure we only do this once
+        //
+        synchronized(this) {
+            if (theStatus == DECEASED)
+                return;
+
+            theStatus = aStatus;
+            theException = aTE;
+        }
+
+        if (shouldUpdate)
+            theDynamicView.getSearchTask().taint();
+
+        if (theTxn.isNull()) {
+            try {
+                TxnManager.get().prepareAndCommit(theTxn);
+            } catch (UnknownTransactionException aUTE) {
+                /*
+                  Don't care much...if we got here, we're defining state
+                  and everyone else will fail at the status test above
+                */
+                synchronized(this) {
+                    theException = aUTE;
+                }
+            }
+        }
+    }
+
+    public void close() {
+        setStatus(DECEASED, null);
+    }
+
+    public EntryChit next() throws TransactionException, IOException {
+        synchronized(this) {
+            if (theStatus == DECEASED) {
+                if (theException != null)
+                    throw theException;
+                else
+                    throw new TransactionException("No longer active");
+            }
+        }
+
+        SpaceEntryUID myUID;
+
+        while ((myUID = theUIDs.pop()) != null) {
+            EntryRepository myRepos =
+                EntryRepositoryFactory.get().get(myUID.getType());
+
+            myRepos.find(theBuffer, myUID.getOID(), null);
+
+            MangledEntry myEntry = theBuffer.getEntry();
+
+            if (myEntry != null)
+                return new EntryChit(myEntry, myUID);
+        }
+
+        return null;
+    }
+
+    /**
+       Used to receive the entry requested by id from the EntryRepository
+       It performs the appropriate locking checks and updates the transaction
+       if we're holding locks
+     */
+    private static class EntryRx implements SearchVisitor {
+        private MangledEntry theEntry;
+
+        private TxnState theTxn;
+        private boolean keepLock;
+
+        private TransactionException theFailure;
+
+        EntryRx(TxnState aTxn, boolean holdLock) {
+            theTxn = aTxn;
+            keepLock = holdLock;
+        }
+
+        public int offer(SearchOffer anOffer) {
+            OpInfo myInfo = anOffer.getInfo();
+
+            // Try the lock
+            LockMgr myMgr = TxnLocks.getLockMgr(myInfo.getType());
+            TxnLock myLock = myMgr.getLock(myInfo.getOID());
+            
+            int myResult;
+            
+            synchronized(myLock) {
+                myResult = myLock.acquire(theTxn, TxnLock.READ,
+                                          null, null, false);
+            }
+            
+            if (myResult == TxnLock.SUCCESS) {
+                if (keepLock) {
+                    /*
+                      Need to track the lock under the transaction
+                     */
+                    try {
+                        theTxn.add(new EntryTxnOp(TxnLock.READ, myInfo,
+                                                  myLock));
+                    } catch (TransactionException aTE) {
+                        myLock.release(theTxn, TxnLock.READ);
+                        theFailure = aTE;
+                        return STOP;
+                    }
+                } else {
+                    /*
+                      No need to track this lock, we were just testing so
+                      we can release it now
+                     */
+                    myLock.release(theTxn, TxnLock.READ);
+                }
+                
+                theEntry = anOffer.getEntry();
+            }
+
+            return STOP;
+        }
+        
+        public boolean isDeleter() {
+            return false;
+        }
+
+        MangledEntry getEntry() throws TransactionException {
+            /*
+              If we're running under an external (non-null) transaction
+              we may have failed whilst attempting to lock (we would have
+              failed to record the lock in the transaction).
+             */
+            if (theFailure != null)
+                throw theFailure;
+
+            MangledEntry myResult = theEntry;
+            theEntry = null;
+
+            return myResult;
+        }
+    }
+}
\ No newline at end of file