Skip to content

Commit a52d6dc

Browse files
EcljpseB0Tjukzi
authored andcommitted
Rework org.eclipse.core.internal.utils.Cache with standard java
* Threadsafe implementation * Instead of predefined cache size use SoftReferences. Should avoid random NullPointerException in concurrent use: #1411
1 parent 2d9238e commit a52d6dc

File tree

10 files changed

+88
-619
lines changed

10 files changed

+88
-619
lines changed

resources/bundles/org.eclipse.core.resources.spysupport/src/org/eclipse/core/internal/resources/SpySupport.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
*******************************************************************************/
1414
package org.eclipse.core.internal.resources;
1515

16-
import java.util.*;
16+
import java.util.ArrayList;
17+
import java.util.Map;
1718
import java.util.Map.Entry;
18-
import org.eclipse.core.internal.utils.Cache;
1919
import org.eclipse.core.internal.watson.ElementTree;
2020
import org.eclipse.core.resources.IResource;
2121
import org.eclipse.core.resources.ResourcesPlugin;
@@ -71,9 +71,4 @@ public static Object[] getElements(MarkerAttributeMap markerMap) {
7171
}
7272
return legacyElements.toArray();
7373
}
74-
public static boolean isContentDescriptionCached(File file) {
75-
ResourceInfo info = file.getResourceInfo(false, false);
76-
Cache.Entry entry = ((Workspace) ResourcesPlugin.getWorkspace()).getContentDescriptionManager().getCache().getEntry(file.getFullPath(), false);
77-
return entry != null && info.getContentId() == entry.getTimestamp();
78-
}
7974
}

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ContentDescriptionManager.java

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.eclipse.core.internal.events.ILifecycleListener;
3636
import org.eclipse.core.internal.events.LifecycleEvent;
3737
import org.eclipse.core.internal.utils.Cache;
38+
import org.eclipse.core.internal.utils.Cache.Entry;
3839
import org.eclipse.core.internal.utils.Messages;
3940
import org.eclipse.core.internal.utils.Policy;
4041
import org.eclipse.core.internal.watson.ElementTreeIterator;
@@ -235,7 +236,7 @@ public long skip(long n) throws IOException {
235236

236237
private static final String PT_CONTENTTYPES = "contentTypes"; //$NON-NLS-1$
237238

238-
private Cache cache;
239+
private final Cache<IPath, IContentDescription> cache = new Cache<>();
239240

240241
private volatile byte cacheState;
241242

@@ -269,7 +270,7 @@ synchronized void doFlushCache(final IProgressMonitor monitor, Set<IPath> toClea
269270
try {
270271
setCacheState(FLUSHING_CACHE);
271272
// flush the MRU cache
272-
cache.discardAll();
273+
cache.clear();
273274
SubMonitor subMonitor = SubMonitor.convert(monitor);
274275
if (toClean.isEmpty()) {
275276
// no project was added, must be a global flush
@@ -317,10 +318,6 @@ private void clearContentFlags(IPath root, final IProgressMonitor monitor) {
317318
Policy.debug("Content type cache for " + root + " flushed in " + (System.currentTimeMillis() - flushStart) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
318319
}
319320

320-
Cache getCache() {
321-
return cache;
322-
}
323-
324321
/** Public so tests can examine it. */
325322
public byte getCacheState() {
326323
if (cacheState != 0) {
@@ -364,7 +361,7 @@ public IContentDescription getDescriptionFor(File file, ResourceInfo info, boole
364361
if (getCacheState() == INVALID_CACHE) {
365362
// discard the cache, so it can be used before the flush job starts
366363
setCacheState(ABOUT_TO_FLUSH);
367-
cache.discardAll();
364+
cache.clear();
368365
// the cache is not good, flush it
369366
flushJob.schedule(1000);
370367
}
@@ -390,10 +387,10 @@ public IContentDescription getDescriptionFor(File file, ResourceInfo info, boole
390387
if (inSync) {
391388
// tries to get a description from the cache
392389
synchronized (this) {
393-
Cache.Entry entry = cache.getEntry(file.getFullPath());
390+
Entry<IContentDescription> entry = cache.getEntry(file.getFullPath());
394391
if (entry != null && entry.getTimestamp() == getTimestamp(info))
395392
// there was a description in the cache, and it was up to date
396-
return (IContentDescription) entry.getCached();
393+
return entry.getCached();
397394
}
398395
}
399396

@@ -403,10 +400,10 @@ public IContentDescription getDescriptionFor(File file, ResourceInfo info, boole
403400

404401
synchronized (this) {
405402
// tries to get a description from the cache
406-
Cache.Entry entry = cache.getEntry(file.getFullPath());
403+
Entry<IContentDescription> entry = cache.getEntry(file.getFullPath());
407404
if (entry != null && inSync && entry.getTimestamp() == getTimestamp(info))
408405
// there was a description in the cache, and it was up to date
409-
return (IContentDescription) entry.getCached();
406+
return entry.getCached();
410407

411408
if (getCacheState() != ABOUT_TO_FLUSH) {
412409
// we are going to add an entry to the cache or update the resource info - remember that
@@ -427,14 +424,7 @@ public IContentDescription getDescriptionFor(File file, ResourceInfo info, boole
427424
}
428425
}
429426
// we actually got a description filled by a describer (or a default description for a non-obvious type)
430-
if (entry == null)
431-
// there was no entry before - create one
432-
entry = cache.addEntry(file.getFullPath(), newDescription, getTimestamp(info));
433-
else {
434-
// just update the existing entry
435-
entry.setTimestamp(getTimestamp(info));
436-
entry.setCached(newDescription);
437-
}
427+
entry = cache.addEntry(file.getFullPath(), newDescription, getTimestamp(info));
438428
return newDescription;
439429
}
440430
}
@@ -470,7 +460,7 @@ public synchronized void invalidateCache(boolean flush, IProject project) {
470460
try {
471461
// discard the cache, so it can be used before the flush job starts
472462
setCacheState(ABOUT_TO_FLUSH);
473-
cache.discardAll();
463+
cache.clear();
474464
} catch (CoreException e) {
475465
Policy.log(e.getStatus());
476466
}
@@ -579,16 +569,14 @@ public void shutdown(IProgressMonitor monitor) throws CoreException {
579569
IExtensionRegistry registry = Platform.getExtensionRegistry();
580570
if (registry != null)
581571
registry.removeRegistryChangeListener(this);
582-
cache.dispose();
583-
cache = null;
572+
cache.clear();
584573
flushJob.cancel();
585574
flushJob = null;
586575
projectContentTypes = null;
587576
}
588577

589578
@Override
590579
public void startup(IProgressMonitor monitor) throws CoreException {
591-
cache = new Cache(100, 1000, 0.1);
592580
projectContentTypes = new ProjectContentTypes(workspace);
593581
getCacheState();
594582
if (cacheState == FLUSHING_CACHE || cacheState == ABOUT_TO_FLUSH)

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectContentTypes.java

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,23 @@
1515
*******************************************************************************/
1616
package org.eclipse.core.internal.resources;
1717

18-
import java.util.*;
18+
import java.util.Arrays;
19+
import java.util.Collections;
20+
import java.util.HashSet;
21+
import java.util.Set;
1922
import org.eclipse.core.internal.utils.Cache;
23+
import org.eclipse.core.internal.utils.Cache.Entry;
2024
import org.eclipse.core.resources.IProject;
2125
import org.eclipse.core.resources.ProjectScope;
22-
import org.eclipse.core.runtime.*;
26+
import org.eclipse.core.runtime.CoreException;
27+
import org.eclipse.core.runtime.IPath;
28+
import org.eclipse.core.runtime.Platform;
2329
import org.eclipse.core.runtime.content.IContentType;
2430
import org.eclipse.core.runtime.content.IContentTypeManager.ISelectionPolicy;
2531
import org.eclipse.core.runtime.content.IContentTypeMatcher;
26-
import org.eclipse.core.runtime.preferences.*;
32+
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
33+
import org.eclipse.core.runtime.preferences.IScopeContext;
34+
import org.eclipse.core.runtime.preferences.InstanceScope;
2735
import org.osgi.service.prefs.BackingStoreException;
2836
import org.osgi.service.prefs.Preferences;
2937

@@ -102,7 +110,7 @@ public IContentType[] select(IContentType[] candidates, boolean fileName, boolea
102110

103111
private static final String PREF_LOCAL_CONTENT_TYPE_SETTINGS = "enabled"; //$NON-NLS-1$
104112
private static final Preferences PROJECT_SCOPE = Platform.getPreferencesService().getRootNode().node(ProjectScope.SCOPE);
105-
private final Cache contentTypesPerProject;
113+
private final Cache<String, Set<String>> contentTypesPerProject = new Cache<>();
106114
private final Workspace workspace;
107115

108116
static boolean usesContentTypePreferences(String projectName) {
@@ -129,8 +137,6 @@ static boolean usesContentTypePreferences(String projectName) {
129137

130138
public ProjectContentTypes(Workspace workspace) {
131139
this.workspace = workspace;
132-
// keep cache small
133-
this.contentTypesPerProject = new Cache(5, 30, 0.4);
134140
}
135141

136142
/**
@@ -166,30 +172,22 @@ private IContentTypeMatcher createMatcher(Project project) {
166172
return Platform.getContentTypeManager().getMatcher(projectContentTypeSelectionPolicy, projectContentTypeSelectionPolicy);
167173
}
168174

169-
@SuppressWarnings({"unchecked"})
170175
private Set<String> getAssociatedContentTypes(Project project) {
171176
final ResourceInfo info = project.getResourceInfo(false, false);
172177
if (info == null)
173178
// the project has been deleted
174179
return null;
175180
final String projectName = project.getName();
176181
synchronized (contentTypesPerProject) {
177-
Cache.Entry entry = contentTypesPerProject.getEntry(projectName);
178-
if (entry != null)
179-
// we have an entry...
180-
if (entry.getTimestamp() == info.getContentId())
181-
// ...and it is not stale, so just return it
182-
return (Set<String>) entry.getCached();
183-
// no cached information found, have to collect associated content types
184-
Set<String> result = collectAssociatedContentTypes(project);
185-
if (entry == null)
186-
// there was no entry before - create one
187-
entry = contentTypesPerProject.addEntry(projectName, result, info.getContentId());
188-
else {
189-
// just update the existing entry
190-
entry.setTimestamp(info.getContentId());
191-
entry.setCached(result);
182+
Entry<Set<String>> entry = contentTypesPerProject.getEntry(projectName);
183+
int contentId = info.getContentId();
184+
if (entry != null && entry.getTimestamp() == contentId) {
185+
// use up-to-date cache
186+
return entry.getCached();
192187
}
188+
// no up-to-date cached information found
189+
Set<String> result = collectAssociatedContentTypes(project);
190+
contentTypesPerProject.addEntry(projectName, result, contentId);
193191
return result;
194192
}
195193
}

0 commit comments

Comments
 (0)