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 |
} |