platform35/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/StringPoolJob.java
changeset 40 eb3c938c7fef
equal deleted inserted replaced
39:2a03ec4dbf31 40:eb3c938c7fef
       
     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 }