You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2013/12/19 03:35:13 UTC

svn commit: r1552211 - in /manifoldcf/trunk: ./ framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/ framework/core/src/main/java/org/apache/manifoldcf/core/connectorpool/ framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawle...

Author: kwright
Date: Thu Dec 19 02:35:13 2013
New Revision: 1552211

URL: http://svn.apache.org/r1552211
Log:
Fix for CONNECTORS-846.

Added:
    manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java   (with props)
    manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java   (with props)
Modified:
    manifoldcf/trunk/CHANGES.txt
    manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/ServletListener.java
    manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/connectorpool/ConnectorPool.java
    manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/ServletListener.java

Modified: manifoldcf/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/CHANGES.txt?rev=1552211&r1=1552210&r2=1552211&view=diff
==============================================================================
--- manifoldcf/trunk/CHANGES.txt (original)
+++ manifoldcf/trunk/CHANGES.txt Thu Dec 19 02:35:13 2013
@@ -3,6 +3,11 @@ $Id$
 
 ======================= 1.5-dev =====================
 
+CONNECTORS-846: Once a service had grabbed all connector
+instances, but was not using them any more, it would not release
+them for other cluster members to use.
+(Karl Wright)
+
 CONNECTORS-844: Remove "per JVM" from connection maximum
 messages in crawler UI.
 (Karl Wright)

Added: manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java?rev=1552211&view=auto
==============================================================================
--- manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java (added)
+++ manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java Thu Dec 19 02:35:13 2013
@@ -0,0 +1,141 @@
+/* $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.apiservice;
+
+import org.apache.manifoldcf.core.interfaces.*;
+import org.apache.manifoldcf.agents.interfaces.*;
+import org.apache.manifoldcf.crawler.interfaces.*;
+import org.apache.manifoldcf.authorities.interfaces.*;
+import org.apache.manifoldcf.core.system.Logging;
+import org.apache.manifoldcf.core.system.ManifoldCF;
+import java.util.*;
+import java.lang.reflect.*;
+
+/** This thread periodically calls the cleanup method in all connected repository connectors.  The ostensible purpose
+* is to allow the connectors to shutdown idle connections etc.
+*/
+public class IdleCleanupThread extends Thread
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  /** Constructor.
+  */
+  public IdleCleanupThread()
+    throws ManifoldCFException
+  {
+    super();
+    setName("Idle cleanup thread");
+    setDaemon(true);
+  }
+
+  public void run()
+  {
+    Logging.root.debug("Start up idle cleanup thread");
+    try
+    {
+      // Create a thread context object.
+      IThreadContext threadContext = ThreadContextFactory.make();
+      // Get the cache handle.
+      ICacheManager cacheManager = CacheManagerFactory.make(threadContext);
+      
+      IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+      IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
+      IAuthorityConnectorPool authorityConnectorPool = AuthorityConnectorPoolFactory.make(threadContext);
+      IMappingConnectorPool mappingConnectorPool = MappingConnectorPoolFactory.make(threadContext);
+      
+      IThrottleGroups throttleGroups = ThrottleGroupsFactory.make(threadContext);
+
+      // Loop
+      while (true)
+      {
+        // Do another try/catch around everything in the loop
+        try
+        {
+          // Do the cleanup
+          repositoryConnectorPool.pollAllConnectors();
+          outputConnectorPool.pollAllConnectors();
+          authorityConnectorPool.pollAllConnectors();
+          mappingConnectorPool.pollAllConnectors();
+          
+          throttleGroups.poll();
+          
+          cacheManager.expireObjects(System.currentTimeMillis());
+          
+          // Sleep for the retry interval.
+          ManifoldCF.sleep(5000L);
+        }
+        catch (ManifoldCFException e)
+        {
+          if (e.getErrorCode() == ManifoldCFException.INTERRUPTED)
+            break;
+
+          if (e.getErrorCode() == ManifoldCFException.DATABASE_CONNECTION_ERROR)
+          {
+            Logging.root.error("Idle cleanup thread aborting and restarting due to database connection reset: "+e.getMessage(),e);
+            try
+            {
+              // Give the database a chance to catch up/wake up
+              ManifoldCF.sleep(10000L);
+            }
+            catch (InterruptedException se)
+            {
+              break;
+            }
+            continue;
+          }
+
+          // Log it, but keep the thread alive
+          Logging.root.error("Exception tossed: "+e.getMessage(),e);
+
+          if (e.getErrorCode() == ManifoldCFException.SETUP_ERROR)
+          {
+            // Shut the whole system down!
+            System.exit(1);
+          }
+
+        }
+        catch (InterruptedException e)
+        {
+          // We're supposed to quit
+          break;
+        }
+        catch (OutOfMemoryError e)
+        {
+          System.err.println("API service ran out of memory - shutting down");
+          e.printStackTrace(System.err);
+          System.exit(-200);
+        }
+        catch (Throwable e)
+        {
+          // A more severe error - but stay alive
+          Logging.root.fatal("Error tossed: "+e.getMessage(),e);
+        }
+      }
+    }
+    catch (Throwable e)
+    {
+      // Severe error on initialization
+      System.err.println("API service could not start - shutting down");
+      Logging.root.fatal("IdleCleanupThread initialization error tossed: "+e.getMessage(),e);
+      System.exit(-300);
+    }
+
+  }
+
+}

Propchange: manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/IdleCleanupThread.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/ServletListener.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/ServletListener.java?rev=1552211&r1=1552210&r2=1552211&view=diff
==============================================================================
--- manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/ServletListener.java (original)
+++ manifoldcf/trunk/framework/api-service/src/main/java/org/apache/manifoldcf/apiservice/ServletListener.java Thu Dec 19 02:35:13 2013
@@ -29,11 +29,16 @@ public class ServletListener implements 
 {
   public static final String _rcsid = "@(#)$Id$";
 
+  protected IdleCleanupThread idleCleanupThread = null;
+  
   public void contextInitialized(ServletContextEvent sce)
   {
     try
     {
-      ManifoldCF.initializeEnvironment(ThreadContextFactory.make());
+      IThreadContext threadContext = ThreadContextFactory.make();
+      ManifoldCF.initializeEnvironment(threadContext);
+      idleCleanupThread = new IdleCleanupThread();
+      idleCleanupThread.start();
     }
     catch (ManifoldCFException e)
     {
@@ -43,7 +48,21 @@ public class ServletListener implements 
   
   public void contextDestroyed(ServletContextEvent sce)
   {
-    ManifoldCF.cleanUpEnvironment(ThreadContextFactory.make());
+    try
+    {
+      while (true)
+      {
+        if (idleCleanupThread == null)
+          break;
+        idleCleanupThread.interrupt();
+        if (!idleCleanupThread.isAlive())
+          idleCleanupThread = null;
+      }
+    }
+    finally
+    {
+      ManifoldCF.cleanUpEnvironment(ThreadContextFactory.make());
+    }
   }
 
 }

Modified: manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/connectorpool/ConnectorPool.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/connectorpool/ConnectorPool.java?rev=1552211&r1=1552210&r2=1552211&view=diff
==============================================================================
--- manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/connectorpool/ConnectorPool.java (original)
+++ manifoldcf/trunk/framework/core/src/main/java/org/apache/manifoldcf/core/connectorpool/ConnectorPool.java Thu Dec 19 02:35:13 2013
@@ -621,7 +621,7 @@ public abstract class ConnectorPool<T ex
           optimalTarget += increment;
         }
         
-        //System.out.println("maxTarget = "+maximumTarget+"; fairTarget = "+fairTarget+"; optimalTarget = "+optimalTarget);
+        //System.out.println(serviceTypeName+":maxTarget = "+maximumTarget+"; fairTarget = "+fairTarget+"; optimalTarget = "+optimalTarget);
 
         // Now compute actual target
         int target = maximumTarget;
@@ -630,6 +630,7 @@ public abstract class ConnectorPool<T ex
         if (target > optimalTarget)
           target = optimalTarget;
         
+        //System.out.println(serviceTypeName+":Picking target="+target+"; localInUse="+localInUse);
         // Write these values to the service data variables.
         // NOTE that there is a race condition here; the target value depends on all the calculations above being accurate, and not changing out from under us.
         // So, that's why we have a write lock around the pool calculations.
@@ -639,6 +640,7 @@ public abstract class ConnectorPool<T ex
         // Now, update our localMax
         if (target == localMax)
           return;
+        //System.out.println(serviceTypeName+":Updating target: "+target);
         // Compute the number of instances in use locally
         localInUse = localMax - numFree;
         localMax = target;
@@ -651,6 +653,35 @@ public abstract class ConnectorPool<T ex
       {
         lockManager.leaveWriteLock(targetCalcLockName);
       }
+      
+      // Finally, free pooled instances in excess of target
+      while (stack.size() > 0 && stack.size() > numFree)
+      {
+        // Try to find a connector instance that is not actually connected.
+        // These are likely to be at the front of the queue, since those are the
+        // oldest.
+        int j;
+        for (j = 0; j < stack.size(); j++)
+        {
+          if (!stack.get(j).isConnected())
+            break;
+        }
+        T rc;
+        if (j == stack.size())
+          rc = stack.remove(stack.size()-1);
+        else
+          rc = stack.remove(j);
+        rc.setThreadContext(threadContext);
+        try
+        {
+          rc.disconnect();
+        }
+        finally
+        {
+          rc.clearThreadContext();
+        }
+      }
+
     }
 
     /** Flush unused connectors.

Added: manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java?rev=1552211&view=auto
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java (added)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java Thu Dec 19 02:35:13 2013
@@ -0,0 +1,141 @@
+/* $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.crawlerui;
+
+import org.apache.manifoldcf.core.interfaces.*;
+import org.apache.manifoldcf.agents.interfaces.*;
+import org.apache.manifoldcf.crawler.interfaces.*;
+import org.apache.manifoldcf.authorities.interfaces.*;
+import org.apache.manifoldcf.core.system.Logging;
+import org.apache.manifoldcf.core.system.ManifoldCF;
+import java.util.*;
+import java.lang.reflect.*;
+
+/** This thread periodically calls the cleanup method in all connected repository connectors.  The ostensible purpose
+* is to allow the connectors to shutdown idle connections etc.
+*/
+public class IdleCleanupThread extends Thread
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  /** Constructor.
+  */
+  public IdleCleanupThread()
+    throws ManifoldCFException
+  {
+    super();
+    setName("Idle cleanup thread");
+    setDaemon(true);
+  }
+
+  public void run()
+  {
+    Logging.root.debug("Start up idle cleanup thread");
+    try
+    {
+      // Create a thread context object.
+      IThreadContext threadContext = ThreadContextFactory.make();
+      // Get the cache handle.
+      ICacheManager cacheManager = CacheManagerFactory.make(threadContext);
+      
+      IRepositoryConnectorPool repositoryConnectorPool = RepositoryConnectorPoolFactory.make(threadContext);
+      IOutputConnectorPool outputConnectorPool = OutputConnectorPoolFactory.make(threadContext);
+      IAuthorityConnectorPool authorityConnectorPool = AuthorityConnectorPoolFactory.make(threadContext);
+      IMappingConnectorPool mappingConnectorPool = MappingConnectorPoolFactory.make(threadContext);
+      
+      IThrottleGroups throttleGroups = ThrottleGroupsFactory.make(threadContext);
+
+      // Loop
+      while (true)
+      {
+        // Do another try/catch around everything in the loop
+        try
+        {
+          // Do the cleanup
+          repositoryConnectorPool.pollAllConnectors();
+          outputConnectorPool.pollAllConnectors();
+          authorityConnectorPool.pollAllConnectors();
+          mappingConnectorPool.pollAllConnectors();
+          
+          throttleGroups.poll();
+          
+          cacheManager.expireObjects(System.currentTimeMillis());
+          
+          // Sleep for the retry interval.
+          ManifoldCF.sleep(5000L);
+        }
+        catch (ManifoldCFException e)
+        {
+          if (e.getErrorCode() == ManifoldCFException.INTERRUPTED)
+            break;
+
+          if (e.getErrorCode() == ManifoldCFException.DATABASE_CONNECTION_ERROR)
+          {
+            Logging.root.error("Idle cleanup thread aborting and restarting due to database connection reset: "+e.getMessage(),e);
+            try
+            {
+              // Give the database a chance to catch up/wake up
+              ManifoldCF.sleep(10000L);
+            }
+            catch (InterruptedException se)
+            {
+              break;
+            }
+            continue;
+          }
+
+          // Log it, but keep the thread alive
+          Logging.root.error("Exception tossed: "+e.getMessage(),e);
+
+          if (e.getErrorCode() == ManifoldCFException.SETUP_ERROR)
+          {
+            // Shut the whole system down!
+            System.exit(1);
+          }
+
+        }
+        catch (InterruptedException e)
+        {
+          // We're supposed to quit
+          break;
+        }
+        catch (OutOfMemoryError e)
+        {
+          System.err.println("Crawler UI ran out of memory - shutting down");
+          e.printStackTrace(System.err);
+          System.exit(-200);
+        }
+        catch (Throwable e)
+        {
+          // A more severe error - but stay alive
+          Logging.root.fatal("Error tossed: "+e.getMessage(),e);
+        }
+      }
+    }
+    catch (Throwable e)
+    {
+      // Severe error on initialization
+      System.err.println("Crawler UI could not start - shutting down");
+      Logging.root.fatal("IdleCleanupThread initialization error tossed: "+e.getMessage(),e);
+      System.exit(-300);
+    }
+
+  }
+
+}

Propchange: manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/IdleCleanupThread.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/ServletListener.java
URL: http://svn.apache.org/viewvc/manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/ServletListener.java?rev=1552211&r1=1552210&r2=1552211&view=diff
==============================================================================
--- manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/ServletListener.java (original)
+++ manifoldcf/trunk/framework/crawler-ui/src/main/java/org/apache/manifoldcf/crawlerui/ServletListener.java Thu Dec 19 02:35:13 2013
@@ -29,11 +29,16 @@ public class ServletListener implements 
 {
   public static final String _rcsid = "@(#)$Id$";
 
+  protected IdleCleanupThread idleCleanupThread = null;
+
   public void contextInitialized(ServletContextEvent sce)
   {
     try
     {
-      ManifoldCF.initializeEnvironment(ThreadContextFactory.make());
+      IThreadContext threadContext = ThreadContextFactory.make();
+      ManifoldCF.initializeEnvironment(threadContext);
+      idleCleanupThread = new IdleCleanupThread();
+      idleCleanupThread.start();
     }
     catch (ManifoldCFException e)
     {
@@ -43,7 +48,21 @@ public class ServletListener implements 
   
   public void contextDestroyed(ServletContextEvent sce)
   {
-    ManifoldCF.cleanUpEnvironment(ThreadContextFactory.make());
+    try
+    {
+      while (true)
+      {
+        if (idleCleanupThread == null)
+          break;
+        idleCleanupThread.interrupt();
+        if (!idleCleanupThread.isAlive())
+          idleCleanupThread = null;
+      }
+    }
+    finally
+    {
+      ManifoldCF.cleanUpEnvironment(ThreadContextFactory.make());
+    }
   }
 
 }