View | Details | Raw Unified | Return to bug 12044 | Differences between
and this patch

Collapse All | Expand All

(-)search/org/eclipse/jdt/internal/core/search/processing/JobManager.java (-76 / +136 lines)
Lines 17-26 Link Here
17
17
18
public abstract class JobManager implements Runnable {
18
public abstract class JobManager implements Runnable {
19
19
20
	/* queue of jobs to execute */
20
	/* queues of jobs to execute */
21
	protected IJob[] awaitingJobs = new IJob[10];
21
	protected static final int HIGH_PRIORITY = 1;
22
	protected int jobStart = 0;
22
	protected static final int LOW_PRIORITY = 0;
23
	protected int jobEnd = -1;
23
	protected static final int MAX_PRIORITY = HIGH_PRIORITY; 
24
	protected IJob[][] awaitingJobs = new IJob[MAX_PRIORITY+1][10];
25
	protected int[] jobStart = new int[MAX_PRIORITY+1];
26
	protected int[] jobEnd = new int[MAX_PRIORITY+1];
24
	protected boolean executing = false;
27
	protected boolean executing = false;
25
28
26
	/* background processing */
29
	/* background processing */
Lines 36-41 Link Here
36
	public boolean activated = false;
39
	public boolean activated = false;
37
40
38
	private int awaitingClients = 0;
41
	private int awaitingClients = 0;
42
	
43
	public JobManager() {
44
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY; priorityIndex++) {
45
			this.jobStart[priorityIndex] = 0;
46
			this.jobEnd[priorityIndex] = -1;
47
		}
48
	}
39
49
40
	/**
50
	/**
41
	 * Invoked exactly once, in background, before starting processing any job
51
	 * Invoked exactly once, in background, before starting processing any job
Lines 46-62 Link Here
46
	/**
56
	/**
47
	 * Answer the amount of awaiting jobs.
57
	 * Answer the amount of awaiting jobs.
48
	 */
58
	 */
49
	public synchronized int awaitingJobsCount() {
59
	public int awaitingJobsCount() {
50
		// pretend busy in case concurrent job attempts performing before activated
60
		return awaitingJobsCount(HIGH_PRIORITY);
51
		return this.activated ? this.jobEnd - this.jobStart + 1 : 1;
61
	}
62
	
63
	/**
64
	 * Answer the amount of awaiting jobs with a given priority (jobs with a lower priority are not considered).
65
	 */
66
	private synchronized int awaitingJobsCount(int maxPriority) {
67
		if (!this.activated) {
68
			// pretend busy in case concurrent job attempts performing before activated
69
			return 1;
70
		}
71
		int count = 0;
72
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY-maxPriority; priorityIndex++) {
73
			count += this.jobEnd[priorityIndex] - this.jobStart[priorityIndex] + 1;
74
		}
75
		return count;
76
	}
77
	/**
78
	 * Answers the first job in the queue, or null if there is no job available
79
	 * Until the job has completed, the job manager will keep answering the same job.
80
	 */
81
	public IJob currentJob() {
82
		return currentJob(HIGH_PRIORITY);
52
	}
83
	}
53
	/**
84
	/**
54
	 * Answers the first job in the queue, or null if there is no job available
85
	 * Answers the first job in the queue, or null if there is no job available
55
	 * Until the job has completed, the job manager will keep answering the same job.
86
	 * Until the job has completed, the job manager will keep answering the same job.
56
	 */
87
	 */
57
	public synchronized IJob currentJob() {
88
	private synchronized IJob currentJob(int maxPriority) {
58
		if (this.enableCount > 0 && this.jobStart <= this.jobEnd)
89
		if (this.enableCount <= 0)
59
			return this.awaitingJobs[this.jobStart];
90
			return null;
91
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY-maxPriority; priorityIndex++) {
92
			IJob job = currentJobForPriority(priorityIndex);
93
			if (job != null)
94
				return job;
95
		}
96
		return null;
97
	}
98
99
	private IJob currentJobForPriority(int prorityIndex) {
100
		int start = this.jobStart[prorityIndex];
101
		if (start <= this.jobEnd[prorityIndex])
102
			return this.awaitingJobs[prorityIndex][start];
60
		return null;
103
		return null;
61
	}
104
	}
62
	public synchronized void disable() {
105
	public synchronized void disable() {
Lines 65-134 Link Here
65
			Util.verbose("DISABLING background indexing"); //$NON-NLS-1$
108
			Util.verbose("DISABLING background indexing"); //$NON-NLS-1$
66
	}
109
	}
67
	/**
110
	/**
68
	 * Remove the index from cache for a given project.
111
	 * Remove the jobs belonging to the given family.
69
	 * Passing null as a job family discards them all.
112
	 * Passing null as a job family discards them all.
70
	 */
113
	 */
71
	public void discardJobs(String jobFamily) {
114
	public void discardJobs(String jobFamily) {
72
73
		if (VERBOSE)
115
		if (VERBOSE)
74
			Util.verbose("DISCARD   background job family - " + jobFamily); //$NON-NLS-1$
116
			Util.verbose("DISCARD   background job family - " + jobFamily); //$NON-NLS-1$
75
117
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY; priorityIndex++) {
76
		try {
118
			try {
77
			IJob currentJob;
119
				IJob currentJob;
78
			// cancel current job if it belongs to the given family
120
				// cancel current job if it belongs to the given family
79
			synchronized(this){
121
				synchronized(this){
80
				currentJob = currentJob();
122
					currentJob = currentJobForPriority(priorityIndex);
81
				disable();
123
					disable();
82
			}
83
			if (currentJob != null && (jobFamily == null || currentJob.belongsTo(jobFamily))) {
84
				currentJob.cancel();
85
86
				// wait until current active job has finished
87
				while (this.processingThread != null && this.executing){
88
					try {
89
						if (VERBOSE)
90
							Util.verbose("-> waiting end of current background job - " + currentJob); //$NON-NLS-1$
91
						Thread.sleep(50);
92
					} catch(InterruptedException e){
93
						// ignore
94
					}
95
				}
124
				}
96
			}
125
				if (currentJob != null && (jobFamily == null || currentJob.belongsTo(jobFamily))) {
97
126
					currentJob.cancel();
98
			// flush and compact awaiting jobs
127
	
99
			int loc = -1;
128
					// wait until current active job has finished
100
			synchronized(this) {
129
					while (this.processingThread != null && this.executing){
101
				for (int i = this.jobStart; i <= this.jobEnd; i++) {
130
						try {
102
					currentJob = this.awaitingJobs[i];
103
					if (currentJob != null) { // sanity check
104
						this.awaitingJobs[i] = null;
105
						if (!(jobFamily == null || currentJob.belongsTo(jobFamily))) { // copy down, compacting
106
							this.awaitingJobs[++loc] = currentJob;
107
						} else {
108
							if (VERBOSE)
131
							if (VERBOSE)
109
								Util.verbose("-> discarding background job  - " + currentJob); //$NON-NLS-1$
132
								Util.verbose("-> waiting end of current background job - " + currentJob); //$NON-NLS-1$
110
							currentJob.cancel();
133
							Thread.sleep(50);
134
						} catch(InterruptedException e){
135
							// ignore
136
						}
137
					}
138
				}
139
	
140
				// flush and compact awaiting jobs
141
				int loc = -1;
142
				synchronized(this) {
143
					for (int i = this.jobStart[priorityIndex]; i <= this.jobEnd[priorityIndex]; i++) {
144
						currentJob = this.awaitingJobs[priorityIndex][i];
145
						if (currentJob != null) { // sanity check
146
							this.awaitingJobs[priorityIndex][i] = null;
147
							if (!(jobFamily == null || currentJob.belongsTo(jobFamily))) { // copy down, compacting
148
								this.awaitingJobs[priorityIndex][++loc] = currentJob;
149
							} else {
150
								if (VERBOSE)
151
									Util.verbose("-> discarding background job  - " + currentJob); //$NON-NLS-1$
152
								currentJob.cancel();
153
							}
111
						}
154
						}
112
					}
155
					}
156
					this.jobStart[priorityIndex] = 0;
157
					this.jobEnd[priorityIndex] = loc;
113
				}
158
				}
114
				this.jobStart = 0;
159
			} finally {
115
				this.jobEnd = loc;
160
				enable();
116
			}
161
			}
117
		} finally {
118
			enable();
119
		}
162
		}
120
		if (VERBOSE)
163
		if (VERBOSE)
121
			Util.verbose("DISCARD   DONE with background job family - " + jobFamily); //$NON-NLS-1$
164
			Util.verbose("DISCARD   DONE with background job family - " + jobFamily); //$NON-NLS-1$
122
	}
165
	}
166
	
123
	public synchronized void enable() {
167
	public synchronized void enable() {
124
		this.enableCount++;
168
		this.enableCount++;
125
		if (VERBOSE)
169
		if (VERBOSE)
126
			Util.verbose("ENABLING  background indexing"); //$NON-NLS-1$
170
			Util.verbose("ENABLING  background indexing"); //$NON-NLS-1$
127
		notifyAll(); // wake up the background thread if it is waiting (context must be synchronized)
171
		notifyAll(); // wake up the background thread if it is waiting (context must be synchronized)
128
	}
172
	}
129
	protected synchronized boolean isJobWaiting(IJob request) {
173
	protected boolean isJobWaiting(IJob request) {
130
		for (int i = this.jobEnd; i > this.jobStart; i--) // don't check job at jobStart, as it may have already started
174
		return isJobWaiting(request, HIGH_PRIORITY);
131
			if (request.equals(this.awaitingJobs[i])) return true;
175
	}
176
	protected synchronized boolean isJobWaiting(IJob request, int maxPriority) {	
177
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY-maxPriority; priorityIndex++) {
178
			for (int i = this.jobEnd[priorityIndex]; i > this.jobStart[priorityIndex]; i--) // don't check job at jobStart, as it may have already started
179
				if (request.equals(this.awaitingJobs[priorityIndex][i])) 
180
					return true;
181
		}
132
		return false;
182
		return false;
133
	}
183
	}
134
	/**
184
	/**
Lines 136-148 Link Here
136
	 * Note: clients awaiting until the job count is zero are still waiting at this point.
186
	 * Note: clients awaiting until the job count is zero are still waiting at this point.
137
	 */
187
	 */
138
	protected synchronized void moveToNextJob() {
188
	protected synchronized void moveToNextJob() {
139
		//if (!enabled) return;
189
		for (int priorityIndex=0; priorityIndex <= MAX_PRIORITY; priorityIndex++) {
140
190
			if (this.jobStart[priorityIndex] <= this.jobEnd[priorityIndex]) {
141
		if (this.jobStart <= this.jobEnd) {
191
				this.awaitingJobs[priorityIndex][this.jobStart[priorityIndex]++] = null;
142
			this.awaitingJobs[this.jobStart++] = null;
192
				if (this.jobStart[priorityIndex] > this.jobEnd[priorityIndex]) {
143
			if (this.jobStart > this.jobEnd) {
193
					this.jobStart[priorityIndex] = 0;
144
				this.jobStart = 0;
194
					this.jobEnd[priorityIndex] = -1;
145
				this.jobEnd = -1;
195
				}
196
				return;
146
			}
197
			}
147
		}
198
		}
148
	}
199
	}
Lines 168-173 Link Here
168
	 *
219
	 *
169
	 */
220
	 */
170
	public boolean performConcurrentJob(IJob searchJob, int waitingPolicy, IProgressMonitor progress) {
221
	public boolean performConcurrentJob(IJob searchJob, int waitingPolicy, IProgressMonitor progress) {
222
		return performConcurrentJob(searchJob, waitingPolicy, HIGH_PRIORITY, progress);
223
	}
224
	public boolean performConcurrentJob(IJob searchJob, int waitingPolicy, int maxPriority, IProgressMonitor progress) {
171
		if (VERBOSE)
225
		if (VERBOSE)
172
			Util.verbose("STARTING  concurrent job - " + searchJob); //$NON-NLS-1$
226
			Util.verbose("STARTING  concurrent job - " + searchJob); //$NON-NLS-1$
173
227
Lines 178-184 Link Here
178
			int concurrentJobWork = 100;
232
			int concurrentJobWork = 100;
179
			if (progress != null)
233
			if (progress != null)
180
				progress.beginTask("", concurrentJobWork); //$NON-NLS-1$
234
				progress.beginTask("", concurrentJobWork); //$NON-NLS-1$
181
			if (awaitingJobsCount() > 0) {
235
			if (awaitingJobsCount(maxPriority) > 0) {
182
				switch (waitingPolicy) {
236
				switch (waitingPolicy) {
183
237
184
					case IJob.ForceImmediate :
238
					case IJob.ForceImmediate :
Lines 225-234 Link Here
225
								int lastJobsCount = totalWork;
279
								int lastJobsCount = totalWork;
226
								float lastWorked = 0;
280
								float lastWorked = 0;
227
								float totalWorked = 0;
281
								float totalWorked = 0;
228
								while ((awaitingJobsCount = awaitingJobsCount()) > 0) {
282
								while ((awaitingJobsCount = awaitingJobsCount(maxPriority)) > 0) {
229
									if (subProgress != null && subProgress.isCanceled())
283
									if (subProgress != null && subProgress.isCanceled())
230
										throw new OperationCanceledException();
284
										throw new OperationCanceledException();
231
									IJob currentJob = currentJob();
285
									IJob currentJob = currentJob(maxPriority);
232
									// currentJob can be null when jobs have been added to the queue but job manager is not enabled
286
									// currentJob can be null when jobs have been added to the queue but job manager is not enabled
233
									if (currentJob != null && currentJob != previousJob) {
287
									if (currentJob != null && currentJob != previousJob) {
234
										if (VERBOSE)
288
										if (VERBOSE)
Lines 285-301 Link Here
285
	public abstract String processName();
339
	public abstract String processName();
286
340
287
	public synchronized void request(IJob job) {
341
	public synchronized void request(IJob job) {
288
342
		request(job, HIGH_PRIORITY);
343
	}
344
		
345
	public void request(IJob job, int priority) {
289
		job.ensureReadyToRun();
346
		job.ensureReadyToRun();
290
347
		int priorityIndex = MAX_PRIORITY-priority; // reverse order
291
		// append the job to the list of ones to process later on
348
		// append the job to the list of ones to process later on
292
		int size = this.awaitingJobs.length;
349
		int size = this.awaitingJobs[priorityIndex].length;
293
		if (++this.jobEnd == size) { // when growing, relocate jobs starting at position 0
350
		if (++this.jobEnd[priorityIndex] == size) { // when growing, relocate jobs starting at position 0
294
			this.jobEnd -= this.jobStart;
351
			this.jobEnd[priorityIndex] -= this.jobStart[priorityIndex];
295
			System.arraycopy(this.awaitingJobs, this.jobStart, this.awaitingJobs = new IJob[size * 2], 0, this.jobEnd);
352
			System.arraycopy(this.awaitingJobs[priorityIndex], this.jobStart[priorityIndex], this.awaitingJobs[priorityIndex] = new IJob[size * 2], 0, this.jobEnd[priorityIndex]);
296
			this.jobStart = 0;
353
			this.jobStart[priorityIndex] = 0;
297
		}
354
		}
298
		this.awaitingJobs[this.jobEnd] = job;
355
		this.awaitingJobs[priorityIndex][this.jobEnd[priorityIndex]] = job;
299
		if (VERBOSE) {
356
		if (VERBOSE) {
300
			Util.verbose("REQUEST   background job - " + job); //$NON-NLS-1$
357
			Util.verbose("REQUEST   background job - " + job); //$NON-NLS-1$
301
			Util.verbose("AWAITING JOBS count: " + awaitingJobsCount()); //$NON-NLS-1$
358
			Util.verbose("AWAITING JOBS count: " + awaitingJobsCount()); //$NON-NLS-1$
Lines 457-469 Link Here
457
			// ignore
514
			// ignore
458
		}
515
		}
459
	}
516
	}
460
	public String toString() {
517
	public synchronized String toString() {
461
		StringBuffer buffer = new StringBuffer(10);
518
		StringBuffer buffer = new StringBuffer(10);
462
		buffer.append("Enable count:").append(this.enableCount).append('\n'); //$NON-NLS-1$
519
		buffer.append("Enable count:").append(this.enableCount).append('\n'); //$NON-NLS-1$
463
		int numJobs = this.jobEnd - this.jobStart + 1;
520
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY; priorityIndex++) {
464
		buffer.append("Jobs in queue:").append(numJobs).append('\n'); //$NON-NLS-1$
521
			int numJobs = this.jobEnd[priorityIndex] - this.jobStart[priorityIndex] + 1;
465
		for (int i = 0; i < numJobs && i < 15; i++) {
522
			buffer.append("Jobs in queue [").append(MAX_PRIORITY-priorityIndex).append("]:").append(numJobs).append('\n'); //$NON-NLS-1$ //$NON-NLS-2$
466
			buffer.append(i).append(" - job["+i+"]: ").append(this.awaitingJobs[this.jobStart+i]).append('\n'); //$NON-NLS-1$ //$NON-NLS-2$
523
			for (int i = 0; i < numJobs && i < 15; i++) {
524
				buffer.append(i).append(" - job[").append(i).append("]: ").append(this.awaitingJobs[priorityIndex][this.jobStart[priorityIndex]+i]).append('\n'); //$NON-NLS-1$ //$NON-NLS-2$
525
		}
526
			
467
		}
527
		}
468
		return buffer.toString();
528
		return buffer.toString();
469
	}
529
	}
(-)search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java (-10 / +14 lines)
Lines 419-428 Link Here
419
 */
419
 */
420
public void indexSourceFolder(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
420
public void indexSourceFolder(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
421
	IProject project = javaProject.getProject();
421
	IProject project = javaProject.getProject();
422
	if (this.jobEnd > this.jobStart) {
422
	int priorityIndex = MAX_PRIORITY - HIGH_PRIORITY;
423
	if (this.jobEnd[priorityIndex] > this.jobStart[priorityIndex]) {
423
		// skip it if a job to index the project is already in the queue
424
		// skip it if a job to index the project is already in the queue
424
		IndexRequest request = new IndexAllProject(project, this);
425
		IndexRequest request = new IndexAllProject(project, this);
425
		if (isJobWaiting(request)) return;
426
		if (isJobWaiting(request, HIGH_PRIORITY)) return;
426
	}
427
	}
427
428
428
	request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this));
429
	request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this));
Lines 602-611 Link Here
602
 */
603
 */
603
public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
604
public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
604
	IProject project = javaProject.getProject();
605
	IProject project = javaProject.getProject();
605
	if (this.jobEnd > this.jobStart) {
606
	int priorityIndex = MAX_PRIORITY - HIGH_PRIORITY;
607
	if (this.jobEnd[priorityIndex] > this.jobStart[priorityIndex]) {
606
		// skip it if a job to index the project is already in the queue
608
		// skip it if a job to index the project is already in the queue
607
		IndexRequest request = new IndexAllProject(project, this);
609
		IndexRequest request = new IndexAllProject(project, this);
608
		if (isJobWaiting(request)) return;
610
		if (isJobWaiting(request, HIGH_PRIORITY)) return;
609
	}
611
	}
610
612
611
	request(new RemoveFolderFromIndex(sourceFolder, inclusionPatterns, exclusionPatterns, project, this));
613
	request(new RemoveFolderFromIndex(sourceFolder, inclusionPatterns, exclusionPatterns, project, this));
Lines 631-641 Link Here
631
	}
633
	}
632
	synchronized (this) {
634
	synchronized (this) {
633
		IPath containerPath = new Path(index.containerPath);
635
		IPath containerPath = new Path(index.containerPath);
634
		if (this.jobEnd > this.jobStart) {
636
		for (int priorityIndex = 0; priorityIndex <= MAX_PRIORITY; priorityIndex++) {
635
			for (int i = this.jobEnd; i > this.jobStart; i--) { // skip the current job
637
			if (this.jobEnd[priorityIndex] > this.jobStart[priorityIndex]) {
636
				IJob job = this.awaitingJobs[i];
638
				for (int i = this.jobEnd[priorityIndex]; i > this.jobStart[priorityIndex]; i--) { // skip the current job
637
				if (job instanceof IndexRequest)
639
					IJob job = this.awaitingJobs[priorityIndex][i];
638
					if (((IndexRequest) job).containerPath.equals(containerPath)) return;
640
					if (job instanceof IndexRequest)
641
						if (((IndexRequest) job).containerPath.equals(containerPath)) return;
642
				}
639
			}
643
			}
640
		}
644
		}
641
		IPath indexLocation = computeIndexLocation(containerPath);
645
		IPath indexLocation = computeIndexLocation(containerPath);
Lines 714-720 Link Here
714
	});
718
	});
715
}
719
}
716
720
717
public String toString() {
721
public synchronized String toString() {
718
	StringBuffer buffer = new StringBuffer(10);
722
	StringBuffer buffer = new StringBuffer(10);
719
	buffer.append(super.toString());
723
	buffer.append(super.toString());
720
	buffer.append("In-memory indexes:\n"); //$NON-NLS-1$
724
	buffer.append("In-memory indexes:\n"); //$NON-NLS-1$

Return to bug 12044