[jbosstools-commits] JBoss Tools SVN: r39418 - trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl.

jbosstools-commits at lists.jboss.org jbosstools-commits at lists.jboss.org
Fri Mar 9 18:15:01 EST 2012


Author: scabanovich
Date: 2012-03-09 18:15:01 -0500 (Fri, 09 Mar 2012)
New Revision: 39418

Modified:
   trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/Libs.java
Log:
JBIDE-11188
https://issues.jboss.org/browse/JBIDE-11188
The update algorithm in Libs.updateFileSystems is fixed to provide its safe and correct completion when done concurrently by multiple threads.

Modified: trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/Libs.java
===================================================================
--- trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/Libs.java	2012-03-09 21:21:19 UTC (rev 39417)
+++ trunk/common/plugins/org.jboss.tools.common.model/src/org/jboss/tools/common/model/filesystems/impl/Libs.java	2012-03-09 23:15:01 UTC (rev 39418)
@@ -14,6 +14,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -26,7 +27,6 @@
 import org.eclipse.jdt.core.ElementChangedEvent;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.IElementChangedListener;
-import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaElementDelta;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
@@ -91,13 +91,20 @@
 			if(isExcludedStateChanged()) {
 				result = true;
 			}
-			if(result) fire();
-			if(paths == null && result) return true;
+			if(paths == null && result) {
+				fire();
+				return true;
+			}
+		}	
+	
+		if(paths != null && fsVersion < pathsVersion) {
+			updateFileSystems(paths, 0);
 		}
-	
-		if(paths != null) updateFileSystems(paths);
 		fsVersion = pathsVersion;
 
+		if(result) {
+			fire();
+		}
 		return result;
 	}
 
@@ -115,6 +122,16 @@
 			result = EclipseResourceUtil.getAllVisibleLibraries(getProjectResource());
 			List<String> jre = EclipseResourceUtil.getJREClassPath(getProjectResource());
 			if(jre != null) result.removeAll(jre);
+			if(result != null) {
+				Iterator<String> it = result.iterator();
+				while(it.hasNext()) {
+					String path = it.next();
+					String fileName = new File(path).getName();
+					if(EclipseResourceUtil.isJar(path) && EclipseResourceUtil.SYSTEM_JAR_SET.contains(fileName)) {
+						it.remove();
+					}
+				}
+			}
 			updateProjects();
 		} catch (CoreException e) {
 			ModelPlugin.getDefault().logError(e);
@@ -162,7 +179,7 @@
 				IPath[] ps = es[i].getExclusionPatterns();
 				if(ps != null && ps.length > 0) {
 					for (int j = 0; j < ps.length; j++) {
-						String key = p.toString() + "/" + ps[j].toString();
+						String key = p.toString() + "/" + ps[j].toString(); //$NON-NLS-1$
 						result += key.hashCode();
 					}
 				}
@@ -191,18 +208,28 @@
 	
 	public static String LIB_PREFIX = "lib-"; //$NON-NLS-1$
 
-	void updateFileSystems(List<String> paths) {
-		if(fsVersion >= pathsVersion) {
-			return;
-		}
-		
+	/**
+	 * This method is designed to run safe when invoked by several concurrent threads.
+	 * Each thread requesting file systems needs them up-to-date when this method returns.
+	 * If thread 1 is already running update, and thread 2 is going to request file systems,
+	 * it has to start this method independently, because it cannot rely on the other thread
+	 * completing before the file systems are obtained.
+	 * Synchronizing this method would involve high risk of a deadlock, 
+	 * concurrent modification is a better solution if implemented safely.
+	 * 
+	 * @param paths
+	 * @param iteration
+	 */
+	private void updateFileSystems(List<String> paths, int iteration) {
 		Set<String> oldPaths = libraryNames.getPaths();
 		for (String p: oldPaths) {
 			if(!paths.contains(p)) {
 				String n = libraryNames.getName(p);
-				XModelObject o = object.getChildByPath(n);
-				if(o != null) {
-					o.removeFromParent();
+				if(n != null) {
+					XModelObject o = object.getChildByPath(n);
+					if(o != null) {
+						o.removeFromParent();
+					}
 				}
 				libraryNames.removePath(p);
 			}
@@ -221,15 +248,7 @@
 			boolean isJar = EclipseResourceUtil.isJar(path);
 			String libEntity = isJar ? "FileSystemJar" : "FileSystemFolder"; //$NON-NLS-1$ //$NON-NLS-2$
 			String fileName = new File(path).getName();
-			if(isJar && EclipseResourceUtil.SYSTEM_JAR_SET.contains(fileName)) continue;
-			String jsname = libraryNames.getName(path);
-			if(jsname == null) {
-				jsname = LIB_PREFIX + fileName;
-				int q = 0;
-				while(libraryNames.hasName(jsname)) {
-					jsname = LIB_PREFIX + fileName + "-" + (++q); //$NON-NLS-1$
-				}				
-			}
+			String jsname = libraryNames.getExistingOrNewName(path, fileName);
 			XModelObject o = object.getChildByPath(jsname);
 			if(o != null) {
 				fss.remove(o);
@@ -255,6 +274,17 @@
 				o.removeFromParent();
 			}			
 		}
+
+		List<String> newPaths = this.paths;
+		if(newPaths != null && (paths != newPaths || !libraryNames.isValidList(newPaths))) {
+			if(iteration == 5) {
+				ModelPlugin.getDefault().logWarning("Iterative update of file systems for project " //$NON-NLS-1$
+					+ EclipseResourceUtil.getProject(object)
+					+ " is interrupted to prevent deadlock."); //$NON-NLS-1$
+			} else {
+				updateFileSystems(newPaths, iteration + 1);
+			}
+		}
 	}
 
 	public List<String> getPaths() {
@@ -312,8 +342,8 @@
 					return;
 				} else {
 					for (IJavaElementDelta d1: dc.getAffectedChildren()) {
-						IJavaElement e = d1.getElement();
-						if(d1.getKind() == IJavaElementDelta.ADDED) {
+//						IJavaElement e = d1.getElement();
+						if(d1.getKind() == IJavaElementDelta.ADDED || d1.getKind() == IJavaElementDelta.REMOVED) {
 							requestForUpdate();
 							return;
 						}
@@ -355,6 +385,18 @@
 		return pathToName.get(path);
 	}
 
+	public synchronized String getExistingOrNewName(String path, String fileName) {
+		String jsname = getName(path);
+		if(jsname == null) {
+			jsname = Libs.LIB_PREFIX + fileName;
+			int q = 0;
+			while(hasName(jsname)) {
+				jsname = Libs.LIB_PREFIX + fileName + "-" + (++q); //$NON-NLS-1$
+			}				
+		}
+		return jsname;
+	}
+
 	public String getPath(String name) {
 		return nameToPath.get(name);
 	}
@@ -366,4 +408,16 @@
 	public synchronized Set<String> getPaths() {
 		return new HashSet<String>(pathToName.keySet());
 	}
+
+	public synchronized boolean isValidList(List<String> paths) {
+		if(pathToName.size() != paths.size()) {
+			return false;
+		}
+		for (String p: paths) {
+			if(!pathToName.containsKey(p)) {
+				return false;
+			}
+		}
+		return true;
+	}
 }



More information about the jbosstools-commits mailing list