~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit/BatchingProgressMonitor.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
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
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
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.
 
23
 
 
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
 
27
  written permission.
 
28
 
 
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.
 
42
*/
 
43
 
 
44
using NGit;
 
45
using Sharpen;
 
46
 
 
47
namespace NGit
 
48
{
 
49
        /// <summary>ProgressMonitor that batches update events.</summary>
 
50
        /// <remarks>ProgressMonitor that batches update events.</remarks>
 
51
        public abstract class BatchingProgressMonitor : ProgressMonitor
 
52
        {
 
53
                private static readonly ScheduledThreadPoolExecutor alarmQueue;
 
54
 
 
55
                internal static readonly object alarmQueueKiller;
 
56
 
 
57
                static BatchingProgressMonitor()
 
58
                {
 
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.
 
63
                        //
 
64
                        int threads = 1;
 
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.
 
72
                        //
 
73
                        alarmQueue.SetThreadFactory(Executors.DefaultThreadFactory());
 
74
                        alarmQueueKiller = new _object_87();
 
75
                }
 
76
 
 
77
                private sealed class _ThreadFactory_66 : ThreadFactory
 
78
                {
 
79
                        public _ThreadFactory_66()
 
80
                        {
 
81
                                this.baseFactory = Executors.DefaultThreadFactory();
 
82
                        }
 
83
 
 
84
                        private readonly ThreadFactory baseFactory;
 
85
 
 
86
                        public Sharpen.Thread NewThread(Runnable taskBody)
 
87
                        {
 
88
                                Sharpen.Thread thr = this.baseFactory.NewThread(taskBody);
 
89
                                thr.SetName("JGit-AlarmQueue");
 
90
                                thr.SetDaemon(true);
 
91
                                return thr;
 
92
                        }
 
93
                }
 
94
 
 
95
                private sealed class _object_87 : object
 
96
                {
 
97
                        public _object_87()
 
98
                        {
 
99
                        }
 
100
 
 
101
                        ~_object_87()
 
102
                        {
 
103
                                BatchingProgressMonitor.alarmQueue.ShutdownNow();
 
104
                        }
 
105
                }
 
106
 
 
107
                private long delayStartTime;
 
108
 
 
109
                private TimeUnit delayStartUnit = TimeUnit.MILLISECONDS;
 
110
 
 
111
                private BatchingProgressMonitor.Task task;
 
112
 
 
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
 
117
                /// first
 
118
                /// <see cref="Update(int)">Update(int)</see>
 
119
                /// call.
 
120
                /// </param>
 
121
                /// <param name="unit">
 
122
                /// time unit of
 
123
                /// <code>time</code>
 
124
                /// .
 
125
                /// </param>
 
126
                public virtual void SetDelayStart(long time, TimeUnit unit)
 
127
                {
 
128
                        delayStartTime = time;
 
129
                        delayStartUnit = unit;
 
130
                }
 
131
 
 
132
                public override void Start(int totalTasks)
 
133
                {
 
134
                }
 
135
 
 
136
                // Ignore the number of tasks.
 
137
                public override void BeginTask(string title, int work)
 
138
                {
 
139
                        EndTask();
 
140
                        task = new BatchingProgressMonitor.Task(title, work);
 
141
                        if (delayStartTime != 0)
 
142
                        {
 
143
                                task.Delay(delayStartTime, delayStartUnit);
 
144
                        }
 
145
                }
 
146
 
 
147
                public override void Update(int completed)
 
148
                {
 
149
                        if (task != null)
 
150
                        {
 
151
                                task.Update(this, completed);
 
152
                        }
 
153
                }
 
154
 
 
155
                public override void EndTask()
 
156
                {
 
157
                        if (task != null)
 
158
                        {
 
159
                                task.End(this);
 
160
                                task = null;
 
161
                        }
 
162
                }
 
163
 
 
164
                public override bool IsCancelled()
 
165
                {
 
166
                        return false;
 
167
                }
 
168
 
 
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);
 
173
 
 
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);
 
179
 
 
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>
 
187
                /// .
 
188
                /// </param>
 
189
                protected internal abstract void OnUpdate(string taskName, int workCurr, int workTotal
 
190
                        , int percentDone);
 
191
 
 
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>
 
199
                /// .
 
200
                /// </param>
 
201
                protected internal abstract void OnEndTask(string taskName, int workCurr, int workTotal
 
202
                        , int percentDone);
 
203
 
 
204
                private class Task : Runnable
 
205
                {
 
206
                        /// <summary>Title of the current task.</summary>
 
207
                        /// <remarks>Title of the current task.</remarks>
 
208
                        private readonly string taskName;
 
209
 
 
210
                        /// <summary>
 
211
                        /// Number of work units, or
 
212
                        /// <see cref="ProgressMonitor.UNKNOWN">ProgressMonitor.UNKNOWN</see>
 
213
                        /// .
 
214
                        /// </summary>
 
215
                        private readonly int totalWork;
 
216
 
 
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;
 
220
 
 
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;
 
224
 
 
225
                        /// <summary>True if the task has displayed anything.</summary>
 
226
                        /// <remarks>True if the task has displayed anything.</remarks>
 
227
                        private bool output;
 
228
 
 
229
                        /// <summary>Number of work units already completed.</summary>
 
230
                        /// <remarks>Number of work units already completed.</remarks>
 
231
                        private int lastWork;
 
232
 
 
233
                        /// <summary>
 
234
                        /// Percentage of
 
235
                        /// <see cref="totalWork">totalWork</see>
 
236
                        /// that is done.
 
237
                        /// </summary>
 
238
                        private int lastPercent;
 
239
 
 
240
                        internal Task(string taskName, int totalWork)
 
241
                        {
 
242
                                this.taskName = taskName;
 
243
                                this.totalWork = totalWork;
 
244
                                this.display = true;
 
245
                        }
 
246
 
 
247
                        internal virtual void Delay(long time, TimeUnit unit)
 
248
                        {
 
249
                                display = false;
 
250
                                timerFuture = alarmQueue.Schedule(this, time, unit);
 
251
                        }
 
252
 
 
253
                        public virtual void Run()
 
254
                        {
 
255
                                display = true;
 
256
                        }
 
257
 
 
258
                        internal virtual void Update(BatchingProgressMonitor pm, int completed)
 
259
                        {
 
260
                                lastWork += completed;
 
261
                                if (totalWork == UNKNOWN)
 
262
                                {
 
263
                                        // Only display once per second, as the alarm fires.
 
264
                                        if (display)
 
265
                                        {
 
266
                                                pm.OnUpdate(taskName, lastWork);
 
267
                                                output = true;
 
268
                                                RestartTimer();
 
269
                                        }
 
270
                                }
 
271
                                else
 
272
                                {
 
273
                                        // Display once per second or when 1% is done.
 
274
                                        int currPercent = lastWork * 100 / totalWork;
 
275
                                        if (display)
 
276
                                        {
 
277
                                                pm.OnUpdate(taskName, lastWork, totalWork, currPercent);
 
278
                                                output = true;
 
279
                                                RestartTimer();
 
280
                                                lastPercent = currPercent;
 
281
                                        }
 
282
                                        else
 
283
                                        {
 
284
                                                if (currPercent != lastPercent)
 
285
                                                {
 
286
                                                        pm.OnUpdate(taskName, lastWork, totalWork, currPercent);
 
287
                                                        output = true;
 
288
                                                        lastPercent = currPercent;
 
289
                                                }
 
290
                                        }
 
291
                                }
 
292
                        }
 
293
 
 
294
                        private void RestartTimer()
 
295
                        {
 
296
                                display = false;
 
297
                                timerFuture = alarmQueue.Schedule(this, 1, TimeUnit.SECONDS);
 
298
                        }
 
299
 
 
300
                        internal virtual void End(BatchingProgressMonitor pm)
 
301
                        {
 
302
                                if (output)
 
303
                                {
 
304
                                        if (totalWork == UNKNOWN)
 
305
                                        {
 
306
                                                pm.OnEndTask(taskName, lastWork);
 
307
                                        }
 
308
                                        else
 
309
                                        {
 
310
                                                int pDone = lastWork * 100 / totalWork;
 
311
                                                pm.OnEndTask(taskName, lastWork, totalWork, pDone);
 
312
                                        }
 
313
                                }
 
314
                                if (timerFuture != null)
 
315
                                {
 
316
                                        timerFuture.Cancel(false);
 
317
                                }
 
318
                        }
 
319
                }
 
320
        }
 
321
}