Author: kwright
Date: Mon Nov 25 14:41:36 2013
New Revision: 1545304

URL: http://svn.apache.org/r1545304
Log:
Revamp ILockManager registration logic to remove requirement for external 
locking during cleanup.

Added:
    
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java
   (with props)
Modified:
    
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentRun.java
    
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentStop.java
    
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/system/ManifoldCF.java
    
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/ILockManager.java
    
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/BaseLockManager.java
    
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/LockManager.java

Modified: 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentRun.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentRun.java?rev=1545304&r1=1545303&r2=1545304&view=diff
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentRun.java
 (original)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentRun.java
 Mon Nov 25 14:41:36 2013
@@ -51,7 +51,7 @@ public class AgentRun extends BaseAgents
     // AgentStop only, and AgentStop will wait until all services become 
inactive before exiting.
     String processID = ManifoldCF.getProcessID();
     ILockManager lockManager = LockManagerFactory.make(tc);
-    lockManager.registerServiceBeginServiceActivity(agentServiceType, 
processID);
+    lockManager.registerServiceBeginServiceActivity(agentServiceType, 
processID, null);
     try
     {
       // Register a shutdown hook to make sure we signal that the main agents 
process is going inactive.

Modified: 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentStop.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentStop.java?rev=1545304&r1=1545303&r2=1545304&view=diff
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentStop.java
 (original)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/AgentStop.java
 Mon Nov 25 14:41:36 2013
@@ -44,17 +44,8 @@ public class AgentStop extends BaseAgent
       while (true)
       {
         // Check to see if services are down yet
-        String[] agents = 
lockManager.getRegisteredServices(AgentRun.agentServiceType);
-        boolean alive = false;
-        for (String agent : agents)
-        {
-          if (lockManager.checkServiceActive(AgentRun.agentServiceType, agent))
-          {
-            alive = true;
-            break;
-          }
-        }
-        if (!alive)
+        int count = lockManager.countActiveServices(AgentRun.agentServiceType);
+        if (count == 0)
           break;
         try
         {

Modified: 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/system/ManifoldCF.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/system/ManifoldCF.java?rev=1545304&r1=1545303&r2=1545304&view=diff
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/system/ManifoldCF.java
 (original)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/agents/src/main/java/org/apache/manifoldcf/agents/system/ManifoldCF.java
 Mon Nov 25 14:41:36 2013
@@ -198,13 +198,6 @@ public class ManifoldCF extends org.apac
     }
   }
 
-  protected final static String agentClassLockPrefix = "_AGENTCLASSLOCK_";
-  
-  protected static String getAgentsClassLockName(String agentClassName)
-  {
-    return agentClassLockPrefix + agentClassName;
-  }
-  
   protected static String getAgentsClassServiceType(String agentClassName)
   {
     return agentServicePrefix + agentClassName;
@@ -241,30 +234,8 @@ public class ManifoldCF extends org.apac
           try
           {
             // Throw a lock, so that cleanup processes and startup processes 
don't collide.
-            String lockName = getAgentsClassLockName(className);
             String serviceType = getAgentsClassServiceType(className);
-            boolean firstTime;
-            lockManager.enterWriteLock(lockName);
-            try
-            {
-              firstTime = 
lockManager.registerServiceBeginServiceActivity(serviceType, processID);
-              if (firstTime)
-              {
-                agent.cleanUpAgentData(threadContext);
-                String[] deadAgents = 
lockManager.getInactiveServices(serviceType);
-                for (String deadAgent : deadAgents)
-                {
-                  lockManager.unregisterService(serviceType, deadAgent);
-                }
-              }
-            }
-            finally
-            {
-              lockManager.leaveWriteLock(lockName);
-            }
-            // Now initialize agent, being sure to clean up data from previous 
incarnations
-            if (!firstTime)
-              agent.cleanUpAgentData(threadContext, processID);
+            lockManager.registerServiceBeginServiceActivity(serviceType, 
processID, new CleanupAgent(threadContext, agent));
             // There is a potential race condition where the agent has been 
started but hasn't yet appeared in runningHash.
             // But having runningHash be the synchronizer for this activity 
will prevent any problems.
             agent.startAgent(threadContext, processID);
@@ -279,7 +250,7 @@ public class ManifoldCF extends org.apac
         }
         currentAgentClasses.add(className);
       }
-      
+
       // Go through running hash and look for agents processes that have left
       Iterator<String> runningAgentsIterator = runningHash.keySet().iterator();
       while (runningAgentsIterator.hasNext())
@@ -303,43 +274,27 @@ public class ManifoldCF extends org.apac
           }
         }
       }
-      
+    }
+
+    if (problem != null)
+      throw problem;
+    
+    synchronized (runningHash)
+    {
       // For every class we're supposed to be running, find registered but 
no-longer-active instances and clean
       // up after them.
       for (String agentsClass : runningHash.keySet())
       {
         IAgent agent = runningHash.get(agentsClass);
-        // Look for dead service instances for this class.
-        // This cannot happen at the same time as other processes doing this 
check, or at the same
-        // time as a service of that class starting up, so we need a lock to 
prevent those situations.
-        String lockName = getAgentsClassLockName(agentsClass);
-        lockManager.enterWriteLock(lockName);
-        try
-        {
-          // Find the derelict agents of this class, clean them up, and 
deregister them.
-          String agentsClassServiceType = 
getAgentsClassServiceType(agentsClass);
-          String[] inactiveAgents = 
lockManager.getInactiveServices(agentsClassServiceType);
-          for (String inactiveAgentProcessID : inactiveAgents)
-          {
-            agent.cleanUpAgentData(threadContext, inactiveAgentProcessID);
-            // Deregister
-            lockManager.unregisterService(agentsClassServiceType, 
inactiveAgentProcessID);
-          }
-        }
-        catch (ManifoldCFException e)
+        IServiceCleanup cleanup = new CleanupAgent(threadContext, agent);
+        String agentsClassServiceType = getAgentsClassServiceType(agentsClass);
+        while (lockManager.cleanupInactiveService(agentsClassServiceType, 
cleanup))
         {
-          problem = e;
-        }
-        finally
-        {
-          lockManager.leaveWriteLock(lockName);
+          // Loop until no more inactive services
         }
       }
-
     }
-    if (problem != null)
-      throw problem;
-    // Done.
+    
   }
 
   /** Stop all started agents.
@@ -366,6 +321,51 @@ public class ManifoldCF extends org.apac
     // Done.
   }
   
+  protected static class CleanupAgent implements IServiceCleanup
+  {
+    protected final IAgent agent;
+    protected final IThreadContext threadContext;
+    
+    public CleanupAgent(IThreadContext threadContext, IAgent agent)
+    {
+      this.agent = agent;
+      this.threadContext = threadContext;
+    }
+    
+    /** Clean up after the specified service.  This method will block any 
startup of the specified
+    * service for as long as it runs.
+    *@param serviceName is the name of the service.
+    */
+    @Override
+    public void cleanUpService(String serviceName)
+      throws ManifoldCFException
+    {
+      agent.cleanUpAgentData(threadContext, serviceName);
+    }
+
+    /** Clean up after ALL services of the type on the cluster.
+    */
+    @Override
+    public void cleanUpAllServices()
+      throws ManifoldCFException
+    {
+      agent.cleanUpAgentData(threadContext);
+    }
+    
+    /** Perform cluster initialization - that is, whatever is needed presuming 
that the
+    * cluster has been down for an indeterminate period of time, but is 
otherwise in a clean
+    * state.
+    */
+    @Override
+    public void clusterInit()
+      throws ManifoldCFException
+    {
+      // MHL - we really want a separate clusterInit in agents
+      agent.cleanUpAgentData(threadContext);
+    }
+
+  }
+  
   /** Signal output connection needs redoing.
   * This is called when something external changed on an output connection, and
   * therefore all associated documents must be reindexed.

Modified: 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/ILockManager.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/ILockManager.java?rev=1545304&r1=1545303&r2=1545304&view=diff
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/ILockManager.java
 (original)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/ILockManager.java
 Mon Nov 25 14:41:36 2013
@@ -43,34 +43,33 @@ public interface ILockManager
   * called when the service shuts down.  Some ILockManager implementations 
require that this take place for
   * proper management.
   * If the transient registration already exists, it is treated as an error 
and an exception will be thrown.
+  * If registration will succeed, then this method may call an appropriate 
IServiceCleanup method to clean up either the
+  * current service, or all services on the cluster.
   *@param serviceType is the type of service.
   *@param serviceName is the name of the service to register.
-  *@return true if this is the only active service of this type at this time.
+  *@param cleanup is called to clean up either the current service, or all 
services of this type, if no other active service exists
   */
-  public boolean registerServiceBeginServiceActivity(String serviceType, 
String serviceName)
+  public void registerServiceBeginServiceActivity(String serviceType, String 
serviceName, IServiceCleanup cleanup)
     throws ManifoldCFException;
   
-  /** Un-register a service.
-  * This operation cancels the permanent registration of the specified service.
-  * If the service does not exist, this method will do nothing.
-  *@param serviceType is the type of service.
-  *@param serviceName is the name of the service to unregister.
-  */
-  public void unregisterService(String serviceType, String serviceName)
-    throws ManifoldCFException;
-    
-  /** List all registered services of a given type.
+  /** Count all active services of a given type.
   *@param serviceType is the service type.
-  *@return the service names.
+  *@return the count.
   */
-  public String[] getRegisteredServices(String serviceType)
+  public int countActiveServices(String serviceType)
     throws ManifoldCFException;
   
-  /** List services that are registered but not active.
+  /** Clean up any inactive services found.
+  * Calling this method will invoke cleanup of one inactive service at a time.
+  * If there are no inactive services around, then false will be returned.
+  * Note that this method will block whatever service it finds from starting up
+  * for the time the cleanup is proceeding.  At the end of the cleanup, if
+  * successful, the service will be atomically unregistered.
   *@param serviceType is the service type.
-  *@return the list of service names.
+  *@param cleanup is the object to call to clean up an inactive service.
+  *@return true if there were no cleanup operations necessary.
   */
-  public String[] getInactiveServices(String serviceType)
+  public boolean cleanupInactiveService(String serviceType, IServiceCleanup 
cleanup)
     throws ManifoldCFException;
 
   /** End service activity.

Added: 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java?rev=1545304&view=auto
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java
 (added)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java
 Mon Nov 25 14:41:36 2013
@@ -0,0 +1,50 @@
+/* $Id$ */
+
+/**
+* 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.manifoldcf.core.interfaces;
+
+
+/** The IServiceCleanup interface describes functionality needed to clean up 
after
+* a service that has ended, as determined by an ILockManager instance.  It is 
always
+* throttled in a manner where only one thread in
+* the entire cluster will be cleaning up after any specific service.
+*/
+public interface IServiceCleanup
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  /** Clean up after the specified service.  This method will block any 
startup of the specified
+  * service for as long as it runs.
+  *@param serviceName is the name of the service.
+  */
+  public void cleanUpService(String serviceName)
+    throws ManifoldCFException;
+
+  /** Clean up after ALL services of the type on the cluster.
+  */
+  public void cleanUpAllServices()
+    throws ManifoldCFException;
+  
+  /** Perform cluster initialization - that is, whatever is needed presuming 
that the
+  * cluster has been down for an indeterminate period of time, but is 
otherwise in a clean
+  * state.
+  */
+  public void clusterInit()
+    throws ManifoldCFException;
+
+}

Propchange: 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/interfaces/IServiceCleanup.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/BaseLockManager.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/BaseLockManager.java?rev=1545304&r1=1545303&r2=1545304&view=diff
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/BaseLockManager.java
 (original)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/BaseLockManager.java
 Mon Nov 25 14:41:36 2013
@@ -98,12 +98,14 @@ public class BaseLockManager implements 
   * called when the service shuts down.  Some ILockManager implementations 
require that this take place for
   * proper management.
   * If the transient registration already exists, it is treated as an error 
and an exception will be thrown.
+  * If registration will succeed, then this method may call an appropriate 
IServiceCleanup method to clean up either the
+  * current service, or all services on the cluster.
   *@param serviceType is the type of service.
   *@param serviceName is the name of the service to register.
-  *@return true if this is the only active service of this type at this time.
+  *@param cleanup is called to clean up either the current service, or all 
services of this type, if no other active service exists
   */
   @Override
-  public boolean registerServiceBeginServiceActivity(String serviceType, 
String serviceName)
+  public void registerServiceBeginServiceActivity(String serviceType, String 
serviceName, IServiceCleanup cleanup)
     throws ManifoldCFException
   {
     enterWriteLock(serviceLock);
@@ -113,182 +115,183 @@ public class BaseLockManager implements 
       String serviceActiveFlag = makeActiveServiceFlagName(serviceType, 
serviceName);
       if (checkGlobalFlag(serviceActiveFlag))
         throw new ManifoldCFException("Service '"+serviceName+"' of type 
'"+serviceType+"' is already active");
-      // First, register the service and find out how many such services are 
active.
+      
+      // First, see where we stand.
+      // We need to find out whether (a) our service is already registered; 
(b) how many registered services there are;
+      // (c) whether there are other active services.  But no changes will be 
made at this time.
       boolean foundService = false;
       boolean foundActiveService = false;
+      String resourceName;
       int i = 0;
       while (true)
       {
-        String resourceName = buildServiceListEntry(serviceType, i);
+        resourceName = buildServiceListEntry(serviceType, i);
         String x = readServiceName(resourceName);
         if (x == null)
-        {
-          if (!foundService)
-          {
-            writeServiceName(resourceName, serviceName);
-            try
-            {
-              setGlobalFlag(makeRegisteredServiceFlagName(serviceType, 
serviceName));
-            }
-            catch (Throwable e)
-            {
-              writeServiceName(resourceName, null);
-              if (e instanceof Error)
-                throw (Error)e;
-              if (e instanceof RuntimeException)
-                throw (RuntimeException)e;
-              if (e instanceof ManifoldCFException)
-                throw (ManifoldCFException)e;
-              else
-                throw new RuntimeException("Unknown exception of type: 
"+e.getClass().getName()+": "+e.getMessage(),e);
-            }
-          }
           break;
-        }
         if (x.equals(serviceName))
           foundService = true;
         else if (checkGlobalFlag(makeActiveServiceFlagName(serviceType, x)))
           foundActiveService = true;
         i++;
       }
-      // Now, set the appropriate active flag
-      setGlobalFlag(serviceActiveFlag);
-      return !foundActiveService;
-    }
-    finally
-    {
-      leaveWriteLock(serviceLock);
-    }
-  }
-  
-  /** Un-register a service.
-  * This operation cancels the permanent registration of the specified service.
-  * If the service does not exist, this method will do nothing.
-  *@param serviceType is the type of service.
-  *@param serviceName is the name of the service to unregister.
-  */
-  @Override
-  public void unregisterService(String serviceType, String serviceName)
-    throws ManifoldCFException
-  {
-    enterWriteLock(serviceLock);
-    try
-    {
-      // First, do an active check
-      String serviceActiveFlag = makeActiveServiceFlagName(serviceType, 
serviceName);
-      if (checkGlobalFlag(serviceActiveFlag))
-        throw new ManifoldCFException("Service '"+serviceName+"' of type 
'"+serviceType+"' is still active; can't unregister");
-      String serviceRegisteredFlag = 
makeRegisteredServiceFlagName(serviceType, serviceName);
-      clearGlobalFlag(serviceRegisteredFlag);
-      int i = 0;
-      String removalEntry = null;
-      String lastEntry = null;
-      String lastService = null;
-      while (true)
+
+      // Call the appropriate cleanup.  This will depend on what's actually 
registered, and what's active.
+      // If there were no services registered at all when we started, then no 
cleanup is needed, just cluster init.
+      // If this fails, we must revert to having our service not be registered 
and not be active.
+      boolean unregisterAll = false;
+      if (cleanup != null)
       {
-        String resourceName = buildServiceListEntry(serviceType, i);
-        String x = readServiceName(resourceName);
-        if (x == null)
+        if (i == 0)
+          cleanup.clusterInit();
+        else if (foundService && foundActiveService)
+          cleanup.cleanUpService(serviceName);
+        else if (!foundActiveService)
         {
-          if (lastEntry != null)
-            writeServiceName(lastEntry, null);
-          try
-          {
-            if (removalEntry != null && !lastEntry.equals(removalEntry))
-              writeServiceName(removalEntry, lastService);
-          }
-          catch (Throwable e)
-          {
-            writeServiceName(lastEntry, lastService);
-            if (e instanceof Error)
-              throw (Error)e;
-            if (e instanceof RuntimeException)
-              throw (RuntimeException)e;
-            if (e instanceof ManifoldCFException)
-              throw (ManifoldCFException)e;
-            throw new RuntimeException("Unknown exception of type 
"+e.getClass().getName()+": "+e.getMessage(),e);
-          }
-          break;
+          cleanup.cleanUpAllServices();
+          cleanup.clusterInit();
+          unregisterAll = true;
+        }
+      }
+      
+      if (unregisterAll)
+      {
+        // Unregister all (since we did a global cleanup)
+        int k = i;
+        while (k > 0)
+        {
+          k--;
+          resourceName = buildServiceListEntry(serviceType, k);
+          String x = readServiceName(resourceName);
+          clearGlobalFlag(makeRegisteredServiceFlagName(serviceType, x));
+          writeServiceName(resourceName, null);
         }
-        lastEntry = resourceName;
-        lastService = x;
-        if (x.equals(serviceName))
-          removalEntry = resourceName;
-        i++;
       }
+
+      // Now, register (if needed)
+      if (!foundService)
+      {
+        writeServiceName(resourceName, serviceName);
+        try
+        {
+          setGlobalFlag(makeRegisteredServiceFlagName(serviceType, 
serviceName));
+        }
+        catch (Throwable e)
+        {
+          writeServiceName(resourceName, null);
+          if (e instanceof Error)
+            throw (Error)e;
+          if (e instanceof RuntimeException)
+            throw (RuntimeException)e;
+          if (e instanceof ManifoldCFException)
+            throw (ManifoldCFException)e;
+          else
+            throw new RuntimeException("Unknown exception of type: 
"+e.getClass().getName()+": "+e.getMessage(),e);
+        }
+      }
+
+      // Last, set the appropriate active flag
+      setGlobalFlag(serviceActiveFlag);
     }
     finally
     {
       leaveWriteLock(serviceLock);
     }
   }
-    
-  /** List all registered services of a given type.
+  
+  /** Count all active services of a given type.
   *@param serviceType is the service type.
-  *@return the service names.
+  *@return the count.
   */
   @Override
-  public String[] getRegisteredServices(String serviceType)
+  public int countActiveServices(String serviceType)
     throws ManifoldCFException
   {
     enterWriteLock(serviceLock);
     try
     {
+      int count = 0;
       int i = 0;
-      List<String> services = new ArrayList<String>();
       while (true)
       {
         String resourceName = buildServiceListEntry(serviceType, i);
         String x = readServiceName(resourceName);
         if (x == null)
           break;
-        services.add(x);
+        if (checkGlobalFlag(makeActiveServiceFlagName(serviceType, x)))
+          count++;
         i++;
       }
-      String[] rval = new String[services.size()];
-      i = 0;
-      for (String x : services)
-      {
-        rval[i++] = x;
-      }
-      return rval;
+      return count;
     }
     finally
     {
       leaveWriteLock(serviceLock);
     }
   }
-  
-  /** List services that are registered but not active.
+
+  /** Clean up any inactive services found.
+  * Calling this method will invoke cleanup of one inactive service at a time.
+  * If there are no inactive services around, then false will be returned.
+  * Note that this method will block whatever service it finds from starting up
+  * for the time the cleanup is proceeding.  At the end of the cleanup, if
+  * successful, the service will be atomically unregistered.
   *@param serviceType is the service type.
-  *@return the list of service names.
+  *@param cleanup is the object to call to clean up an inactive service.
+  *@return true if there were no cleanup operations necessary.
   */
   @Override
-  public String[] getInactiveServices(String serviceType)
+  public boolean cleanupInactiveService(String serviceType, IServiceCleanup 
cleanup)
     throws ManifoldCFException
   {
     enterWriteLock(serviceLock);
     try
     {
+      // We find ONE service that is registered but inactive, and clean up 
after that one.
+      // Presumably the caller will lather, rinse, and repeat.
+      String serviceName;
+      String resourceName;
       int i = 0;
-      List<String> inactiveServices = new ArrayList<String>();
       while (true)
       {
-        String resourceName = buildServiceListEntry(serviceType, i);
-        String x = readServiceName(resourceName);
-        if (x == null)
+        resourceName = buildServiceListEntry(serviceType, i);
+        serviceName = readServiceName(resourceName);
+        if (serviceName == null)
+          return true;
+        if (!checkGlobalFlag(makeActiveServiceFlagName(serviceType, 
serviceName)))
           break;
-        if (!checkGlobalFlag(makeActiveServiceFlagName(serviceType, x)))
-          inactiveServices.add(x);
         i++;
       }
-      String[] rval = new String[inactiveServices.size()];
-      i = 0;
-      for (String x : inactiveServices)
+      
+      // Found one, in serviceName, at position i
+      // Ideally, we should signal at this point that we're cleaning up after 
it, and then leave
+      // the exclusive lock, so that other activity can take place.  MHL
+      cleanup.cleanUpService(serviceName);
+      
+      // Clean up the registration
+      String serviceRegisteredFlag = 
makeRegisteredServiceFlagName(serviceType, serviceName);
+      
+      // Find the end of the list
+      int k = i + 1;
+      String lastResourceName = null;
+      String lastServiceName = null;
+      while (true)
       {
-        rval[i++] = x;
+        String rName = buildServiceListEntry(serviceType, k);
+        String x = readServiceName(rName);
+        if (x == null)
+          break;
+        lastResourceName = rName;
+        lastServiceName = x;
+        k++;
       }
-      return rval;
+
+      // Rearrange the registration
+      clearGlobalFlag(serviceRegisteredFlag);
+      if (lastServiceName != null)
+        writeServiceName(resourceName, lastServiceName);
+      writeServiceName(lastResourceName, null);
+      return false;
     }
     finally
     {

Modified: 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/LockManager.java
URL: 
http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/LockManager.java?rev=1545304&r1=1545303&r2=1545304&view=diff
==============================================================================
--- 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/LockManager.java
 (original)
+++ 
manifoldcf/branches/CONNECTORS-781/framework/core/src/main/java/org/apache/manifoldcf/core/lockmanager/LockManager.java
 Mon Nov 25 14:41:36 2013
@@ -52,49 +52,45 @@ public class LockManager implements ILoc
   * called when the service shuts down.  Some ILockManager implementations 
require that this take place for
   * proper management.
   * If the transient registration already exists, it is treated as an error 
and an exception will be thrown.
+  * If registration will succeed, then this method may call an appropriate 
IServiceCleanup method to clean up either the
+  * current service, or all services on the cluster.
   *@param serviceType is the type of service.
   *@param serviceName is the name of the service to register.
-  *@return true if this is the only active service of this type at this time.
+  *@param cleanup is called to clean up either the current service, or all 
services of this type, if no other active service exists
   */
   @Override
-  public boolean registerServiceBeginServiceActivity(String serviceType, 
String serviceName)
+  public void registerServiceBeginServiceActivity(String serviceType, String 
serviceName, IServiceCleanup cleanup)
     throws ManifoldCFException
   {
-    return lockManager.registerServiceBeginServiceActivity(serviceType, 
serviceName);
+    lockManager.registerServiceBeginServiceActivity(serviceType, serviceName, 
cleanup);
   }
   
-  /** Un-register a service.
-  * This operation cancels the permanent registration of the specified service.
-  * If the service does not exist, this method will do nothing.
-  *@param serviceType is the type of service.
-  *@param serviceName is the name of the service to unregister.
-  */
-  @Override
-  public void unregisterService(String serviceType, String serviceName)
-    throws ManifoldCFException
-  {
-    lockManager.unregisterService(serviceType, serviceName);
-  }
-    
-  /** List all registered services of a given type.
+  /** Clean up any inactive services found.
+  * Calling this method will invoke cleanup of one inactive service at a time.
+  * If there are no inactive services around, then false will be returned.
+  * Note that this method will block whatever service it finds from starting up
+  * for the time the cleanup is proceeding.  At the end of the cleanup, if
+  * successful, the service will be atomically unregistered.
   *@param serviceType is the service type.
-  *@return the service names.
+  *@param cleanup is the object to call to clean up an inactive service.
+  *@return true if there were no cleanup operations necessary.
   */
   @Override
-  public String[] getRegisteredServices(String serviceType)
+  public boolean cleanupInactiveService(String serviceType, IServiceCleanup 
cleanup)
     throws ManifoldCFException
   {
-    return lockManager.getRegisteredServices(serviceType);
+    return lockManager.cleanupInactiveService(serviceType, cleanup);
   }
-
-  /** List services that are registered but not active.
+  
+  /** Count all active services of a given type.
   *@param serviceType is the service type.
-  *@return the list of service names.
+  *@return the count.
   */
-  public String[] getInactiveServices(String serviceType)
+  @Override
+  public int countActiveServices(String serviceType)
     throws ManifoldCFException
   {
-    return lockManager.getInactiveServices(serviceType);
+    return lockManager.countActiveServices(serviceType);
   }
 
   /** End service activity.


Reply via email to