incubator-connectors-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kwri...@apache.org
Subject svn commit: r952221 - in /incubator/lcf/trunk/modules/framework: agents/org/apache/lcf/agents/ agents/org/apache/lcf/agents/system/ core/org/apache/lcf/core/interfaces/ core/org/apache/lcf/core/system/ pull-agent/org/apache/lcf/crawler/system/
Date Mon, 07 Jun 2010 13:39:41 GMT
Author: kwright
Date: Mon Jun  7 13:39:40 2010
New Revision: 952221

URL: http://svn.apache.org/viewvc?rev=952221&view=rev
Log:
Revise how shutdown occurs, so that system shutdown is automatic, and is no longer explicit.
 This will help the port to Jetty, and also adds resilience in cases where the agents process
is killed, rather than shutdown in an orderly way.

Added:
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java
  (with props)
Modified:
    incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/AgentRun.java
    incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/system/LCF.java
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/system/LCF.java
    incubator/lcf/trunk/modules/framework/pull-agent/org/apache/lcf/crawler/system/LCF.java

Modified: incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/AgentRun.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/AgentRun.java?rev=952221&r1=952220&r2=952221&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/AgentRun.java (original)
+++ incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/AgentRun.java Mon Jun
 7 13:39:40 2010
@@ -52,32 +52,25 @@ public class AgentRun
       // Clear the agents shutdown signal.
       lockManager.clearGlobalFlag(agentShutdownSignal);
       System.err.println("Running...");
-      try
+      while (true)
       {
-        while (true)
-        {
-          // Any shutdown signal yet?
-          if (lockManager.checkGlobalFlag(agentShutdownSignal))
-            break;
+        // Any shutdown signal yet?
+        if (lockManager.checkGlobalFlag(agentShutdownSignal))
+          break;
           
-          // Start whatever agents need to be started
-          LCF.startAgents(tc);
+        // Start whatever agents need to be started
+        LCF.startAgents(tc);
 
-          try
-          {
-            LCF.sleep(5000);
-          }
-          catch (InterruptedException e)
-          {
-            break;
-          }
+        try
+        {
+          LCF.sleep(5000);
+        }
+        catch (InterruptedException e)
+        {
+          break;
         }
-        System.err.println("Shutting down...");
-      }
-      finally
-      {
-        LCF.stopAgents(tc);
       }
+      System.err.println("Shutting down...");
     }
     catch (LCFException e)
     {

Modified: incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/system/LCF.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/system/LCF.java?rev=952221&r1=952220&r2=952221&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/system/LCF.java (original)
+++ incubator/lcf/trunk/modules/framework/agents/org/apache/lcf/agents/system/LCF.java Mon
Jun  7 13:39:40 2010
@@ -42,17 +42,22 @@ public class LCF extends org.apache.lcf.
 
   /** This is the place we keep track of the agents we've started. */
   protected static HashMap runningHash = new HashMap();
-
+  /** This flag prevents startAgents() from starting anything once stopAgents() has been
called. */
+  protected static boolean stopAgentsRun = false;
+  
   /** Initialize environment.
   */
   public static synchronized void initializeEnvironment()
   {
-    // System.out.println(" In agents initializeEnvironment");
     if (initialized)
       return;
 
-    // System.out.println("Initializing");
+    // Do core initialization
     org.apache.lcf.core.system.LCF.initializeEnvironment();
+    
+    // Create the shutdown hook for agents.  All activity will be keyed off of runningHash,
so it is safe to do this under all conditions.
+    org.apache.lcf.core.system.LCF.addShutdownHook(new AgentsShutdownHook());
+    
     Logging.initializeLoggers();
     Logging.setLogLevels();
     initialized = true;
@@ -93,7 +98,7 @@ public class LCF extends org.apache.lcf.
   }
 
 
-  /** Start agents.
+  /** Start all not-running agents.
   *@param threadContext is the thread context.
   */
   public static void startAgents(IThreadContext threadContext)
@@ -102,34 +107,51 @@ public class LCF extends org.apache.lcf.
     // Get agent manager
     IAgentManager manager = AgentManagerFactory.make(threadContext);
     String[] classes = manager.getAllAgents();
-    int i = 0;
-    while (i < classes.length)
+    LCFException problem = null;
+    synchronized (runningHash)
     {
-      String className = classes[i++];
-      synchronized (runningHash)
+      // DO NOT permit this method to do anything if stopAgents() has ever been called for
this JVM! 
+      // (If it has, it means that the JVM is trying to shut down.)
+      if (stopAgentsRun)
+        return;
+      int i = 0;
+      while (i < classes.length)
       {
+        String className = classes[i++];
         if (runningHash.get(className) == null)
         {
           // Start this agent
           IAgent agent = AgentFactory.make(threadContext,className);
-          // Start it
-          agent.startAgent();
-          // Successful
-          runningHash.put(className,agent);
+          try
+          {
+            // 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.
+            // There is ANOTHER potential race condition, however, that can occur if the
process is shut down just before startAgents() is called.
+            // We avoid that problem by means of a flag, which prevents startAgents() from
doing anything once stopAgents() has been called.
+            agent.startAgent();
+            // Successful!
+            runningHash.put(className,agent);
+          }
+          catch (LCFException e)
+          {
+            problem = e;
+          }
         }
       }
     }
+    if (problem != null)
+      throw problem;
     // Done.
   }
 
-  /** Stop agents.
-  *@param threadContext is the thread context
+  /** Stop all started agents.
   */
   public static void stopAgents(IThreadContext threadContext)
     throws LCFException
   {
     synchronized (runningHash)
     {
+      stopAgentsRun = true;
       HashMap iterHash = (HashMap)runningHash.clone();
       Iterator iter = iterHash.keySet().iterator();
       while (iter.hasNext())
@@ -161,5 +183,22 @@ public class LCF extends org.apache.lcf.
     AgentManagerFactory.noteOutputConnectionChange(threadContext,connectionName);
   }
   
+  /** Agents shutdown hook class */
+  protected static class AgentsShutdownHook implements IShutdownHook
+  {
+    
+    public AgentsShutdownHook()
+    {
+    }
+    
+    public void doCleanup()
+      throws LCFException
+    {
+      IThreadContext tc = ThreadContextFactory.make();
+      stopAgents(tc);
+    }
+    
+  }
+  
 }
 

Added: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java?rev=952221&view=auto
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java
(added)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java
Mon Jun  7 13:39:40 2010
@@ -0,0 +1,29 @@
+/* $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.lcf.core.interfaces;
+
+/** This interface describes functionality needed for a shutdown hook */
+public interface IShutdownHook
+{
+  /** Do the requisite cleanup.
+  */
+  public void doCleanup()
+    throws LCFException;
+}
+

Propchange: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/IShutdownHook.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/system/LCF.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/system/LCF.java?rev=952221&r1=952220&r2=952221&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/system/LCF.java (original)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/system/LCF.java Mon Jun
 7 13:39:40 2010
@@ -27,16 +27,31 @@ public class LCF
 {
   public static final String _rcsid = "@(#)$Id$";
 
-
-  // On-exit file delete tracking
-  protected static FileTrack tracker = new FileTrack();
-  // Shutdown thread
-  protected static Thread shutdownThread = new FileCleanupThread();
+  
+  // Shutdown hooks
+  /** Temporary file collector */
+  protected static FileTrack tracker;
+  /** Database handle cleanup */
+  protected static DatabaseShutdown dbShutdown;
+  
+  /** Array of cleanup hooks (for managing shutdown) */
+  protected static ArrayList cleanupHooks; 
+  /** Shutdown thread */
+  protected static Thread shutdownThread;
+  /** Static initializer for setting up shutdown thread etc. */
   static
   {
+    cleanupHooks = new ArrayList();
+    shutdownThread = new ShutdownThread(cleanupHooks);
+    tracker = new FileTrack();
+    dbShutdown = new DatabaseShutdown();
     try
     {
       Runtime.getRuntime().addShutdownHook(shutdownThread);
+      // Register the file tracker for cleanup on shutdown
+      addShutdownHook(tracker);
+      // Register the database cleanup hook
+      addShutdownHook(dbShutdown);
     }
     catch (Exception e)
     {
@@ -971,8 +986,45 @@ public class LCF
     return Float.intBitsToFloat(readSdword(os));
   }
 
+  /** Add a cleanup hook to the list.  These hooks will be evaluated in the
+  * reverse order than the order in which they were added.
+  *@param hook is the shutdown hook that needs to be added to the sequence.
+  */
+  public static void addShutdownHook(IShutdownHook hook)
+  {
+    synchronized (cleanupHooks)
+    {
+      cleanupHooks.add(hook);
+    }
+  }
+  
+  /** Perform system shutdown, using the registered shutdown hooks. */
+  protected static void cleanUpSystem()
+  {
+    // It needs to call all registered shutdown hooks, in reverse order.
+    // A failure of any one hook should cause the cleanup to continue, after a logging attempt
is made.
+    synchronized (cleanupHooks)
+    {
+      int i = cleanupHooks.size();
+      while (i > 0)
+      {
+	i--;
+	IShutdownHook hook = (IShutdownHook)cleanupHooks.get(i);
+	try
+	{
+	  hook.doCleanup();
+	}
+	catch (LCFException e)
+	{
+	  Logging.root.warn("Error during system shutdown: "+e.getMessage(),e);
+	}
+      }
+      cleanupHooks.clear();
+    }
+  }
+
   /** Class that tracks files that need to be cleaned up on exit */
-  protected static class FileTrack
+  protected static class FileTrack implements IShutdownHook
   {
     /** Key and value are both File objects */
     protected HashMap filesToDelete = new HashMap();
@@ -996,15 +1048,19 @@ public class LCF
     }
 
     /** Delete all remaining files */
-    public synchronized void cleanUpAll()
+    public void doCleanup()
+      throws LCFException
     {
-      Iterator iter = filesToDelete.keySet().iterator();
-      while (iter.hasNext())
+      synchronized (this)
       {
-        File f = (File)iter.next();
-        f.delete();
+	Iterator iter = filesToDelete.keySet().iterator();
+	while (iter.hasNext())
+	{
+	  File f = (File)iter.next();
+	  f.delete();
+	}
+	filesToDelete.clear();
       }
-      filesToDelete.clear();
     }
 
     /** Finalizer, which is designed to catch class unloading that tomcat 5.5 does.
@@ -1014,7 +1070,7 @@ public class LCF
     {
       try
       {
-        cleanUpAll();
+        doCleanup();
       }
       finally
       {
@@ -1024,18 +1080,15 @@ public class LCF
 
   }
 
-  /** Finisher thread, to be registered with the runtime */
-  protected static class FileCleanupThread extends Thread
+  /** Class that cleans up database handles on exit */
+  protected static class DatabaseShutdown implements IShutdownHook
   {
-    /** Constructor.
-    */
-    public FileCleanupThread()
+    public DatabaseShutdown()
     {
-      super();
-      setName("File cleanup thread");
     }
-
-    public void run()
+    
+    public void doCleanup()
+      throws LCFException
     {
       // Clean up the database handles
       Thread t = new DatabaseConnectionReleaseThread();
@@ -1048,9 +1101,25 @@ public class LCF
       catch (InterruptedException e)
       {
       }
-      // Cleanup temp files
-      if (tracker != null)
-        tracker.cleanUpAll();
+    }
+  }
+  
+  /** Finisher thread, to be registered with the runtime */
+  protected static class ShutdownThread extends Thread
+  {
+    protected ArrayList cleanupHooks;
+    /** Constructor.
+    */
+    public ShutdownThread(ArrayList cleanupHooks)
+    {
+      super();
+      setName("Shutdown thread");
+    }
+
+    public void run()
+    {
+      // This thread is run at shutdown time.
+      cleanUpSystem();
     }
   }
 

Modified: incubator/lcf/trunk/modules/framework/pull-agent/org/apache/lcf/crawler/system/LCF.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/pull-agent/org/apache/lcf/crawler/system/LCF.java?rev=952221&r1=952220&r2=952221&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/pull-agent/org/apache/lcf/crawler/system/LCF.java
(original)
+++ incubator/lcf/trunk/modules/framework/pull-agent/org/apache/lcf/crawler/system/LCF.java
Mon Jun  7 13:39:40 2010
@@ -73,6 +73,9 @@ public class LCF extends org.apache.lcf.
   protected static final String lowWaterFactorProperty = "org.apache.lcf.crawler.lowwaterfactor";
   protected static final String stuffAmtFactorProperty = "org.apache.lcf.crawler.stuffamountfactor";
 
+  /** This object is used to make sure the initialization sequence is atomic.  Shutdown cannot
occur until the system is in a known state. */
+  protected static Integer startupLock = new Integer(0);
+  
   /** Initialize environment.
   */
   public static synchronized void initializeEnvironment()
@@ -130,93 +133,95 @@ public class LCF extends org.apache.lcf.
   public static void startSystem(IThreadContext threadContext)
     throws LCFException
   {
-
-    // Now, start all the threads
-    String maxThreads = getProperty(workerThreadCountProperty);
-    if (maxThreads == null)
-      maxThreads = "100";
-    numWorkerThreads = new Integer(maxThreads).intValue();
-    if (numWorkerThreads < 1 || numWorkerThreads > 300)
-      throw new LCFException("Illegal value for the number of worker threads");
-    String maxDeleteThreads = getProperty(deleteThreadCountProperty);
-    if (maxDeleteThreads == null)
-      maxDeleteThreads = "10";
-    String maxExpireThreads = getProperty(expireThreadCountProperty);
-    if (maxExpireThreads == null)
-      maxExpireThreads = "10";
-    numDeleteThreads = new Integer(maxDeleteThreads).intValue();
-    if (numDeleteThreads < 1 || numDeleteThreads > 300)
-      throw new LCFException("Illegal value for the number of delete threads");
-    numExpireThreads = new Integer(maxExpireThreads).intValue();
-    if (numExpireThreads < 1 || numExpireThreads > 300)
-      throw new LCFException("Illegal value for the number of expire threads");
-    String lowWaterFactorString = getProperty(lowWaterFactorProperty);
-    if (lowWaterFactorString == null)
-      lowWaterFactorString = "5";
-    lowWaterFactor = new Float(lowWaterFactorString).floatValue();
-    if (lowWaterFactor < 1.0 || lowWaterFactor > 1000.0)
-      throw new LCFException("Illegal value for the low water factor");
-    String stuffAmtFactorString = getProperty(stuffAmtFactorProperty);
-    if (stuffAmtFactorString == null)
-      stuffAmtFactorString = "2";
-    stuffAmtFactor = new Float(stuffAmtFactorString).floatValue();
-    if (stuffAmtFactor < 0.1 || stuffAmtFactor > 1000.0)
-      throw new LCFException("Illegal value for the stuffing amount factor");
-
-
-    // Create the threads and objects.  This MUST be completed before there is any chance
of "shutdownSystem" getting called.
-
-    QueueTracker queueTracker = new QueueTracker();
-
-
-    DocumentQueue documentQueue = new DocumentQueue();
-    DocumentDeleteQueue documentDeleteQueue = new DocumentDeleteQueue();
-    DocumentDeleteQueue expireQueue = new DocumentDeleteQueue();
-
-    BlockingDocuments blockingDocuments = new BlockingDocuments();
-
-    workerResetManager = new WorkerResetManager(documentQueue);
-    docDeleteResetManager = new DocDeleteResetManager(documentDeleteQueue);
-
-    jobStartThread = new JobStartThread();
-    startupThread = new StartupThread(queueTracker);
-    finisherThread = new FinisherThread();
-    jobDeleteThread = new JobDeleteThread();
-    stufferThread = new StufferThread(documentQueue,numWorkerThreads,workerResetManager,queueTracker,blockingDocuments,lowWaterFactor,stuffAmtFactor);
-    expireStufferThread = new ExpireStufferThread(expireQueue,numExpireThreads,workerResetManager);
-    setPriorityThread = new SetPriorityThread(queueTracker,numWorkerThreads,blockingDocuments);
-
-    workerThreads = new WorkerThread[numWorkerThreads];
-    int i = 0;
-    while (i < numWorkerThreads)
-    {
-      workerThreads[i] = new WorkerThread(Integer.toString(i),documentQueue,workerResetManager,queueTracker);
-      i++;
-    }
-
-    expireThreads = new ExpireThread[numExpireThreads];
-    i = 0;
-    while (i < numExpireThreads)
+    synchronized (startupLock)
     {
-      expireThreads[i] = new ExpireThread(Integer.toString(i),expireQueue,queueTracker,workerResetManager);
-      i++;
+      // Now, start all the threads
+      String maxThreads = getProperty(workerThreadCountProperty);
+      if (maxThreads == null)
+        maxThreads = "100";
+      numWorkerThreads = new Integer(maxThreads).intValue();
+      if (numWorkerThreads < 1 || numWorkerThreads > 300)
+        throw new LCFException("Illegal value for the number of worker threads");
+      String maxDeleteThreads = getProperty(deleteThreadCountProperty);
+      if (maxDeleteThreads == null)
+        maxDeleteThreads = "10";
+      String maxExpireThreads = getProperty(expireThreadCountProperty);
+      if (maxExpireThreads == null)
+        maxExpireThreads = "10";
+      numDeleteThreads = new Integer(maxDeleteThreads).intValue();
+      if (numDeleteThreads < 1 || numDeleteThreads > 300)
+        throw new LCFException("Illegal value for the number of delete threads");
+      numExpireThreads = new Integer(maxExpireThreads).intValue();
+      if (numExpireThreads < 1 || numExpireThreads > 300)
+        throw new LCFException("Illegal value for the number of expire threads");
+      String lowWaterFactorString = getProperty(lowWaterFactorProperty);
+      if (lowWaterFactorString == null)
+        lowWaterFactorString = "5";
+      lowWaterFactor = new Float(lowWaterFactorString).floatValue();
+      if (lowWaterFactor < 1.0 || lowWaterFactor > 1000.0)
+        throw new LCFException("Illegal value for the low water factor");
+      String stuffAmtFactorString = getProperty(stuffAmtFactorProperty);
+      if (stuffAmtFactorString == null)
+        stuffAmtFactorString = "2";
+      stuffAmtFactor = new Float(stuffAmtFactorString).floatValue();
+      if (stuffAmtFactor < 0.1 || stuffAmtFactor > 1000.0)
+        throw new LCFException("Illegal value for the stuffing amount factor");
+
+
+      // Create the threads and objects.  This MUST be completed before there is any chance
of "shutdownSystem" getting called.
+
+      QueueTracker queueTracker = new QueueTracker();
+
+
+      DocumentQueue documentQueue = new DocumentQueue();
+      DocumentDeleteQueue documentDeleteQueue = new DocumentDeleteQueue();
+      DocumentDeleteQueue expireQueue = new DocumentDeleteQueue();
+
+      BlockingDocuments blockingDocuments = new BlockingDocuments();
+
+      workerResetManager = new WorkerResetManager(documentQueue);
+      docDeleteResetManager = new DocDeleteResetManager(documentDeleteQueue);
+
+      jobStartThread = new JobStartThread();
+      startupThread = new StartupThread(queueTracker);
+      finisherThread = new FinisherThread();
+      jobDeleteThread = new JobDeleteThread();
+      stufferThread = new StufferThread(documentQueue,numWorkerThreads,workerResetManager,queueTracker,blockingDocuments,lowWaterFactor,stuffAmtFactor);
+      expireStufferThread = new ExpireStufferThread(expireQueue,numExpireThreads,workerResetManager);
+      setPriorityThread = new SetPriorityThread(queueTracker,numWorkerThreads,blockingDocuments);
+
+      workerThreads = new WorkerThread[numWorkerThreads];
+      int i = 0;
+      while (i < numWorkerThreads)
+      {
+        workerThreads[i] = new WorkerThread(Integer.toString(i),documentQueue,workerResetManager,queueTracker);
+        i++;
+      }
+
+      expireThreads = new ExpireThread[numExpireThreads];
+      i = 0;
+      while (i < numExpireThreads)
+      {
+        expireThreads[i] = new ExpireThread(Integer.toString(i),expireQueue,queueTracker,workerResetManager);
+        i++;
+      }
+
+      deleteStufferThread = new DocumentDeleteStufferThread(documentDeleteQueue,numDeleteThreads,docDeleteResetManager);
+      deleteThreads = new DocumentDeleteThread[numDeleteThreads];
+      i = 0;
+      while (i < numDeleteThreads)
+      {
+        deleteThreads[i] = new DocumentDeleteThread(Integer.toString(i),documentDeleteQueue,docDeleteResetManager);
+        i++;
+      }
+      jobResetThread = new JobResetThread(queueTracker);
+      seedingThread = new SeedingThread(queueTracker);
+      idleCleanupThread = new IdleCleanupThread();
+
+      initializationThread = new InitializationThread(queueTracker);
+      // Start the initialization thread.  This does the initialization work and starts all
the other threads when that's done.  It then exits.
+      initializationThread.start();
     }
-
-    deleteStufferThread = new DocumentDeleteStufferThread(documentDeleteQueue,numDeleteThreads,docDeleteResetManager);
-    deleteThreads = new DocumentDeleteThread[numDeleteThreads];
-    i = 0;
-    while (i < numDeleteThreads)
-    {
-      deleteThreads[i] = new DocumentDeleteThread(Integer.toString(i),documentDeleteQueue,docDeleteResetManager);
-      i++;
-    }
-    jobResetThread = new JobResetThread(queueTracker);
-    seedingThread = new SeedingThread(queueTracker);
-    idleCleanupThread = new IdleCleanupThread();
-
-    initializationThread = new InitializationThread(queueTracker);
-    // Start the initialization thread.  This does the initialization work and starts all
the other threads when that's done.  It then exits.
-    initializationThread.start();
   }
 
   protected static class InitializationThread extends Thread
@@ -332,230 +337,232 @@ public class LCF extends org.apache.lcf.
   public static void stopSystem(IThreadContext threadContext)
     throws LCFException
   {
-
-    while (initializationThread != null || jobDeleteThread != null || startupThread != null
|| jobStartThread != null || stufferThread != null ||
-      finisherThread != null || workerThreads != null || expireStufferThread != null | expireThreads
!= null ||
-      deleteStufferThread != null || deleteThreads != null ||
-      jobResetThread != null || seedingThread != null || idleCleanupThread != null || setPriorityThread
!= null)
+    synchronized (startupLock)
     {
-      // Send an interrupt to all threads that are still there.
-      // In theory, this only needs to be done once.  In practice, I have seen cases where
the thread loses track of the fact that it has been
-      // interrupted (which may be a JVM bug - who knows?), but in any case there's no harm
in doing it again.
-      if (initializationThread != null)
-      {
-        initializationThread.interrupt();
-      }
-      if (setPriorityThread != null)
-      {
-        setPriorityThread.interrupt();
-      }
-      if (jobStartThread != null)
-      {
-        jobStartThread.interrupt();
-      }
-      if (jobDeleteThread != null)
-      {
-        jobDeleteThread.interrupt();
-      }
-      if (startupThread != null)
-      {
-        startupThread.interrupt();
-      }
-      if (stufferThread != null)
+      while (initializationThread != null || jobDeleteThread != null || startupThread !=
null || jobStartThread != null || stufferThread != null ||
+        finisherThread != null || workerThreads != null || expireStufferThread != null |
expireThreads != null ||
+        deleteStufferThread != null || deleteThreads != null ||
+        jobResetThread != null || seedingThread != null || idleCleanupThread != null || setPriorityThread
!= null)
       {
-        stufferThread.interrupt();
-      }
-      if (expireStufferThread != null)
-      {
-        expireStufferThread.interrupt();
-      }
-      if (finisherThread != null)
-      {
-        finisherThread.interrupt();
-      }
-      if (workerThreads != null)
-      {
-        int i = 0;
-        while (i < workerThreads.length)
+        // Send an interrupt to all threads that are still there.
+        // In theory, this only needs to be done once.  In practice, I have seen cases where
the thread loses track of the fact that it has been
+        // interrupted (which may be a JVM bug - who knows?), but in any case there's no
harm in doing it again.
+        if (initializationThread != null)
         {
-          Thread workerThread = workerThreads[i++];
-          if (workerThread != null)
-            workerThread.interrupt();
+          initializationThread.interrupt();
         }
-      }
-      if (expireThreads != null)
-      {
-        int i = 0;
-        while (i < expireThreads.length)
+        if (setPriorityThread != null)
         {
-          Thread expireThread = expireThreads[i++];
-          if (expireThread != null)
-            expireThread.interrupt();
+          setPriorityThread.interrupt();
         }
-      }
-      if (deleteStufferThread != null)
-      {
-        deleteStufferThread.interrupt();
-      }
-      if (deleteThreads != null)
-      {
-        int i = 0;
-        while (i < deleteThreads.length)
+        if (jobStartThread != null)
         {
-          Thread deleteThread = deleteThreads[i++];
-          if (deleteThread != null)
-            deleteThread.interrupt();
+          jobStartThread.interrupt();
+        }
+        if (jobDeleteThread != null)
+        {
+          jobDeleteThread.interrupt();
+        }
+        if (startupThread != null)
+        {
+          startupThread.interrupt();
+        }
+        if (stufferThread != null)
+        {
+          stufferThread.interrupt();
+        }
+        if (expireStufferThread != null)
+        {
+          expireStufferThread.interrupt();
+        }
+        if (finisherThread != null)
+        {
+          finisherThread.interrupt();
+        }
+        if (workerThreads != null)
+        {
+          int i = 0;
+          while (i < workerThreads.length)
+          {
+            Thread workerThread = workerThreads[i++];
+            if (workerThread != null)
+              workerThread.interrupt();
+          }
+        }
+        if (expireThreads != null)
+        {
+          int i = 0;
+          while (i < expireThreads.length)
+          {
+            Thread expireThread = expireThreads[i++];
+            if (expireThread != null)
+              expireThread.interrupt();
+          }
+        }
+        if (deleteStufferThread != null)
+        {
+          deleteStufferThread.interrupt();
+        }
+        if (deleteThreads != null)
+        {
+          int i = 0;
+          while (i < deleteThreads.length)
+          {
+            Thread deleteThread = deleteThreads[i++];
+            if (deleteThread != null)
+              deleteThread.interrupt();
+          }
+        }
+        if (jobResetThread != null)
+        {
+          jobResetThread.interrupt();
+        }
+        if (seedingThread != null)
+        {
+          seedingThread.interrupt();
+        }
+        if (idleCleanupThread != null)
+        {
+          idleCleanupThread.interrupt();
         }
-      }
-      if (jobResetThread != null)
-      {
-        jobResetThread.interrupt();
-      }
-      if (seedingThread != null)
-      {
-        seedingThread.interrupt();
-      }
-      if (idleCleanupThread != null)
-      {
-        idleCleanupThread.interrupt();
-      }
 
-      // Now, wait for all threads to die.
-      try
-      {
-        LCF.sleep(1000L);
-      }
-      catch (InterruptedException e)
-      {
-      }
+        // Now, wait for all threads to die.
+        try
+        {
+          LCF.sleep(1000L);
+        }
+        catch (InterruptedException e)
+        {
+        }
 
-      // Check to see which died.
-      if (initializationThread != null)
-      {
-        if (!initializationThread.isAlive())
-          initializationThread = null;
-      }
-      if (setPriorityThread != null)
-      {
-        if (!setPriorityThread.isAlive())
-          setPriorityThread = null;
-      }
-      if (jobDeleteThread != null)
-      {
-        if (!jobDeleteThread.isAlive())
-          jobDeleteThread = null;
-      }
-      if (startupThread != null)
-      {
-        if (!startupThread.isAlive())
-          startupThread = null;
-      }
-      if (jobStartThread != null)
-      {
-        if (!jobStartThread.isAlive())
-          jobStartThread = null;
-      }
-      if (stufferThread != null)
-      {
-        if (!stufferThread.isAlive())
-          stufferThread = null;
-      }
-      if (expireStufferThread != null)
-      {
-        if (!expireStufferThread.isAlive())
-          expireStufferThread = null;
-      }
-      if (finisherThread != null)
-      {
-        if (!finisherThread.isAlive())
-          finisherThread = null;
-      }
-      if (workerThreads != null)
-      {
-        int i = 0;
-        boolean isAlive = false;
-        while (i < workerThreads.length)
+        // Check to see which died.
+        if (initializationThread != null)
+        {
+          if (!initializationThread.isAlive())
+            initializationThread = null;
+        }
+        if (setPriorityThread != null)
+        {
+          if (!setPriorityThread.isAlive())
+            setPriorityThread = null;
+        }
+        if (jobDeleteThread != null)
         {
-          Thread workerThread = workerThreads[i];
-          if (workerThread != null)
+          if (!jobDeleteThread.isAlive())
+            jobDeleteThread = null;
+        }
+        if (startupThread != null)
+        {
+          if (!startupThread.isAlive())
+            startupThread = null;
+        }
+        if (jobStartThread != null)
+        {
+          if (!jobStartThread.isAlive())
+            jobStartThread = null;
+        }
+        if (stufferThread != null)
+        {
+          if (!stufferThread.isAlive())
+            stufferThread = null;
+        }
+        if (expireStufferThread != null)
+        {
+          if (!expireStufferThread.isAlive())
+            expireStufferThread = null;
+        }
+        if (finisherThread != null)
+        {
+          if (!finisherThread.isAlive())
+            finisherThread = null;
+        }
+        if (workerThreads != null)
+        {
+          int i = 0;
+          boolean isAlive = false;
+          while (i < workerThreads.length)
           {
-            if (!workerThread.isAlive())
-              workerThreads[i] = null;
-            else
-              isAlive = true;
+            Thread workerThread = workerThreads[i];
+            if (workerThread != null)
+            {
+              if (!workerThread.isAlive())
+                workerThreads[i] = null;
+              else
+                isAlive = true;
+            }
+            i++;
           }
-          i++;
+          if (!isAlive)
+            workerThreads = null;
         }
-        if (!isAlive)
-          workerThreads = null;
-      }
 
-      if (expireThreads != null)
-      {
-        int i = 0;
-        boolean isAlive = false;
-        while (i < expireThreads.length)
+        if (expireThreads != null)
         {
-          Thread expireThread = expireThreads[i];
-          if (expireThread != null)
+          int i = 0;
+          boolean isAlive = false;
+          while (i < expireThreads.length)
           {
-            if (!expireThread.isAlive())
-              expireThreads[i] = null;
-            else
-              isAlive = true;
+            Thread expireThread = expireThreads[i];
+            if (expireThread != null)
+            {
+              if (!expireThread.isAlive())
+                expireThreads[i] = null;
+              else
+                isAlive = true;
+            }
+            i++;
           }
-          i++;
+          if (!isAlive)
+            expireThreads = null;
         }
-        if (!isAlive)
-          expireThreads = null;
-      }
 
-      if (deleteStufferThread != null)
-      {
-        if (!deleteStufferThread.isAlive())
-          deleteStufferThread = null;
-      }
-      if (deleteThreads != null)
-      {
-        int i = 0;
-        boolean isAlive = false;
-        while (i < deleteThreads.length)
+        if (deleteStufferThread != null)
+        {
+          if (!deleteStufferThread.isAlive())
+            deleteStufferThread = null;
+        }
+        if (deleteThreads != null)
         {
-          Thread deleteThread = deleteThreads[i];
-          if (deleteThread != null)
+          int i = 0;
+          boolean isAlive = false;
+          while (i < deleteThreads.length)
           {
-            if (!deleteThread.isAlive())
-              deleteThreads[i] = null;
-            else
-              isAlive = true;
+            Thread deleteThread = deleteThreads[i];
+            if (deleteThread != null)
+            {
+              if (!deleteThread.isAlive())
+                deleteThreads[i] = null;
+              else
+                isAlive = true;
+            }
+            i++;
           }
-          i++;
+          if (!isAlive)
+            deleteThreads = null;
+        }
+        if (jobResetThread != null)
+        {
+          if (!jobResetThread.isAlive())
+            jobResetThread = null;
+        }
+        if (seedingThread != null)
+        {
+          if (!seedingThread.isAlive())
+            seedingThread = null;
+        }
+        if (idleCleanupThread != null)
+        {
+          if (!idleCleanupThread.isAlive())
+            idleCleanupThread = null;
         }
-        if (!isAlive)
-          deleteThreads = null;
-      }
-      if (jobResetThread != null)
-      {
-        if (!jobResetThread.isAlive())
-          jobResetThread = null;
-      }
-      if (seedingThread != null)
-      {
-        if (!seedingThread.isAlive())
-          seedingThread = null;
-      }
-      if (idleCleanupThread != null)
-      {
-        if (!idleCleanupThread.isAlive())
-          idleCleanupThread = null;
       }
-    }
 
-    // Threads are down; release connectors
-    RepositoryConnectorFactory.closeAllConnectors(threadContext);
-    numWorkerThreads = 0;
-    numDeleteThreads = 0;
-    numExpireThreads = 0;
+      // Threads are down; release connectors
+      RepositoryConnectorFactory.closeAllConnectors(threadContext);
+      numWorkerThreads = 0;
+      numDeleteThreads = 0;
+      numExpireThreads = 0;
+    }
   }
 
   /** Atomically export the crawler configuration */



Mime
View raw message