[MOBY-guts] biomoby commit

Paul Gordon gordonp at dev.open-bio.org
Thu Jun 7 23:55:42 UTC 2007


gordonp
Thu Jun  7 19:55:42 EDT 2007
Update of /home/repository/moby/moby-live/Java/src/main/org/biomoby/client
In directory dev.open-bio.org:/tmp/cvs-serv25439/src/main/org/biomoby/client

Modified Files:
	CentralCachedCallsImpl.java 
Log Message:
First stage commit of update: now concurrent requests for the sameCentral call are blocked, excepted for the first one
moby-live/Java/src/main/org/biomoby/client CentralCachedCallsImpl.java,1.1,1.2
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/org/biomoby/client/CentralCachedCallsImpl.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- /home/repository/moby/moby-live/Java/src/main/org/biomoby/client/CentralCachedCallsImpl.java	2006/07/07 04:12:39	1.1
+++ /home/repository/moby/moby-live/Java/src/main/org/biomoby/client/CentralCachedCallsImpl.java	2007/06/07 23:55:42	1.2
@@ -1,13 +1,15 @@
 /**
  * Implements the functionality of caching by reusing identical calls to
  * MOBY central (e.g. asking multiple times what services take a DNA 
- * sequence in the gi namespace).
+ * sequence in the gi namespace).  This is an in-memory cache in CentralImpl, 
+ * but a filesystem cache backs it up here, so calls can be cached between 
+ * JVM instances.
  */
 
 package org.biomoby.client;
 
 import org.biomoby.shared.MobyException;
-import java.util.Properties;
+import java.util.*;
 
 public class CentralCachedCallsImpl extends CentralImpl{
 
@@ -15,6 +17,8 @@
     protected static final long THE_EPOCH = 0;  // don't care when the call is made, it shouldn't affect the onto mapping of calls to IDs
     protected static final Properties PROPERTIES = null; // don't have any properties for the call
 
+    protected Map<String,String> inProgressCalls; //<callKey,threadName> used to synchronize concurrent, redundant calls to Central
+
     /*************************************************************************
      * Default constructor. It connects to a default Moby registry
      * (as defined in {@link #DEFAULT_ENDPOINT}) using a default namespace
@@ -23,6 +27,7 @@
     public CentralCachedCallsImpl()
 	throws MobyException {
 	super (DEFAULT_ENDPOINT, DEFAULT_NAMESPACE);
+	inProgressCalls = new HashMap();
     }
 
     /*************************************************************************
@@ -34,6 +39,7 @@
     public CentralCachedCallsImpl (String endpoint)
 	throws MobyException {
 	super (endpoint, DEFAULT_NAMESPACE);
+	inProgressCalls = new HashMap();
     }
 
     /*************************************************************************
@@ -47,20 +53,59 @@
     public CentralCachedCallsImpl (String endpoint, String namespace)
 	throws MobyException {
 	super (endpoint, namespace);
+	inProgressCalls = new HashMap();
     }
 
+    /**
+     * The implementation of this method is smart enough that if the same call
+     * is made more than once, even concurrently(!), we only go to the server once,
+     * and use a cached value for all other invocations. 
+     */
     protected Object doCall (String method, Object[] parameters)
 	throws MobyException {
 
-	String callKey = createId(method, parameters);
-	if(getCacheMode() && existsInCache(callKey)){
-	    return getContents(callKey);
-	}
+	Object result = null;
 
-	Object result = super.doCall(method, parameters);
-	
+	String callKey = createId(method, parameters);
 	if(getCacheMode()){
-	    setContents(callKey, result);
+
+	    // It's in the cache?
+	    if(existsInCache(callKey)){
+		return getContents(callKey);
+	    }
+
+	    // The same request is already in progress, in another thread?
+	    Object inProgressCall = null;
+	    synchronized(inProgressCalls){
+		String threadName = inProgressCalls.get(callKey);
+		if(threadName == null){
+		    // No one's currently doing this request...claim it for this thread
+		    threadName = Thread.currentThread().getName();
+		    inProgressCalls.put(callKey, threadName);
+		}
+		inProgressCall = threadName;
+	    }
+
+	    // The first thread making a call will block subsequent ones with the same callKey
+	    synchronized(inProgressCall){
+		// Should be true for subsequent calls
+		if(existsInCache(callKey)){
+		    return getContents(callKey);
+		}
+		// Should get here only if I'm the first caller for the callKey,
+		// or subsequent call when previous doCall() for this callKey throws an exception
+		// i.e. setContents() isn't called after doCall()
+		try{
+		    result = super.doCall(method, parameters);
+		    setContents(callKey, result);
+		} finally{
+		    // Remove the blocker, regardless of whether an Exception was thrown or not.
+		    inProgressCalls.remove(callKey);
+		}
+	    }
+	}
+	else{
+	    result = super.doCall(method, parameters);
 	}
 
 	return result;




More information about the MOBY-guts mailing list