|
1 /******************************************************************************* |
|
2 * Copyright (c) 2004, 2006 IBM Corporation and others. |
|
3 * All rights reserved. This program and the accompanying materials |
|
4 * are made available under the terms of the Eclipse Public License v1.0 |
|
5 * which accompanies this distribution, and is available at |
|
6 * http://www.eclipse.org/legal/epl-v10.html |
|
7 * |
|
8 * Contributors: |
|
9 * IBM - Initial API and implementation |
|
10 *******************************************************************************/ |
|
11 package org.eclipse.core.internal.utils; |
|
12 |
|
13 import java.util.*; |
|
14 import org.eclipse.core.runtime.*; |
|
15 import org.eclipse.core.runtime.jobs.*; |
|
16 import org.osgi.framework.Bundle; |
|
17 |
|
18 /** |
|
19 * Performs string sharing passes on all string pool participants registered |
|
20 * with the platform. |
|
21 */ |
|
22 public class StringPoolJob extends Job { |
|
23 private static final long INITIAL_DELAY = 10000;//ten seconds |
|
24 private static final long RESCHEDULE_DELAY = 300000;//five minutes |
|
25 private long lastDuration; |
|
26 /** |
|
27 * Stores all registered string pool participants, along with the scheduling |
|
28 * rule required when running it. |
|
29 */ |
|
30 private Map participants = Collections.synchronizedMap(new HashMap(10)); |
|
31 |
|
32 private final Bundle systemBundle = Platform.getBundle("org.eclipse.osgi"); //$NON-NLS-1$ |
|
33 |
|
34 public StringPoolJob() { |
|
35 super(Messages.utils_stringJobName); |
|
36 setSystem(true); |
|
37 setPriority(DECORATE); |
|
38 } |
|
39 |
|
40 /** |
|
41 * Adds a string pool participant. The job periodically builds |
|
42 * a string pool and asks all registered participants to share their strings in |
|
43 * the pool. Once all participants have added their strings to the pool, the |
|
44 * pool is discarded to avoid additional memory overhead. |
|
45 * |
|
46 * Adding a participant that is equal to a participant already registered will |
|
47 * replace the scheduling rule associated with the participant, but will otherwise |
|
48 * be ignored. |
|
49 * |
|
50 * @param participant The participant to add |
|
51 * @param rule The scheduling rule that must be owned at the time the |
|
52 * participant is called. This allows a participant to protect their data structures |
|
53 * against access at unsafe times. |
|
54 * |
|
55 * @see #removeStringPoolParticipant(IStringPoolParticipant) |
|
56 * @since 3.1 |
|
57 */ |
|
58 public void addStringPoolParticipant(IStringPoolParticipant participant, ISchedulingRule rule) { |
|
59 participants.put(participant, rule); |
|
60 if (getState() == Job.SLEEPING) |
|
61 wakeUp(INITIAL_DELAY); |
|
62 else |
|
63 schedule(INITIAL_DELAY); |
|
64 } |
|
65 |
|
66 /** |
|
67 * Removes the indicated log listener from the set of registered string |
|
68 * pool participants. If no such participant is registered, no action is taken. |
|
69 * |
|
70 * @param participant the participant to deregister |
|
71 * @see #addStringPoolParticipant(IStringPoolParticipant, ISchedulingRule) |
|
72 * @since 3.1 |
|
73 */ |
|
74 public void removeStringPoolParticipant(IStringPoolParticipant participant) { |
|
75 participants.remove(participant); |
|
76 } |
|
77 |
|
78 /* (non-Javadoc) |
|
79 * Method declared on Job |
|
80 */ |
|
81 protected IStatus run(IProgressMonitor monitor) { |
|
82 //if the system is shutting down, don't build |
|
83 if (systemBundle.getState() == Bundle.STOPPING) |
|
84 return Status.OK_STATUS; |
|
85 |
|
86 //copy current participants to handle concurrent additions and removals to map |
|
87 Map.Entry[] entries = (Map.Entry[]) participants.entrySet().toArray(new Map.Entry[0]); |
|
88 ISchedulingRule[] rules = new ISchedulingRule[entries.length]; |
|
89 IStringPoolParticipant[] toRun = new IStringPoolParticipant[entries.length]; |
|
90 for (int i = 0; i < toRun.length; i++) { |
|
91 toRun[i] = (IStringPoolParticipant) entries[i].getKey(); |
|
92 rules[i] = (ISchedulingRule) entries[i].getValue(); |
|
93 } |
|
94 final ISchedulingRule rule = MultiRule.combine(rules); |
|
95 long start = -1; |
|
96 int savings = 0; |
|
97 final IJobManager jobManager = Job.getJobManager(); |
|
98 try { |
|
99 jobManager.beginRule(rule, monitor); |
|
100 start = System.currentTimeMillis(); |
|
101 savings = shareStrings(toRun, monitor); |
|
102 } finally { |
|
103 jobManager.endRule(rule); |
|
104 } |
|
105 if (start > 0) { |
|
106 lastDuration = System.currentTimeMillis() - start; |
|
107 if (Policy.DEBUG_STRINGS) |
|
108 Policy.debug("String sharing saved " + savings + " bytes in: " + lastDuration); //$NON-NLS-1$ //$NON-NLS-2$ |
|
109 } |
|
110 //throttle frequency if it takes too long |
|
111 long scheduleDelay = Math.max(RESCHEDULE_DELAY, lastDuration*100); |
|
112 if (Policy.DEBUG_STRINGS) |
|
113 Policy.debug("Rescheduling string sharing job in: " + scheduleDelay); //$NON-NLS-1$ |
|
114 schedule(scheduleDelay); |
|
115 return Status.OK_STATUS; |
|
116 } |
|
117 |
|
118 private int shareStrings(IStringPoolParticipant[] toRun, IProgressMonitor monitor) { |
|
119 final StringPool pool = new StringPool(); |
|
120 for (int i = 0; i < toRun.length; i++) { |
|
121 if (monitor.isCanceled()) |
|
122 break; |
|
123 final IStringPoolParticipant current = toRun[i]; |
|
124 SafeRunner.run(new ISafeRunnable() { |
|
125 public void handleException(Throwable exception) { |
|
126 //exceptions are already logged, so nothing to do |
|
127 } |
|
128 |
|
129 public void run() { |
|
130 current.shareStrings(pool); |
|
131 } |
|
132 }); |
|
133 } |
|
134 return pool.getSavedStringCount(); |
|
135 } |
|
136 } |