2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49
/// <summary>ProgressMonitor that batches update events.</summary>
50
/// <remarks>ProgressMonitor that batches update events.</remarks>
51
public abstract class BatchingProgressMonitor : ProgressMonitor
53
private static readonly ScheduledThreadPoolExecutor alarmQueue;
55
internal static readonly object alarmQueueKiller;
57
static BatchingProgressMonitor()
59
// To support garbage collection, start our thread but
60
// swap out the thread factory. When our class is GC'd
61
// the alarmQueueKiller will finalize and ask the executor
62
// to shutdown, ending the worker.
65
alarmQueue = new ScheduledThreadPoolExecutor(threads, new _ThreadFactory_66());
66
alarmQueue.SetContinueExistingPeriodicTasksAfterShutdownPolicy(false);
67
alarmQueue.SetExecuteExistingDelayedTasksAfterShutdownPolicy(false);
68
alarmQueue.PrestartAllCoreThreads();
69
// Now that the threads are running, its critical to swap out
70
// our own thread factory for one that isn't in the ClassLoader.
71
// This allows the class to GC.
73
alarmQueue.SetThreadFactory(Executors.DefaultThreadFactory());
74
alarmQueueKiller = new _object_87();
77
private sealed class _ThreadFactory_66 : ThreadFactory
79
public _ThreadFactory_66()
81
this.baseFactory = Executors.DefaultThreadFactory();
84
private readonly ThreadFactory baseFactory;
86
public Sharpen.Thread NewThread(Runnable taskBody)
88
Sharpen.Thread thr = this.baseFactory.NewThread(taskBody);
89
thr.SetName("JGit-AlarmQueue");
95
private sealed class _object_87 : object
103
BatchingProgressMonitor.alarmQueue.ShutdownNow();
107
private long delayStartTime;
109
private TimeUnit delayStartUnit = TimeUnit.MILLISECONDS;
111
private BatchingProgressMonitor.Task task;
113
/// <summary>Set an optional delay before the first output.</summary>
114
/// <remarks>Set an optional delay before the first output.</remarks>
115
/// <param name="time">
116
/// how long to wait before output. If 0 output begins on the
118
/// <see cref="Update(int)">Update(int)</see>
121
/// <param name="unit">
123
/// <code>time</code>
126
public virtual void SetDelayStart(long time, TimeUnit unit)
128
delayStartTime = time;
129
delayStartUnit = unit;
132
public override void Start(int totalTasks)
136
// Ignore the number of tasks.
137
public override void BeginTask(string title, int work)
140
task = new BatchingProgressMonitor.Task(title, work);
141
if (delayStartTime != 0)
143
task.Delay(delayStartTime, delayStartUnit);
147
public override void Update(int completed)
151
task.Update(this, completed);
155
public override void EndTask()
164
public override bool IsCancelled()
169
/// <summary>Update the progress monitor if the total work isn't known,</summary>
170
/// <param name="taskName">name of the task.</param>
171
/// <param name="workCurr">number of units already completed.</param>
172
protected internal abstract void OnUpdate(string taskName, int workCurr);
174
/// <summary>Finish the progress monitor when the total wasn't known in advance.</summary>
175
/// <remarks>Finish the progress monitor when the total wasn't known in advance.</remarks>
176
/// <param name="taskName">name of the task.</param>
177
/// <param name="workCurr">total number of units processed.</param>
178
protected internal abstract void OnEndTask(string taskName, int workCurr);
180
/// <summary>Update the progress monitor when the total is known in advance.</summary>
181
/// <remarks>Update the progress monitor when the total is known in advance.</remarks>
182
/// <param name="taskName">name of the task.</param>
183
/// <param name="workCurr">number of units already completed.</param>
184
/// <param name="workTotal">estimated number of units to process.</param>
185
/// <param name="percentDone">
186
/// <code>workCurr * 100 / workTotal</code>
189
protected internal abstract void OnUpdate(string taskName, int workCurr, int workTotal
192
/// <summary>Finish the progress monitor when the total is known in advance.</summary>
193
/// <remarks>Finish the progress monitor when the total is known in advance.</remarks>
194
/// <param name="taskName">name of the task.</param>
195
/// <param name="workCurr">total number of units processed.</param>
196
/// <param name="workTotal">estimated number of units to process.</param>
197
/// <param name="percentDone">
198
/// <code>workCurr * 100 / workTotal</code>
201
protected internal abstract void OnEndTask(string taskName, int workCurr, int workTotal
204
private class Task : Runnable
206
/// <summary>Title of the current task.</summary>
207
/// <remarks>Title of the current task.</remarks>
208
private readonly string taskName;
211
/// Number of work units, or
212
/// <see cref="ProgressMonitor.UNKNOWN">ProgressMonitor.UNKNOWN</see>
215
private readonly int totalWork;
217
/// <summary>True when timer expires and output should occur on next update.</summary>
218
/// <remarks>True when timer expires and output should occur on next update.</remarks>
219
private volatile bool display;
221
/// <summary>Scheduled timer, supporting cancellation if task ends early.</summary>
222
/// <remarks>Scheduled timer, supporting cancellation if task ends early.</remarks>
223
private Future<object> timerFuture;
225
/// <summary>True if the task has displayed anything.</summary>
226
/// <remarks>True if the task has displayed anything.</remarks>
229
/// <summary>Number of work units already completed.</summary>
230
/// <remarks>Number of work units already completed.</remarks>
231
private int lastWork;
235
/// <see cref="totalWork">totalWork</see>
238
private int lastPercent;
240
internal Task(string taskName, int totalWork)
242
this.taskName = taskName;
243
this.totalWork = totalWork;
247
internal virtual void Delay(long time, TimeUnit unit)
250
timerFuture = alarmQueue.Schedule(this, time, unit);
253
public virtual void Run()
258
internal virtual void Update(BatchingProgressMonitor pm, int completed)
260
lastWork += completed;
261
if (totalWork == UNKNOWN)
263
// Only display once per second, as the alarm fires.
266
pm.OnUpdate(taskName, lastWork);
273
// Display once per second or when 1% is done.
274
int currPercent = lastWork * 100 / totalWork;
277
pm.OnUpdate(taskName, lastWork, totalWork, currPercent);
280
lastPercent = currPercent;
284
if (currPercent != lastPercent)
286
pm.OnUpdate(taskName, lastWork, totalWork, currPercent);
288
lastPercent = currPercent;
294
private void RestartTimer()
297
timerFuture = alarmQueue.Schedule(this, 1, TimeUnit.SECONDS);
300
internal virtual void End(BatchingProgressMonitor pm)
304
if (totalWork == UNKNOWN)
306
pm.OnEndTask(taskName, lastWork);
310
int pDone = lastWork * 100 / totalWork;
311
pm.OnEndTask(taskName, lastWork, totalWork, pDone);
314
if (timerFuture != null)
316
timerFuture.Cancel(false);