| /******************************************************************************* |
| * Copyright (c) 2005, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.core; |
| |
| import java.lang.ref.SoftReference; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.ElementChangedEvent; |
| import org.eclipse.dltk.core.IElementCacheListener; |
| import org.eclipse.dltk.core.IElementChangedListener; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IModelElementDelta; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ISourceModuleInfoCache; |
| |
| /** |
| * Used to cache some source module information. All information related to |
| * source module are removed, then source module are changed. |
| * |
| * @author haiodo |
| * |
| */ |
| public class SourceModuleInfoCache implements ISourceModuleInfoCache { |
| private ElementCache cache = null; |
| static long allAccess = 0; |
| static long miss = 0; |
| static long closes = 0; |
| |
| public SourceModuleInfoCache() { |
| // set the size of the caches in function of the maximum amount of |
| // memory available |
| // long maxMemory = Runtime.getRuntime().freeMemory(); |
| // if max memory is infinite, set the ratio to 4d which corresponds to |
| // the 256MB that Eclipse defaults to |
| // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=111299) |
| double ratio = 50; // 128000000 |
| |
| this.cache = new ElementCache( |
| (int) (ModelCache.DEFAULT_ROOT_SIZE * ratio)); |
| this.cache.setLoadFactor(0.90); |
| this.cache.addListener(new IElementCacheListener() { |
| public void close(Object element) { |
| closes++; |
| } |
| }); |
| DLTKCore.addElementChangedListener(changedListener); |
| } |
| |
| public void stop() { |
| DLTKCore.removeElementChangedListener(changedListener); |
| } |
| |
| private final ISourceModuleInfo cacheGet(ISourceModule module) { |
| allAccess++; |
| final SoftReference ref = (SoftReference) cache.get(module); |
| return ref != null ? (ISourceModuleInfo) ref.get() : null; |
| } |
| |
| public ISourceModuleInfo get(ISourceModule module) { |
| if (DLTKCore.VERBOSE) { |
| System.out.println("Filling ratio:" + this.cache.fillingRatio()); //$NON-NLS-1$ |
| } |
| ISourceModuleInfo info = cacheGet(module); |
| if (info == null) { |
| miss++; |
| info = new SourceModuleInfo(); |
| cache.put(module, new SoftReference(info)); |
| cache.ensureSpaceLimit(1, module); |
| return info; |
| } |
| // this.cache.printStats(); |
| if (DLTKCore.PERFOMANCE) { |
| System.out.println("SourceModuleInfoCache: access:" + allAccess //$NON-NLS-1$ |
| + " ok:" + (100.0f * (allAccess - miss) / allAccess) //$NON-NLS-1$ |
| + "% closes:" + closes); //$NON-NLS-1$ |
| System.out.println("Filling ratio:" + this.cache.fillingRatio()); //$NON-NLS-1$ |
| } |
| return info; |
| } |
| |
| private IElementChangedListener changedListener = new IElementChangedListener() { |
| public void elementChanged(ElementChangedEvent event) { |
| IModelElementDelta delta = event.getDelta(); |
| processDelta(delta); |
| } |
| |
| private void processDelta(IModelElementDelta delta) { |
| IModelElement element = delta.getElement(); |
| if (delta.getKind() == IModelElementDelta.REMOVED |
| || delta.getKind() == IModelElementDelta.CHANGED) { |
| if (element.getElementType() == IModelElement.SOURCE_MODULE) { |
| if (delta.getKind() == IModelElementDelta.REMOVED |
| || isContentChanged(delta) || isWorkingCopy(delta)) { |
| if (DEBUG) { |
| System.out |
| .println("[Cache] remove: kind=" + delta.getKind() + " flags=" + Integer.toHexString(delta.getFlags()) + " elementName=" + delta.getElement().getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| SourceModuleInfoCache.this |
| .remove((ISourceModule) element); |
| } else if (DEBUG) { |
| System.out |
| .println("[Cache] skip delta: kind=" + delta.getKind() + " flags=" + Integer.toHexString(delta.getFlags()) + " elementName=" + delta.getElement().getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| } |
| } |
| if ((delta.getFlags() & IModelElementDelta.F_CHILDREN) != 0) { |
| IModelElementDelta[] affectedChildren = delta |
| .getAffectedChildren(); |
| for (int i = 0; i < affectedChildren.length; i++) { |
| IModelElementDelta child = affectedChildren[i]; |
| processDelta(child); |
| } |
| } |
| } |
| |
| private final boolean isContentChanged(IModelElementDelta delta) { |
| return (delta.getFlags() & (IModelElementDelta.F_CONTENT | IModelElementDelta.F_FINE_GRAINED)) == IModelElementDelta.F_CONTENT; |
| } |
| |
| private final boolean isWorkingCopy(IModelElementDelta delta) { |
| return (delta.getFlags() & IModelElementDelta.F_PRIMARY_WORKING_COPY) != 0; |
| } |
| }; |
| |
| private static class SourceModuleInfo implements ISourceModuleInfo { |
| private Map map; |
| |
| public Object get(Object key) { |
| if (map == null) { |
| return null; |
| } |
| return map.get(key); |
| } |
| |
| public void put(Object key, Object value) { |
| if (map == null) { |
| map = new HashMap(); |
| } |
| map.put(key, value); |
| } |
| |
| public void remove(Object key) { |
| if (map != null) { |
| map.remove(key); |
| } |
| } |
| |
| public boolean isEmpty() { |
| if (this.map == null) { |
| return true; |
| } |
| return this.map.isEmpty(); |
| } |
| } |
| |
| public void remove(ISourceModule element) { |
| if (DEBUG) { |
| System.out.println("[Cache] remove " + element.getElementName()); //$NON-NLS-1$ |
| } |
| cache.remove(element); |
| cache.resetSpaceLimit(ModelCache.DEFAULT_ROOT_SIZE, element); |
| } |
| |
| private static final boolean DEBUG = false; |
| |
| public void clear() { |
| this.cache.flush(); |
| } |
| } |