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 2012/12/27 08:03:50 UTC

svn commit: r1426134 - in /manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs: JobManager.java JobQueue.java TrackerClass.java

Author: kwright
Date: Thu Dec 27 07:03:49 2012
New Revision: 1426134

URL: http://svn.apache.org/viewvc?rev=1426134&view=rev
Log:
Partial inclusion of TrackerClass.

Added:
    manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java   (with props)
Modified:
    manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java
    manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobQueue.java

Modified: manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java?rev=1426134&r1=1426133&r2=1426134&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java (original)
+++ manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobManager.java Thu Dec 27 07:03:49 2012
@@ -639,12 +639,14 @@ public class JobManager implements IJobM
         // Clean up carrydown stuff
         carryDown.reset();
         database.performCommit();
+        TrackerClass.noteCommit();
         Logging.jobs.debug("Reset complete");
         break;
       }
       catch (ManifoldCFException e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         if (e.getErrorCode() == e.DATABASE_TRANSACTION_ABORT)
         {
           if (Logging.perf.isDebugEnabled())
@@ -657,6 +659,7 @@ public class JobManager implements IJobM
       catch (Error e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         throw e;
       }
       finally
@@ -681,11 +684,13 @@ public class JobManager implements IJobM
       {
         jobQueue.resetDocumentWorkerStatus();
         database.performCommit();
+        TrackerClass.noteCommit();
         break;
       }
       catch (ManifoldCFException e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         if (e.getErrorCode() == e.DATABASE_TRANSACTION_ABORT)
         {
           if (Logging.perf.isDebugEnabled())
@@ -698,6 +703,7 @@ public class JobManager implements IJobM
       catch (Error e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         throw e;
       }
       finally
@@ -726,6 +732,7 @@ public class JobManager implements IJobM
   {
     Logging.jobs.debug("Resetting doc deleting status");
     jobQueue.resetDocDeleteWorkerStatus();
+    TrackerClass.noteCommit();
     Logging.jobs.debug("Reset complete");
   }
 
@@ -736,6 +743,7 @@ public class JobManager implements IJobM
   {
     Logging.jobs.debug("Resetting doc cleaning status");
     jobQueue.resetDocCleanupWorkerStatus();
+    TrackerClass.noteCommit();
     Logging.jobs.debug("Reset complete");
   }
 
@@ -4145,6 +4153,7 @@ public class JobManager implements IJobM
           jobQueue.reactivateHopcountRemovedRecords(jobID);
 
         database.performCommit();
+        TrackerClass.noteCommit();
         
         if (Logging.perf.isDebugEnabled())
           Logging.perf.debug("Took "+new Long(System.currentTimeMillis()-startTime).toString()+" ms to add "+Integer.toString(reorderedDocIDHashes.length)+
@@ -4164,6 +4173,7 @@ public class JobManager implements IJobM
       catch (ManifoldCFException e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         if (e.getErrorCode() == e.DATABASE_TRANSACTION_ABORT)
         {
           sleepAmt = getRandomAmount();
@@ -4177,6 +4187,7 @@ public class JobManager implements IJobM
       catch (Error e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         throw e;
       }
       finally
@@ -5353,6 +5364,7 @@ public class JobManager implements IJobM
     // No special treatment needed for hopcount or carrydown, since these all get deleted at once
     // at the end of the job delete process.
     jobQueue.prepareDeleteScan(jobID);
+    TrackerClass.noteCommit();
   }
   
   /** Prepare for a full scan.
@@ -5386,11 +5398,13 @@ public class JobManager implements IJobM
 
         jobQueue.prepareFullScan(jobID);
         database.performCommit();
+        TrackerClass.noteCommit();
         break;
       }
       catch (ManifoldCFException e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         if (e.getErrorCode() == e.DATABASE_TRANSACTION_ABORT)
         {
           if (Logging.perf.isDebugEnabled())
@@ -5403,6 +5417,7 @@ public class JobManager implements IJobM
       catch (Error e)
       {
         database.signalRollback();
+        TrackerClass.noteRollback();
         throw e;
       }
       finally

Modified: manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobQueue.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobQueue.java?rev=1426134&r1=1426133&r2=1426134&view=diff
==============================================================================
--- manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobQueue.java (original)
+++ manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/JobQueue.java Thu Dec 27 07:03:49 2012
@@ -381,6 +381,8 @@ public class JobQueue extends org.apache
     // Reindex the jobqueue table, since we've probably made lots of bad tuples doing the above operations.
     reindexTable();
     unconditionallyAnalyzeTables();
+
+    TrackerClass.noteGlobalEvent("Restart");
   }
 
   /** Flip all records for a job that have status HOPCOUNTREMOVED back to PENDING.
@@ -398,6 +400,8 @@ public class JobQueue extends org.apache
       new UnitaryClause(jobIDField,jobID),
       new UnitaryClause(statusField,statusToString(STATUS_HOPCOUNTREMOVED))});
     performUpdate(map,"WHERE "+query,list,null);
+    
+    TrackerClass.noteJobEvent(jobID,"Map HOPCOUNTREMOVED to PENDING");
   }
 
   /** Delete all records for a job that have status HOPCOUNTREMOVED.
@@ -455,6 +459,8 @@ public class JobQueue extends org.apache
         statusToString(STATUS_ACTIVEPURGATORY),
         statusToString(STATUS_ACTIVENEEDRESCANPURGATORY)})});
     performUpdate(map,"WHERE "+query,list,null);
+        
+    TrackerClass.noteGlobalEvent("Reset document worker status");
   }
 
   /** Reset doc delete worker status.
@@ -470,6 +476,8 @@ public class JobQueue extends org.apache
     String query = buildConjunctionClause(list,new ClauseDescription[]{
       new UnitaryClause(statusField,statusToString(STATUS_BEINGDELETED))});
     performUpdate(map,"WHERE "+query,list,null);
+      
+    TrackerClass.noteGlobalEvent("Reset document delete worker status");
   }
 
   /** Reset doc cleaning worker status.
@@ -485,6 +493,8 @@ public class JobQueue extends org.apache
     String query = buildConjunctionClause(list,new ClauseDescription[]{
       new UnitaryClause(statusField,statusToString(STATUS_BEINGCLEANED))});
     performUpdate(map,"WHERE "+query,list,null);
+      
+    TrackerClass.noteGlobalEvent("Reset document cleanup worker status");
   }
 
   /** Prepare for a job delete pass.  This will not be called
@@ -535,6 +545,7 @@ public class JobQueue extends org.apache
     // Do an analyze, otherwise our plans are going to be crap right off the bat
     unconditionallyAnalyzeTables();
 
+    TrackerClass.noteJobEvent(jobID,"Prepare delete scan");
   }
   
   /** Prepare for a "full scan" job.  This will not be called
@@ -584,6 +595,8 @@ public class JobQueue extends org.apache
     noteModifications(0,2,0);
     // Do an analyze, otherwise our plans are going to be crap right off the bat
     unconditionallyAnalyzeTables();
+        
+    TrackerClass.noteJobEvent(jobID,"Prepare full scan");
   }
 
   /** Prepare for an "incremental" job.  This is called ONLY when the job is inactive;
@@ -613,6 +626,8 @@ public class JobQueue extends org.apache
     noteModifications(0,1,0);
     // Do an analyze, otherwise our plans are going to be crap right off the bat
     unconditionallyAnalyzeTables();
+      
+    TrackerClass.noteJobEvent(jobID,"Prepare incremental scan");
   }
 
   /** Delete ingested document identifiers (as part of deleting the owning job).
@@ -726,6 +741,7 @@ public class JobQueue extends org.apache
       // Leave doc priority unchanged.
       break;
     default:
+      TrackerClass.printForensics(recID, currentStatus);
       throw new ManifoldCFException("Unexpected jobqueue status - record id "+recID.toString()+", expecting active status, saw "+Integer.toString(currentStatus));
     }
 
@@ -738,6 +754,8 @@ public class JobQueue extends org.apache
     String query = buildConjunctionClause(list,new ClauseDescription[]{
       new UnitaryClause(idField,recID)});
     performUpdate(map,"WHERE "+query,list,null);
+      
+    TrackerClass.noteRecordEvent(recID, newStatus, "Note completion");
   }
 
   /** Either delete a record, or set status to "rescan", depending on the
@@ -767,6 +785,7 @@ public class JobQueue extends org.apache
       // Leave doc priority unchanged.
       break;
     default:
+      TrackerClass.printForensics(recID, currentStatus);
       throw new ManifoldCFException("Unexpected jobqueue status - record id "+recID.toString()+", expecting active status, saw "+Integer.toString(currentStatus));
     }
 
@@ -779,6 +798,7 @@ public class JobQueue extends org.apache
     String query = buildConjunctionClause(list,new ClauseDescription[]{
       new UnitaryClause(idField,recID)});
     performUpdate(map,"WHERE "+query,list,null);
+    TrackerClass.noteRecordEvent(recID, newStatus, "Rescan or delete");
     return false;
   }
 
@@ -815,6 +835,7 @@ public class JobQueue extends org.apache
       // Leave doc priority unchanged.
       break;
     default:
+      TrackerClass.printForensics(recID, currentStatus);
       throw new ManifoldCFException("Unexpected jobqueue status - record id "+recID.toString()+", expecting active status, saw "+Integer.toString(currentStatus));
     }
 
@@ -827,6 +848,7 @@ public class JobQueue extends org.apache
     String query = buildConjunctionClause(list,new ClauseDescription[]{
       new UnitaryClause(idField,recID)});
     performUpdate(map,"WHERE "+query,list,null);
+    TrackerClass.noteRecordEvent(recID, newStatus, "Update or hopcount remove");
     return rval;
   }
 
@@ -847,6 +869,7 @@ public class JobQueue extends org.apache
       newStatus = STATUS_ACTIVEPURGATORY;
       break;
     default:
+      TrackerClass.printForensics(id, currentStatus);
       throw new ManifoldCFException("Unexpected status value for jobqueue record "+id.toString()+"; got "+Integer.toString(currentStatus));
     }
 
@@ -857,6 +880,7 @@ public class JobQueue extends org.apache
       new UnitaryClause(idField,id)});
     performUpdate(map,"WHERE "+query,list,null);
     noteModifications(0,1,0);
+    TrackerClass.noteRecordEvent(id, newStatus, "Make active");
   }
 
   /** Set the status on a record, including check time and priority.
@@ -888,6 +912,7 @@ public class JobQueue extends org.apache
       new UnitaryClause(idField,id)});
     performUpdate(map,"WHERE "+query,list,null);
     noteModifications(0,1,0);
+    TrackerClass.noteRecordEvent(id, status, "Set status");
   }
 
   /** Set the status of a document to "being deleted".
@@ -902,6 +927,7 @@ public class JobQueue extends org.apache
       new UnitaryClause(idField,id)});
     performUpdate(map,"WHERE "+query,list,null);
     noteModifications(0,1,0);
+    TrackerClass.noteRecordEvent(id, STATUS_BEINGDELETED, "Set deleting status");
   }
 
   /** Set the status of a document to be "no longer deleting" */
@@ -919,6 +945,7 @@ public class JobQueue extends org.apache
       new UnitaryClause(idField,id)});
     performUpdate(map,"WHERE "+query,list,null);
     noteModifications(0,1,0);
+    TrackerClass.noteRecordEvent(id, STATUS_ELIGIBLEFORDELETE, "Set undeleting status");
   }
 
   /** Set the status of a document to "being cleaned".
@@ -933,6 +960,7 @@ public class JobQueue extends org.apache
       new UnitaryClause(idField,id)});
     performUpdate(map,"WHERE "+query,list,null);
     noteModifications(0,1,0);
+    TrackerClass.noteRecordEvent(id, STATUS_BEINGCLEANED, "Set cleaning status");
   }
 
   /** Set the status of a document to be "no longer cleaning" */
@@ -950,6 +978,7 @@ public class JobQueue extends org.apache
       new UnitaryClause(idField,id)});
     performUpdate(map,"WHERE "+query,list,null);
     noteModifications(0,1,0);
+    TrackerClass.noteRecordEvent(id, STATUS_PURGATORY, "Set uncleaning status");
   }
 
   /** Remove multiple records entirely.
@@ -1040,6 +1069,7 @@ public class JobQueue extends org.apache
     case STATUS_PURGATORY:
       // Set the status and time both
       map.put(statusField,statusToString(STATUS_PENDINGPURGATORY));
+      TrackerClass.noteRecordEvent(recordID, STATUS_PENDINGPURGATORY, "Update existing record initial");
       if (desiredExecuteTime == -1L)
         map.put(checkTimeField,new Long(0L));
       else
@@ -1130,6 +1160,7 @@ public class JobQueue extends org.apache
     performInsert(map,null);
     prereqEventManager.addRows(recordID,prereqEvents);
     noteModifications(1,0,0);
+    TrackerClass.noteRecordEvent(recordID, STATUS_PENDING, "Create initial");
   }
 
   /** Note the remaining documents that do NOT need to be queued.  These are noted so that the
@@ -1316,6 +1347,7 @@ public class JobQueue extends org.apache
     case STATUS_PURGATORY:
       // Set the status and time both
       map.put(statusField,statusToString(STATUS_PENDINGPURGATORY));
+      TrackerClass.noteRecordEvent(recordID, STATUS_PENDINGPURGATORY, "Update existing");
       map.put(checkTimeField,new Long(desiredExecuteTime));
       map.put(checkActionField,actionToString(ACTION_RESCAN));
       map.put(failTimeField,null);
@@ -1333,6 +1365,7 @@ public class JobQueue extends org.apache
         // The document has been processed before, so it has to go into PENDINGPURGATORY.
         // Set the status and time both
         map.put(statusField,statusToString(STATUS_PENDINGPURGATORY));
+        TrackerClass.noteRecordEvent(recordID, STATUS_PENDINGPURGATORY, "Update existing");
         map.put(checkTimeField,new Long(desiredExecuteTime));
         map.put(checkActionField,actionToString(ACTION_RESCAN));
         map.put(failTimeField,null);
@@ -1362,6 +1395,7 @@ public class JobQueue extends org.apache
         // Flip the state to the new one, and set the document priority at this time too - it will be preserved when the
         // processing is completed.
         map.put(statusField,statusToString(STATUS_ACTIVENEEDRESCAN));
+        TrackerClass.noteRecordEvent(recordID, STATUS_ACTIVENEEDRESCAN, "Update existing");
         map.put(checkTimeField,new Long(desiredExecuteTime));
         map.put(checkActionField,actionToString(ACTION_RESCAN));
         map.put(failTimeField,null);
@@ -1386,6 +1420,7 @@ public class JobQueue extends org.apache
         // Flip the state to the new one, and set the document priority at this time too - it will be preserved when the
         // processing is completed.
         map.put(statusField,statusToString(STATUS_ACTIVENEEDRESCANPURGATORY));
+        TrackerClass.noteRecordEvent(recordID, STATUS_ACTIVENEEDRESCANPURGATORY, "Update existing");
         map.put(checkTimeField,new Long(desiredExecuteTime));
         map.put(checkActionField,actionToString(ACTION_RESCAN));
         map.put(failTimeField,null);
@@ -1453,6 +1488,8 @@ public class JobQueue extends org.apache
     performInsert(map,null);
     prereqEventManager.addRows(recordID,prereqEvents);
     noteModifications(1,0,0);
+    TrackerClass.noteRecordEvent(recordID, STATUS_PENDING, "Create new");
+
   }
 
   // Methods to convert status strings to integers and back

Added: manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java
URL: http://svn.apache.org/viewvc/manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java?rev=1426134&view=auto
==============================================================================
--- manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java (added)
+++ manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java Thu Dec 27 07:03:49 2012
@@ -0,0 +1,279 @@
+/* $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.crawler.jobs;
+
+import java.util.*;
+
+/** Debugging class to keep track of recent modifications to the jobqueue table,
+* along with context as to where it occurred.  If a jobqueue state error occurs,
+* we can then print out all of the pertinent history and find the culprit.
+*/
+public class TrackerClass
+{
+  // The goal of this class is to keep track of at least the last two events
+  // potentially affecting each record.
+  
+  // Active transaction
+  protected final static Map<String,TransactionData> transactionData = new HashMap<String,TransactionData>();
+  
+  // Modification history
+  protected final static List<TransactionData> history = new ArrayList<TransactionData>();
+  
+  // Place where we keep track of individual modifications
+  private TrackerClass()
+  {
+  }
+  
+  /** Add a single record event, as yet uncommitted */
+  public static void noteRecordEvent(Long recordID, int newStatus, String description)
+  {
+    addEvent(new RecordEvent(recordID, newStatus, new Exception(description)));
+  }
+  
+  /** Add a global event, as yet uncommitted, which has the potential
+  * to affect any record's state in a given job.
+  */
+  public static void noteJobEvent(Long jobID, String description)
+  {
+    addEvent(new JobEvent(jobID, new Exception(description)));
+  }
+  
+  /** Add a global event, as yet uncommitted, which has the potential
+  * to affect the state of any record.
+  */
+  public static void noteGlobalEvent(String description)
+  {
+    addEvent(new GlobalEvent(new Exception(description)));
+  }
+  
+  protected static void addEvent(HistoryRecord hr)
+  {
+    String threadName = Thread.currentThread().getName();
+    TransactionData td;
+    synchronized (transactionData)
+    {
+      td = transactionData.get(threadName);
+      if (td == null)
+      {
+        td = new TransactionData();
+        transactionData.put(threadName,td);
+      }
+    }
+    td.addEvent(hr);
+  }
+  
+  /** Note a commit operation.
+  */
+  public static void noteCommit()
+  {
+    long currentTime = System.currentTimeMillis();
+    String threadName = Thread.currentThread().getName();
+    TransactionData td;
+    synchronized (transactionData)
+    {
+      td = transactionData.get(threadName);
+      transactionData.remove(threadName);
+    }
+    if (td == null)
+      return;
+    // Only keep stuff around for an hour
+    long removalCutoff = currentTime - (60000 * 60);
+    synchronized (history)
+    {
+      history.add(td);
+      // Clean out older records
+      while (history.size() > 0)
+      {
+        TransactionData td2 = history.get(0);
+        if (td2.isFlushable(removalCutoff))
+          history.remove(0);
+      }
+    }
+    
+  }
+  
+  /** Note a rollback operation.
+  */
+  public static void noteRollback()
+  {
+    String threadName = Thread.currentThread().getName();
+    synchronized (transactionData)
+    {
+      transactionData.remove(threadName);
+    }
+  }
+  
+  public static void printForensics(Long recordID, int existingStatus)
+  {
+    synchronized (transactionData)
+    {
+      synchronized (history)
+      {
+        System.out.println("---- Forensics for record "+recordID+", current status: "+existingStatus+" ----");
+        System.out.println("--Current stack trace--");
+        new Exception("Unexpected jobqueue status").printStackTrace();
+        System.out.println("--Active transactions--");
+        for (String threadName : transactionData.keySet())
+        {
+          for (HistoryRecord hr : transactionData.get(threadName).getEvents())
+          {
+            if (hr.applies(recordID))
+            {
+              System.out.println("Thread '"+threadName+"' was active:");
+              hr.print();
+            }
+          }
+        }
+        System.out.println("--Pertinent History--");
+        for (TransactionData td : history)
+        {
+          for (HistoryRecord hr : td.getEvents())
+          {
+            if (hr.applies(recordID))
+            {
+              hr.print();
+            }
+          }
+        }
+      }
+    }
+        
+  }
+  
+  protected static class TransactionData
+  {
+    protected final List<HistoryRecord> transactionEvents = new ArrayList<HistoryRecord>();
+    protected long timestamp;
+    
+    public TransactionData()
+    {
+      timestamp = System.currentTimeMillis();
+    }
+    
+    public void addEvent(HistoryRecord event)
+    {
+      transactionEvents.add(event);
+    }
+    
+    public List<HistoryRecord> getEvents()
+    {
+      return transactionEvents;
+    }
+    
+    public boolean isFlushable(long cutoffTime)
+    {
+      return cutoffTime > timestamp;
+    }
+  }
+  
+  protected abstract static class HistoryRecord
+  {
+    protected long timestamp;
+    protected Exception trace;
+    
+    public HistoryRecord(Exception trace)
+    {
+      this.trace = trace;
+      this.timestamp = System.currentTimeMillis();
+    }
+    
+    public void print()
+    {
+      System.out.println("  at "+new Long(timestamp)+", location: ");
+      trace.printStackTrace();
+    }
+    
+    public abstract boolean applies(Long recordID);
+    
+  }
+  
+  protected static class RecordEvent extends HistoryRecord
+  {
+    protected Long recordID;
+    protected int newStatus;
+    
+    public RecordEvent(Long recordID, int newStatus, Exception trace)
+    {
+      super(trace);
+      this.recordID = recordID;
+      this.newStatus = newStatus;
+    }
+    
+    @Override
+    public void print()
+    {
+      System.out.println("Record "+recordID+" status modified to "+newStatus);
+      super.print();
+    }
+    
+    @Override
+    public boolean applies(Long recordID)
+    {
+      return this.recordID.equals(recordID);
+    }
+
+  }
+  
+  protected static class JobEvent extends HistoryRecord
+  {
+    protected Long jobID;
+    
+    public JobEvent(Long jobID, Exception trace)
+    {
+      super(trace);
+      this.jobID = jobID;
+    }
+    
+    @Override
+    public void print()
+    {
+      System.out.println("All job related records modified for job "+jobID);
+      super.print();
+    }
+    
+    @Override
+    public boolean applies(Long recordID)
+    {
+      return true;
+    }
+  }
+  
+  protected static class GlobalEvent extends HistoryRecord
+  {
+    public GlobalEvent(Exception trace)
+    {
+      super(trace);
+    }
+    
+    @Override
+    public void print()
+    {
+      System.out.println("All records modified");
+      super.print();
+    }
+
+    @Override
+    public boolean applies(Long recordID)
+    {
+      return true;
+    }
+  }
+  
+}

Propchange: manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: manifoldcf/branches/CONNECTORS-590/framework/pull-agent/src/main/java/org/apache/manifoldcf/crawler/jobs/TrackerClass.java
------------------------------------------------------------------------------
    svn:keywords = Id