Bug 35528 - When I check out a project from CVS, Updating takes a very long time
Summary: When I check out a project from CVS, Updating takes a very long time
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.1   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 2.1.1   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 35859 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-03-21 18:17 EST by Raj Mandayam CLA
Modified: 2003-06-10 10:23 EDT (History)
2 users (show)

See Also:


Attachments
Proposed implementation as an attachment (3.34 KB, text/plain)
2003-04-09 07:06 EDT, Philipe Mulet CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Raj Mandayam CLA 2003-03-21 18:17:10 EST
This problem occurs in 2.0.2 & 2.1
Firstly I import a number of plugins from wsad build. Then I delete one plugin
and try to get that plugin as a source from my CVS repository.

The dialog initially says "Checking out the project" the project, clearly stalls
in the stage "Updating". The process takes 10 minutes. Only after that the
dialog displays "Invoking Java Builder" and completes. 
Even after that when I delete this project from the workspace it will take the
same duration of time in the stage "Updating"

I printed the java core during this  and this is what I get

---------------------- Exception Information ---------------------------
No Exception
 
---------------------- System Properties -------------------------------
J2RE 1.3.1 IBM Windows 32 build cn131-20020710
..
..
...
---------------------- XM component Dump Routine  ----------------------
Full thread dump Classic VM (J2RE 1.3.1 IBM Windows 32 build cn131-20020710,
native threads):
    "ModalContext" (TID:0x7E6EB28, sys_thread_t:0x3610B7F8, state:R, native
ID:0x5D4) prio=5
	at
org.eclipse.jdt.internal.core.JavaProject.updateAllCycleMarkers(JavaProject.java:2258)
	at
org.eclipse.jdt.internal.core.DeltaProcessor.updateClasspathMarkers(DeltaProcessor.java:1916)
	at
org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:1648)
	at
org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:137)
	at
org.eclipse.core.internal.runtime.InternalPlatform.run(InternalPlatform.java(Compiled
Code))
	at org.eclipse.core.runtime.Platform.run(Platform.java(Compiled Code))
	at
org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java(Compiled
Code))
	at
org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:67)
	at
org.eclipse.core.internal.resources.Workspace.broadcastChanges(Workspace.java:161)
	at
org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java(Compiled
Code))
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java(Compiled Code))
	at
org.eclipse.ui.actions.WorkspaceModifyOperation.run(WorkspaceModifyOperation.java:79)
	at
org.eclipse.team.internal.ccvs.ui.repo.RepositoryManager.run(RepositoryManager.java:785)
	at org.eclipse.team.internal.ccvs.ui.actions.CVSAction$1.run(CVSAction.java:242)
	at
org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:95)
    "Snapshot" (TID:0x64BC310, sys_thread_t:0x3602B360, state:CW, native
ID:0x4C4) prio=5
	at java.lang.Object.wait(Native Method)
	at
org.eclipse.core.internal.resources.DelayedSnapshotRunnable.run(DelayedSnapshotRunnable.java:38)
	at java.lang.Thread.run(Thread.java:512)
    "Decoration" (TID:0x16FA908, sys_thread_t:0x35E6F608, state:CW, native
ID:0x5C4) prio=1
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:429)
	at
org.eclipse.ui.internal.decorators.DecorationScheduler.next(DecorationScheduler.java:244)
	at
org.eclipse.ui.internal.decorators.DecorationScheduler$3.run(DecorationScheduler.java:270)
	at java.lang.Thread.run(Thread.java:512)
    "Java indexing" (TID:0x9001A0, sys_thread_t:0x34F3CC68, state:CW, native
ID:0x5A4) prio=4
	at java.lang.Thread.sleep(Native Method)
	at
org.eclipse.jdt.internal.core.search.processing.JobManager.run(JobManager.java(Compiled
Code))
	at java.lang.Thread.run(Thread.java:512)
    "Finalizer" (TID:0x901900, sys_thread_t:0x89B330, state:CW, native ID:0x5B8)
prio=8
	at java.lang.Object.wait(Native Method)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java(Compiled Code))
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java(Compiled Code))
    "Reference Handler" (TID:0x901948, sys_thread_t:0x8993C0, state:CW, native
ID:0x4E0) prio=10
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java(Compiled Code))
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java(Compiled Code))
    "Signal dispatcher" (TID:0x901990, sys_thread_t:0x892520, state:R, native
ID:0x378) prio=5
    "main" (TID:0x9019D8, sys_thread_t:0x7B0388, state:R, native ID:0x5DC) prio=5
	at org.eclipse.swt.internal.win32.OS.WaitMessage(Native Method)
	at org.eclipse.swt.widgets.Display.sleep(Display.java(Compiled Code))
	at
org.eclipse.jface.operation.ModalContext$ModalContextThread.block(ModalContext.java(Compiled
Code))
	at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:255)
	at
org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:351)
	at org.eclipse.team.internal.ccvs.ui.actions.CVSAction.run(CVSAction.java:262)
	at
org.eclipse.team.internal.ccvs.ui.actions.AddToWorkspaceAction.checkoutSelectionIntoWorkspaceDirectory(AddToWorkspaceAction.java:64)
	at
org.eclipse.team.internal.ccvs.ui.actions.AddToWorkspaceAction.execute(AddToWorkspaceAction.java:60)
	at org.eclipse.team.internal.ccvs.ui.actions.CVSAction.run(CVSAction.java:69)
	at org.eclipse.ui.actions.ActionDelegate.runWithEvent(ActionDelegate.java:71)
	at org.eclipse.ui.internal.PluginAction.runWithEvent(PluginAction.java:240)
	at
org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:456)
	at
org.eclipse.jface.action.ActionContributionItem.handleWidgetEvent(ActionContributionItem.java:403)
	at
org.eclipse.jface.action.ActionContributionItem.access$0(ActionContributionItem.java:397)
	at
org.eclipse.jface.action.ActionContributionItem$ActionListener.handleEvent(ActionContributionItem.java:72)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java(Compiled Code))
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java(Compiled Code))
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java(Compiled Code))
	at org.eclipse.ui.internal.Workbench.run(Workbench.java:1254)
	at
org.eclipse.core.internal.boot.InternalBootLoader.run(InternalBootLoader.java:845)
	at org.eclipse.core.boot.BootLoader.run(BootLoader.java:461)
	at java.lang.reflect.Method.invoke(Native Method)
	at org.eclipse.core.launcher.Main.basicRun(Main.java:247)
	at org.eclipse.core.launcher.Main.run(Main.java:703)
	at org.eclipse.core.launcher.Main.main(Main.java:539)
---------------------- LK component Dump Routine  ----------------------
Monitor pool info:
  Initial monitor count: 32
  Minimum number of free monitors before expansion: 5
  Pool will next be expanded by: 16
  Current total number of monitors: 32
  Current number of free monitors: 21
Monitor Pool Dump (flat & inflated object-monitors):
  sys_mon_t:0x0023F6B0 infl_mon_t: 0x0023F2A0:
    java.lang.ref.Reference$Lock@912550/912558: <unowned>
	Waiting to be notified:
	    "Reference Handler" (0x8993C0)
  sys_mon_t:0x0023F700 infl_mon_t: 0x0023F2E0:
    java.lang.ref.ReferenceQueue$Lock@912160/912168: <unowned>
	Waiting to be notified:
	    "Finalizer" (0x89B330)
  sys_mon_t:0x0023F728 infl_mon_t: 0x0023F300:
    org.eclipse.ui.internal.decorators.DecorationScheduler@15E8EA8/15E8EB0:
<unowned>
	Waiting to be notified:
	    "Decoration" (0x35E6F608)
  sys_mon_t:0x0023F8E0 infl_mon_t: 0x0023F460:
    org.eclipse.core.internal.resources.DelayedSnapshotRunnable@A2E770/A2E778:
<unowned>
	Waiting to be notified:
	    "Snapshot" (0x3602B360)
JVM System Monitor Dump (registered monitors):
    Evacuation Region lock: <unowned>
    Heap Promotion lock: <unowned>
    Sleep lock: <unowned>
	Waiting to be notified:
	    "Java indexing" (0x34F3CC68)
    Method trace lock: <unowned>
    Heap lock: owner "Signal dispatcher" (0x892520), entry count 1
    Monitor Cache lock: owner "Signal dispatcher" (0x892520), entry count 1
    JNI Pinning lock: <unowned>
    JNI Global Reference lock: <unowned>
    Classloader lock: <unowned>
    Binclass lock: <unowned>
    Monitor Registry lock: owner "Signal dispatcher" (0x892520), entry count 1
    Thread queue lock: owner "Signal dispatcher" (0x892520), entry count 1
Thread identifiers (as used in flat monitors):
    ident 0x08 "ModalContext" (0x3610B7F8) ee 0x3610B5E8
    ident 0x09 "Snapshot" (0x3602B360) ee 0x3602B150
    ident 0x07 "Decoration" (0x35E6F608) ee 0x35E6F3F8
    ident 0x06 "Java indexing" (0x34F3CC68) ee 0x34F3CA58
    ident 0x05 "Finalizer" (0x89B330) ee 0x0089B120
    ident 0x04 "Reference Handler" (0x8993C0) ee 0x008991B0
    ident 0x03 "Signal dispatcher" (0x892520) ee 0x00892310
    ident 0x02 "main" (0x7B0388) ee 0x007B0178
Java Object Monitor Dump (flat & inflated object-monitors):
    java.lang.ref.ReferenceQueue$Lock@912160/912168
        locknflags 80000400 Monitor inflated infl_mon 0x0023F2E0
    java.lang.ref.Reference$Lock@912550/912558
        locknflags 80000200 Monitor inflated infl_mon 0x0023F2A0
    org.eclipse.core.internal.resources.DelayedSnapshotRunnable@A2E770/A2E778
        locknflags 80001000 Monitor inflated infl_mon 0x0023F460
    org.eclipse.ui.internal.decorators.DecorationScheduler@15E8EA8/15E8EB0
        locknflags 80000500 Monitor inflated infl_mon 0x0023F300
    org.eclipse.team.internal.ccvs.ui.actions.AddToWorkspaceAction$1@7EA4770/7EA4778
        locknflags 00080000 Flat locked by thread ident 0x08, entry count 1
---------------------- END OF DUMP -------------------------------------


I think it is the following which takes that long.
	at
org.eclipse.jdt.internal.core.JavaProject.updateAllCycleMarkers(JavaProject.java:2258)
	at
org.eclipse.jdt.internal.core.DeltaProcessor.updateClasspathMarkers(DeltaProcessor.java:1916)
	at
org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:1648)
	at
org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:137)

This is a real performance bottleneck.  I can reproduce this scenario as many
times as possible therefore its not merely circumstantial.
Comment 1 Philipe Mulet CLA 2003-03-22 04:41:05 EST
Did you use 2.0.2 to produce the thread dump ? In 2.1, we think we have 
improved the cycle detection significantly.

Also we would need exact steps to reproduce. What you are doing is close to 
what we do when developping Eclipse and we have not seen problems in 2.1 (in 
2.0.2 it was a performance issue).
Comment 2 Raj Mandayam CLA 2003-03-24 04:30:42 EST
Hi Philippe,

Problem:

I import a lot of plugins to my Eclipse RC2 environment (problem occurs in 2.0.2
(Here it is even slower,as you have mentioned earlier) & RC1 as well)
After I do that. I delete two projects, connect to my CVS repository and select the 
same two projects and retrieve them from the repository (where I have the source). 
The dialog is popped up which, after retreiving the files, tries to update
classpaths.
This stage of the operation takes almost 10 minutes displaying "Updating". 

The thread stack trace reveals

Full thread dump Classic VM (J2RE 1.3.1 IBM Windows 32 build cn131-20020710,
native threads):
    "ModalContext" (TID:0x2FF9390, sys_thread_t:0x36D9F900, state:R, native
ID:0x3B8) prio=5
	at
org.eclipse.jdt.internal.core.JavaProject.updateAllCycleMarkers(JavaProject.java:2272)
	at
org.eclipse.jdt.internal.core.DeltaProcessor.updateClasspathMarkers(DeltaProcessor.java:1949)
	at
org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:1686)
	at
org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:137)
	at
org.eclipse.core.internal.runtime.InternalPlatform.run(InternalPlatform.java(Compiled
Code))
	at org.eclipse.core.runtime.Platform.run(Platform.java(Compiled Code))
	at
org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:152)
	at
org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:67)
	at
org.eclipse.core.internal.resources.Workspace.broadcastChanges(Workspace.java:161)
	at
org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java(Compiled
Code))
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java(Compiled Code))
	at
org.eclipse.ui.actions.WorkspaceModifyOperation.run(WorkspaceModifyOperation.java:79)
	at
org.eclipse.team.internal.ccvs.ui.repo.RepositoryManager.run(RepositoryManager.java:790)
	at org.eclipse.team.internal.ccvs.ui.actions.CVSAction$1.run(CVSAction.java:242)
	at
org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:95)

After essentially setting up a development environment to launch Eclipse, I
performed the same
steps as above from my Runtime Workbench and found that the operation was taking
an inordinate amount of time in

executing 
	at
org.eclipse.jdt.internal.core.JavaProject.updateAllCycleMarkers(JavaProject.java:2272)

This method is used to perform cycle detection when traversing classpaths of
each project in the workspace.

The following segment of the code 

		for (int i = 0; i < length; i++){
			JavaProject project = (JavaProject)projects[i];
			if (!cycleParticipants.contains(project)){
				visited.clear();
				project.updateCycleParticipants(null, visited, cycleParticipants,
workspaceRoot);
			}
		}


Here, for each project a cycle detection algorithm is run and the cycle
participants are stored in a HashSet "cycleParticipants"
The method project.updateCycleParticipants performs the core operation.

In the method updateCycleParticipants

	public void updateCycleParticipants(IClasspathEntry[] preferredClasspath,
ArrayList visited, HashSet cycleParticipants, IWorkspaceRoot workspaceRoot){
		visited.add(this);
		try {
			IClasspathEntry[] classpath = preferredClasspath == null ?
getResolvedClasspath(true) : preferredClasspath;
			for (int i = 0, length = classpath.length; i < length; i++) {
				IClasspathEntry entry = classpath[i];
				
				if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
					IPath entryPath = entry.getPath();
					IResource member = workspaceRoot.findMember(entryPath);
					if (member != null && member.getType() == IResource.PROJECT){
						JavaProject project = (JavaProject)JavaCore.create((IProject)member);
						int index = visited.indexOf(project);
						if (index == -1 && cycleParticipants.contains(project))
							index = visited.indexOf(this); // another loop in the cycle exists
						if (index >= 0) { // only consider direct participants inside the cycle
							for (int size = visited.size(); index < size; index++)
								cycleParticipants.add(visited.get(index)); 
						} else {
							project.updateCycleParticipants(null, visited, cycleParticipants,
workspaceRoot);
						}
					}
				}
			}
		} catch(JavaModelException e){
		}
		visited.remove(this);
	}


This method as seen maintains two objects a ArrayList named "visited" & the
HashSet "cycleParticipants". It's a recursive method and
what this method does is that it retrieves the classpath entries for the current
project and for each entry that is of type "PROJECT"
It checks to see if its on its "visited" list, If it is then it forms a cycle
and the method adds the project (classpath entry) to the list of cycleParticipants

As seen above these two methods since they are recursive they would encounter
the same project again and again, Note that some effort at optimizing
has been made by ensuring that if a project is already part of the
cycleParticipant then project.updateCycleParticipants(..) is not called.
But there is one problem that has been overlooked, projects whose classpath
entries have been already been visited can be marked as "doneTraversing" and
need not
be analyzed later when another project has this project as its classpath entry.  

To illustrate the problem,  if 

   A  --> B  ---> C --> D --> E-..>
          |             |
          |-------------

  If you are traversing the path  A->B->C->D->E. Once you have finished visiting
project "D" & its classpath entries (in this case "E")
  There is no need to visit the project "D" when traversing the path
A->B->D->E..>  because D has already been exhausted. 

Infact Since the code segment already checks, if cycleParticipants includes a
project, 
so if it doesn't include the project then
  we do not need to call project.updateCyc... 
     if the project has already been "doneTraversing". 

So we do not lose genuine cycle participants as well.
  

When I did that the it went a long way to reducing the amount of time this
method was taking. It took 10 seconds for the above case instead of minutes.

To do that, I added another HashSet named "doneTraversing". At the end of
project.updateCycleParticipants(..) when one has finished analyzing the current
project and
all of its classpath entries, this project can be added to "doneTraversing".
Therefore if we encounter the same project later in another classpath entry one
need not call
the project.updateCycleParticipants(..)

The following code is what I had to do 

	public static void updateAllCycleMarkers() throws JavaModelException {
		...
		
		HashSet doneTraversing = new HashSet;
		ArrayList visited = new ArrayList();

		for (int i = 0; i < length; i++){
			JavaProject project = (JavaProject)projects[i];
			if (!cycleParticipants.contains(project) && !doneTraversing.contains(project)){
				visited.clear();
				project.updateCycleParticipants(null, visited, cycleParticipants,
workspaceRoot, doneTraversing);
			}
		}
                doneTraversing.clear(); //flush out
		...
	}
		
&

	public void updateCycleParticipants(IClasspathEntry[] preferredClasspath,
ArrayList visited, HashSet cycleParticipants, IWorkspaceRoot workspaceRoot,
HashSet doneTraversing){
		visited.add(this);
		try {
			IClasspathEntry[] classpath = preferredClasspath == null ?
getResolvedClasspath(true) : preferredClasspath;
			for (int i = 0, length = classpath.length; i < length; i++) {
				IClasspathEntry entry = classpath[i];
				
				if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
					IPath entryPath = entry.getPath();
					IResource member = workspaceRoot.findMember(entryPath);
					if (member != null && member.getType() == IResource.PROJECT){
						JavaProject project = (JavaProject)JavaCore.create((IProject)member);
						int index = visited.indexOf(project);
						if (index == -1 && cycleParticipants.contains(project))
							index = visited.indexOf(this); // another loop in the cycle exists
						if (index >= 0) { // only consider direct participants inside the cycle
							for (int size = visited.size(); index < size; index++)
								cycleParticipants.add(visited.get(index)); 
						} else {
							if(!doneTraversing.contains(project))
								project.updateCycleParticipants(null, visited, cycleParticipants,
workspaceRoot);
						}
					}
				}
			}
		} catch(JavaModelException e){
		}
		visited.remove(this);

		doneTraversing.add(this);
	}

The above was happening because I had 180 projects in my workspace and almost
many of them have "org.eclipse.core.boot" & "org.eclipse.core.runtime"
"org..xerces" in their classpath
so the method ended up trying to detect cycles and ended up with 10 levels of
recursive calls for the method "updateCycleParticipants"

The above is just a rudimentary fix. I don't know if there is some drawback to
this approach or something Iam overlooking as I said I checked it with some
scenarios and it 
did not eliminate any genuine cycle participants.

Please let me know if the above is useful in fixing the problem.
Comment 3 Philipe Mulet CLA 2003-03-24 08:44:59 EST
This feels like a good performance improvement. We should not only cache cycle 
participants (which is fairly rare in general).
Comment 4 Philipe Mulet CLA 2003-03-25 07:00:32 EST
When building a WSAD workspace with *.nl1 circular plugin fragments (bug in 
PDE?), the fix proposal improves the speed considerably, however some of the 
cycle detection doesn't occur any longer. Need to investigate.
Comment 5 Philipe Mulet CLA 2003-03-25 08:54:04 EST
Steps:
- import all plugins from WSAD (~760 binary projects) with cycle severity 
turned as warning
- observe that lots of cycle warnings got generated (due to *.nl1 projects)
- import Eclipse SDK to refresh existing projects
- observe that all cycle markers are gone, though those outside Eclipse 
projects should have persisted
- change some classpath to introduce a cycle, then all cycle markers reappear.

Need to find a smaller testcase.
Comment 6 Philipe Mulet CLA 2003-03-31 04:32:08 EST
*** Bug 35859 has been marked as a duplicate of this bug. ***
Comment 7 Philipe Mulet CLA 2003-04-09 07:03:35 EDT
Following cycle detection code seems to have the good performance 
characteristics, and not causing mentionned grief:

/**
 * Update cycle markers for all java projects
 */
public static void updateAllCycleMarkers() throws JavaModelException {
	
	JavaModelManager manager = JavaModelManager.getJavaModelManager();
	IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
	IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();

	HashSet cycleParticipants = new HashSet();
	HashSet alreadyTraversed = new HashSet();
	int length = projects.length;
	
	// compute cycle participants
	ArrayList prereqChain = new ArrayList();
	for (int i = 0; i < length; i++){
		JavaProject project = (JavaProject)projects[i];
		if (!alreadyTraversed.contains(project)){
			prereqChain.clear();
			project.updateCycleParticipants(null, prereqChain, 
cycleParticipants, workspaceRoot, alreadyTraversed);
		}
	}
	
	for (int i = 0; i < length; i++){
		JavaProject project = (JavaProject)projects[i];
		
		if (cycleParticipants.contains(project)){
			IMarker cycleMarker = project.getCycleMarker();
			String circularCPOption = project.getOption
(JavaCore.CORE_CIRCULAR_CLASSPATH, true);
			int circularCPSeverity = JavaCore.ERROR.equals
(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING;
			if (cycleMarker != null) {
				// update existing cycle marker if needed
				try {
					int existingSeverity = ((Integer)
cycleMarker.getAttribute(IMarker.SEVERITY)).intValue();
					if (existingSeverity != 
circularCPSeverity) {
						cycleMarker.setAttribute
(IMarker.SEVERITY, circularCPSeverity);
					}
				} catch (CoreException e) {
					throw new JavaModelException(e);
				}
			} else {
				// create new marker
				project.createClasspathProblemMarker(
					new JavaModelStatus
(IJavaModelStatusConstants.CLASSPATH_CYCLE, project)); 
			}
		} else {
			project.flushClasspathProblemMarkers(true, false);
		}			
	}
}

/**
 * If a cycle is detected, then cycleParticipants contains all the project 
involved in this cycle (directly and indirectly),
 * no cycle if the set is empty (and started empty)
 */
public void updateCycleParticipants(
		IClasspathEntry[] preferredClasspath, 
		ArrayList prereqChain, 
		HashSet cycleParticipants, 
		IWorkspaceRoot workspaceRoot,
		HashSet alreadyTraversed){
			
	prereqChain.add(this);
	try {
		IClasspathEntry[] classpath = preferredClasspath == null ? 
getResolvedClasspath(true) : preferredClasspath;
		for (int i = 0, length = classpath.length; i < length; i++) {
			IClasspathEntry entry = classpath[i];
			
			if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
{
				IPath entryPath = entry.getPath();
				IResource member = workspaceRoot.findMember
(entryPath);
				if (member != null && member.getType() == 
IResource.PROJECT){
					JavaProject project = (JavaProject)
JavaCore.create((IProject)member);
					int index = cycleParticipants.contains
(project) ? 0 : prereqChain.indexOf(project);
					if (index >= 0) { // refer to cycle, or 
in cycle itself
						for (int size = prereqChain.size
(); index < size; index++) {
							cycleParticipants.add
(prereqChain.get(index)); 
						}
					} else {
						if (!alreadyTraversed.contains
(project)) {
						
	project.updateCycleParticipants(null, prereqChain, cycleParticipants, 
workspaceRoot, alreadyTraversed);
						}
					}
				}
			}
		}
	} catch(JavaModelException e){
	}
	prereqChain.remove(this);
	alreadyTraversed.add(this);
}
Comment 8 Philipe Mulet CLA 2003-04-09 07:06:23 EDT
Created attachment 4518 [details]
Proposed implementation as an attachment
Comment 9 Philipe Mulet CLA 2003-04-09 08:51:28 EDT
Released slightly better version, which doesn't create handle, but rather 
accumulate paths.

Fixed. 

Will also backport to 2.1 maintenance stream, and post a patch on JDT/Core 
update area shortly (http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%
7E/jdt-core-home/r2.1/main.html#updates).
Comment 10 Philipe Mulet CLA 2003-04-09 09:09:10 EDT
Backported to 2.1 maintenance stream.
Comment 11 Philipe Mulet CLA 2003-04-10 07:19:59 EDT
Also IJavaProject#hasClasspathCycle suffered from a similar performance issue.
Fixed by using the new updateCycleParticipants implementation instead.
Backported this extra fix too.
Comment 12 Jerome Lanneluc CLA 2003-04-15 10:46:14 EDT
Fixed in 2.2 stream as well.
Comment 13 David Audel CLA 2003-06-02 10:29:16 EDT
Verified.
Comment 14 David Audel CLA 2003-06-10 10:23:24 EDT
Verified for 3.0M1.