Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 308120 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/wst/sse/core/internal/model/ModelManagerImpl.java (-54 / +62 lines)
Lines 41-46 Link Here
41
import org.eclipse.core.runtime.IPath;
41
import org.eclipse.core.runtime.IPath;
42
import org.eclipse.core.runtime.IStatus;
42
import org.eclipse.core.runtime.IStatus;
43
import org.eclipse.core.runtime.NullProgressMonitor;
43
import org.eclipse.core.runtime.NullProgressMonitor;
44
import org.eclipse.core.runtime.OperationCanceledException;
44
import org.eclipse.core.runtime.Path;
45
import org.eclipse.core.runtime.Path;
45
import org.eclipse.core.runtime.Platform;
46
import org.eclipse.core.runtime.Platform;
46
import org.eclipse.core.runtime.QualifiedName;
47
import org.eclipse.core.runtime.QualifiedName;
Lines 97-177 Link Here
97
 */
98
 */
98
public class ModelManagerImpl implements IModelManager {
99
public class ModelManagerImpl implements IModelManager {
99
100
100
	private static long WAIT_INTERVAL_MS = 500; 
101
	
102
	
101
	static class ReadEditType {
103
	static class ReadEditType {
102
		ReadEditType(String type) {
104
		ReadEditType(String type) {
103
		}
105
		}
104
	}
106
	}
105
107
106
	/**
108
	class SharedObject {
107
	 * A Data class to track our shared objects
108
	 */
109
	 static class SharedObject {
110
		int referenceCountForEdit;
109
		int referenceCountForEdit;
111
		int referenceCountForRead;
110
		int referenceCountForRead;
112
		IStructuredModel theSharedModel;
111
		volatile IStructuredModel theSharedModel;
112
		final ILock LOAD_LOCK = Job.getJobManager().newLock();
113
		volatile boolean initializing = true;
113
		volatile boolean initializing = true;
114
		volatile boolean doWait = true;
114
		volatile boolean doWait = true;
115
		
115
		// The field 'id' is only meant for debug
116
		SharedObject(IStructuredModel sharedModel) {
116
		volatile String id;
117
			theSharedModel = sharedModel;
117
118
			referenceCountForRead = 0;
118
		SharedObject(String id) {
119
			referenceCountForEdit = 0;
119
			this.id=id;
120
			// be aware, this lock will leak and cause the deadlock detector to be horrible if we never release it
121
			LOAD_LOCK.acquire();
120
		}
122
		}
121
		
123
122
		/**
124
		/**
123
		 * Waits until this shared object has been attempted to be loaded. 
125
		 * Waits until this shared object has been attempted to be loaded. The
124
		 * The load is "attempted" because not all loads result in a model. 
126
		 * load is "attempted" because not all loads result in a model. However,
125
		 * However, upon leaving this method, theShareModel variable
127
		 * upon leaving this method, theShareModel variable is up-to-date.
126
		 * is up-to-date.
127
		 */
128
		 */
128
		public void waitForLoadAttempt() {
129
		public void waitForLoadAttempt() {
130
			final boolean allowInterrupt = PrefUtil.ALLOW_INTERRUPT_WAITING_THREAD;
131
			final long timeLimit = (PrefUtil.WAIT_DELAY==0) ? Long.MAX_VALUE : PrefUtil.now() + PrefUtil.WAIT_DELAY;
132
			final Job current = Job.getJobManager().currentJob();
129
			boolean interrupted = false;
133
			boolean interrupted = false;
130
			try {
134
			try {
131
				// if we have a rule, then use a polling system with
135
				while (initializing) {
132
				// short-circuit, otherwise use wait/notify
136
					if (current!=null) {
133
				if (Job.getJobManager().currentRule() != null) {
137
						current.yieldRule(null);
134
					while (initializing) {
135
						Job.getJobManager().currentJob().yieldRule(null);
136
						synchronized (this) {
137
							if (initializing) {
138
								try {
139
									wait(WAIT_INTERVAL_MS);
140
								}
141
								catch (InterruptedException e) {
142
									interrupted = true;
143
								}
144
							}
145
						}
146
					}
138
					}
147
				}
139
					try {
148
				else {
140
						loop();
149
					synchronized (this) {
141
					} catch (InterruptedException e) {
150
						while (initializing) {
142
						if (allowInterrupt) {
151
							try {
143
							throw new OperationCanceledException("Waiting thread interrupted while waiting for model id: "+id + " to load");
152
								wait();
144
						} else {
153
							}
145
							interrupted=true;
154
							catch (InterruptedException e) {
155
								interrupted = true;
156
							}
157
						}
146
						}
158
					}
147
					}
148
					if (PrefUtil.now() >= timeLimit	)
149
						throw new OperationCanceledException("Waiting thread timeout exceeded while waiting for model id: "+id + " to load");
159
				}
150
				}
160
			}
151
			}
161
			finally {
152
			finally {
162
				if (interrupted)
153
				if (interrupted) {
163
					Thread.currentThread().interrupt();
154
					Thread.currentThread().interrupt();
155
				}
164
			}
156
			}
165
		}
157
		}
166
		
158
159
		private void loop() throws InterruptedException {	
160
			if (initializing) {
161
				if (LOAD_LOCK.acquire(PrefUtil.WAIT_INTERVAL_MS)) {
162
					// if we got the lock, but initializing is still not true the deadlock detector gave us
163
					// the lock and caused reentrancy into this critical section. This is invalid and the 
164
					// sign of a cyclical load attempt. In this case, we through an 
165
					// OperationCanceledException in lew of entering a spin-loop. 
166
					if (initializing) {
167
						LOAD_LOCK.release();
168
						throw new OperationCanceledException("Aborted cyclic load attempt for model with id: "+ id );
169
					} else {
170
						LOAD_LOCK.release();
171
					}
172
				}
173
			}
174
		}
175
167
		/**
176
		/**
168
		 * Flags this model as loaded. All waiting methods on 
177
		 * Flags this model as loaded. All waiting methods on
169
		 * {@link #waitForLoadAttempt()} will proceed after this 
178
		 * {@link #waitForLoadAttempt()} will proceed after this method returns.
170
		 * method returns. 
171
		 */
179
		 */
172
		public synchronized void setLoaded() {
180
		public void setLoaded() {
173
			initializing = false;
181
			initializing = false;
174
			notifyAll();
182
			LOAD_LOCK.release();
175
		}
183
		}
176
	}
184
	}
177
185
Lines 239-245 Link Here
239
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
247
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
240
			if (testObject==null) {
248
			if (testObject==null) {
241
				// null means it's been disposed, we need to do the work to reload it.
249
				// null means it's been disposed, we need to do the work to reload it.
242
				sharedObject = new SharedObject(null);
250
				sharedObject = new SharedObject(id);
243
				fManagedObjects.put(id, sharedObject);
251
				fManagedObjects.put(id, sharedObject);
244
				SYNC.release();
252
				SYNC.release();
245
				_doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule,
253
				_doCommonCreateModel(file, id, handler, resolver, rwType, encodingRule,
Lines 350-356 Link Here
350
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
358
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
351
			if (testObject==null) {
359
			if (testObject==null) {
352
				// it was removed ,so lets create it
360
				// it was removed ,so lets create it
353
				sharedObject = new SharedObject(null);
361
				sharedObject = new SharedObject(id);
354
				fManagedObjects.put(id, sharedObject);
362
				fManagedObjects.put(id, sharedObject);
355
				SYNC.release();
363
				SYNC.release();
356
				_doCommonCreateModel(inputStream, id, handler, resolver, rwType,
364
				_doCommonCreateModel(inputStream, id, handler, resolver, rwType,
Lines 491-497 Link Here
491
				SharedObject testObject = (SharedObject) fManagedObjects.get(id);
499
				SharedObject testObject = (SharedObject) fManagedObjects.get(id);
492
				if (testObject==null) {
500
				if (testObject==null) {
493
					// it was removed ,so lets create it
501
					// it was removed ,so lets create it
494
					sharedObject = new SharedObject(null);
502
					sharedObject = new SharedObject(id);
495
					fManagedObjects.put(id, sharedObject);
503
					fManagedObjects.put(id, sharedObject);
496
					
504
					
497
					SYNC.release();
505
					SYNC.release();
Lines 567-573 Link Here
567
				throw new ResourceInUse();
575
				throw new ResourceInUse();
568
			}
576
			}
569
			
577
			
570
			sharedObject = new SharedObject(null);
578
			sharedObject = new SharedObject(id);
571
			fManagedObjects.put(id, sharedObject);
579
			fManagedObjects.put(id, sharedObject);
572
			
580
			
573
		} finally {
581
		} finally {
Lines 612-618 Link Here
612
			SYNC.acquire();
620
			SYNC.acquire();
613
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
621
			SharedObject testObject = (SharedObject) fManagedObjects.get(id);
614
			if (testObject==null) {
622
			if (testObject==null) {
615
				sharedObject = new SharedObject(null);
623
				sharedObject = new SharedObject(id);
616
				fManagedObjects.put(id, sharedObject);
624
				fManagedObjects.put(id, sharedObject);
617
				SYNC.release();
625
				SYNC.release();
618
				synchronized(sharedObject) {
626
				synchronized(sharedObject) {
Lines 830-836 Link Here
830
			if (sharedObject != null) {
838
			if (sharedObject != null) {
831
				throw new ResourceInUse();
839
				throw new ResourceInUse();
832
			}
840
			}
833
			sharedObject = new SharedObject(null);
841
			sharedObject = new SharedObject(newId);
834
			fManagedObjects.put(newId,sharedObject);
842
			fManagedObjects.put(newId,sharedObject);
835
		} finally {
843
		} finally {
836
			SYNC.release();
844
			SYNC.release();
(-)src/org/eclipse/wst/sse/core/internal/model/PrefUtil.java (+135 lines)
Added Link Here
1
package org.eclipse.wst.sse.core.internal.model;
2
3
import org.eclipse.core.runtime.Platform;
4
import org.eclipse.core.runtime.preferences.ConfigurationScope;
5
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
6
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
7
import org.eclipse.core.runtime.preferences.IPreferencesService;
8
import org.eclipse.core.runtime.preferences.InstanceScope;
9
import org.eclipse.osgi.util.NLS;
10
import org.eclipse.wst.sse.core.internal.SSECorePlugin;
11
import org.osgi.service.prefs.Preferences;
12
13
public class PrefUtil {
14
15
	static long WAIT_INTERVAL_MS = 500;
16
	static int WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad");
17
	static boolean ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad");
18
19
	/** Base of millisecond timings, to avoid wrapping */
20
	private static final long MILLI_ORIGIN = System.currentTimeMillis();
21
22
	/**
23
	 * Returns millisecond time offset by origin
24
	 */
25
	static final long now() {
26
		return System.currentTimeMillis() - MILLI_ORIGIN;
27
	}
28
	
29
	private static IEclipsePreferences.IPreferenceChangeListener LISTENER;
30
	static {
31
		InstanceScope scope = new InstanceScope();
32
		IEclipsePreferences instancePrefs = scope.getNode(SSECorePlugin.ID);
33
		LISTENER = new IEclipsePreferences.IPreferenceChangeListener() {
34
35
			public void preferenceChange(PreferenceChangeEvent event) {
36
37
				if ("modelmanager.maxWaitDuringConcurrentLoad".equals(event.getKey())) {
38
					WAIT_DELAY = getInt("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad");
39
				}
40
				else if ("modelmanager.allowInterruptsDuringConcurrentLoad".equals(event.getKey())) {
41
					ALLOW_INTERRUPT_WAITING_THREAD = getBoolean("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad");
42
				}
43
			}
44
		};
45
		instancePrefs.addPreferenceChangeListener(LISTENER);
46
	}
47
48
	private static String getProperty(String property) {
49
		// Importance order is:
50
		// default-default < instanceScope < configurationScope < systemProperty
51
		// < envVar
52
		String value = null;
53
54
		if (value == null) {
55
			value = System.getenv(property);
56
		}
57
		if (value == null) {
58
			value = System.getProperty(property);
59
		}
60
		if (value == null) {
61
			IPreferencesService preferencesService = Platform.getPreferencesService();
62
			
63
			String key = property;
64
			if (property != null && property.startsWith(SSECorePlugin.ID)) {
65
				// +1, include the "."
66
				key = property.substring(SSECorePlugin.ID.length() + 1, property.length());
67
			}
68
			InstanceScope instance = new InstanceScope();
69
			ConfigurationScope config = new ConfigurationScope();
70
			
71
			Preferences instanceNode = instance.getNode(SSECorePlugin.ID);
72
			Preferences configNode = config.getNode(SSECorePlugin.ID);
73
			value = preferencesService.get(key, getDefault(property), new Preferences[]{configNode,instanceNode});
74
		}
75
76
		return value;
77
	}
78
79
	private static String getDefault(String property) {
80
		// this is the "default-default"
81
		if ("org.eclipse.wst.sse.core.modelmanager.maxWaitDuringConcurrentLoad".equals(property)) {
82
			return "0";
83
		}
84
		else if ("org.eclipse.wst.sse.core.modelmanager.allowInterruptsDuringConcurrentLoad".equals(property)) {
85
			return "false";
86
		}
87
		return null;
88
	}
89
90
	private static boolean getBoolean(String key) {
91
		String property = getProperty(key);
92
		// if (property != null) {
93
		//			System.out.println("Tweak: " + key + "=" + Boolean.parseBoolean(property)); //$NON-NLS-1$ //$NON-NLS-2$
94
		// }
95
		return (property != null ? Boolean.valueOf(property) : Boolean.valueOf(getDefault(key)))
96
				.booleanValue();
97
	}
98
99
	private static int getInt(String key) {
100
		String property = getProperty(key);
101
		int size = 0;
102
		if (property != null) {
103
			try {
104
				size = Integer.parseInt(property);
105
				//	System.out.println("Tweak: " + key + "=" + size); //$NON-NLS-1$ //$NON-NLS-2$
106
			}
107
			catch (NumberFormatException e) {
108
				size = getDefaultInt(key, property, size);
109
			}
110
		}
111
		else {
112
			size = getDefaultInt(key, property, size);
113
		}
114
		return size;
115
	}
116
117
	private static int getDefaultInt(String key, String property, int size) {
118
		// ignored
119
		try {
120
			size = Integer.parseInt(getDefault(key));
121
		}
122
		catch (NumberFormatException e1) {
123
			handleIntParseException(key, property, e1);
124
			size = 0;
125
		}
126
		return size;
127
	}
128
129
	private static void handleIntParseException(String key, String property, NumberFormatException e1) {
130
		Exception n = new Exception(NLS.bind(
131
				"Exception during parse of default value for key ''{0}'' value was ''{1}''. Using 0 instead", //$NON-NLS-1$
132
				key, property), e1);
133
		n.printStackTrace();
134
	}
135
}

Return to bug 308120