Community
Participate
Working Groups
Scenario: We have project migration jobs running in separate threads modifying the ".project" metadata. Our jobs use (workspace root) scheduling rules to lock access to the project files. We noticed that threads were spawned executing the SetClasspathOperation that doesn't have a scheduling rule, and it modifies the .project file - but because no lock is obtained, other threads can modify this file, and cause corruption. Here is a case where a JREUpdateJob is spawned: at org.eclipse.core.internal.resources.Project.setDescription(Project.java:949) at org.eclipse.core.internal.resources.Project.setDescription(Project.java:1062) at org.eclipse.jdt.internal.core.DeltaProcessingState$ProjectUpdateInfo.updateProjectReferencesIfNecessary(DeltaProcessingState.java:160) at org.eclipse.jdt.internal.core.DeltaProcessingState.updateProjectReferences(DeltaProcessingState.java:245) at org.eclipse.jdt.internal.core.SetClasspathOperation.updateProjectReferencesIfNecessary(SetClasspathOperation.java:804) at org.eclipse.jdt.internal.core.SetClasspathOperation.executeOperation(SetClasspathOperation.java:254) at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:720) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1737) at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:784) at org.eclipse.jdt.internal.core.JavaProject.setRawClasspath(JavaProject.java:3016) at org.eclipse.jdt.core.JavaCore$5.run(JavaCore.java:4215) at org.eclipse.jdt.internal.core.BatchOperation.executeOperation(BatchOperation.java:39) at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:720) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1737) at org.eclipse.jdt.core.JavaCore.run(JavaCore.java:4024) at org.eclipse.jdt.core.JavaCore.setClasspathContainer(JavaCore.java:4198) at org.eclipse.jdt.internal.launching.JREContainerInitializer.initialize(JREContainerInitializer.java:57) at org.eclipse.jdt.internal.launching.LaunchingPlugin$VMChanges.rebind(LaunchingPlugin.java:279) at org.eclipse.jdt.internal.launching.LaunchingPlugin$VMChanges.access$0(LaunchingPlugin.java:244) at org.eclipse.jdt.internal.launching.LaunchingPlugin$1.run(LaunchingPlugin.java:232) at org.eclipse.jdt.internal.core.BatchOperation.executeOperation(BatchOperation.java:39) at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:720) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1737) at org.eclipse.jdt.core.JavaCore.run(JavaCore.java:4024) at org.eclipse.jdt.internal.launching.LaunchingPlugin$VMChanges.doit(LaunchingPlugin.java:236) at org.eclipse.jdt.internal.launching.LaunchingPlugin$JREUpdateJob.run(LaunchingPlugin.java:316) The same time, our migration job, using a workspace root rule also falls into the same method, but is allowed to finish: at org.eclipse.core.internal.resources.Project.setDescription(Project.java:949) at org.eclipse.core.internal.resources.Project.setDescription(Project.java:1062) at com.ibm.etools.common.internal.migration.TacitMigrationEngine.migrateAllMappings(TacitMigrationEngine.java:228) at com.ibm.etools.common.internal.migration.TacitMigrationEngine.migrateAllMappings(TacitMigrationEngine.java:209) at com.ibm.etools.common.internal.migration.TacitMigrationOperation.execute(TacitMigrationOperation.java:105) at com.ibm.etools.common.frameworks.internal.datamodel.WTPOperation.doRun(WTPOperation.java:338) at com.ibm.etools.common.frameworks.internal.datamodel.WTPOperation$1.run(WTPOperation.java:250) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1737) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1719) at com.ibm.etools.common.frameworks.internal.datamodel.WTPOperation.run(WTPOperation.java:268) at com.ibm.etools.common.internal.migration.WorkspaceMigrationListener$1.run(WorkspaceMigrationListener.java:142) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37) at com.ibm.etools.common.internal.migration.WorkspaceMigrationListener$WorkspaceMigrationJob.run(WorkspaceMigrationListener.java:111) The JDT job then finishes, but with a "stale" IProjectDescription - corrupting the file, and erasing any changes from the migration job. Can the SetClasspathOperation use a scheduling rule? at least the IProject?
Created attachment 86655 [details] Proposed fix against R3_2_maintenance
Created attachment 86662 [details] Proposed fix against R3_3_maintenance and HEAD
Fix released in R3_2_maintenance stream. Note that there is no regression test since this is a concurrency problem.
Fix released for 3.4M5 in HEAD.
Requesting PMC approval to port to 3.3.2 since: - the bug causes a file corruption - there is no workaround for clients - the fix is simple - the fix is safe - there is no call out to client while we take the lock, so no deadlock can happen
+1 for 3.3.2
Fix released for 3.3.2 in R3_3_maintenance stream.
Verified in the code for 3.3.2 using M20080123-0800 build