Skip to content

Commit 0f9e9b3

Browse files
laeubiHeikoKlare
authored andcommitted
Use a composite key of all bundle ids and version to check the cache
Currently the ContentDescriptionManager relies on a rather vague "timestamp" to indicate that the set of bundles has changed, this leads to some hard to explain instabilities in tests. This now uses a composite key of all bundle ids and their version and computes a hashsum from the string, this has the advantage that it is deterministic what properties of a bundle set is compared.
1 parent 71005ce commit 0f9e9b3

File tree

1 file changed

+47
-19
lines changed

1 file changed

+47
-19
lines changed

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

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,16 @@
2020
import java.io.FileNotFoundException;
2121
import java.io.IOException;
2222
import java.io.InputStream;
23+
import java.nio.charset.StandardCharsets;
24+
import java.security.MessageDigest;
25+
import java.security.NoSuchAlgorithmException;
26+
import java.util.Arrays;
2327
import java.util.Collections;
28+
import java.util.HexFormat;
2429
import java.util.LinkedHashSet;
30+
import java.util.Objects;
2531
import java.util.Set;
32+
import java.util.stream.Collectors;
2633
import org.eclipse.core.filesystem.EFS;
2734
import org.eclipse.core.filesystem.IFileStore;
2835
import org.eclipse.core.internal.events.ILifecycleListener;
@@ -57,6 +64,7 @@
5764
import org.eclipse.core.runtime.jobs.ISchedulingRule;
5865
import org.eclipse.osgi.util.NLS;
5966
import org.osgi.framework.Bundle;
67+
import org.osgi.framework.BundleContext;
6068

6169
/**
6270
* Keeps a cache of recently read content descriptions.
@@ -65,6 +73,7 @@
6573
* @see IFile#getContentDescription()
6674
*/
6775
public class ContentDescriptionManager implements IManager, IRegistryChangeListener, IContentTypeManager.IContentTypeChangeListener, ILifecycleListener {
76+
6877
/**
6978
* This job causes the content description cache and the related flags
7079
* in the resource tree to be flushed.
@@ -337,14 +346,6 @@ public byte getCacheState() {
337346
return cacheState;
338347
}
339348

340-
public long getCacheTimestamp() throws CoreException {
341-
try {
342-
return Long.parseLong(workspace.getRoot().getPersistentProperty(CACHE_TIMESTAMP));
343-
} catch (NumberFormatException e) {
344-
return 0;
345-
}
346-
}
347-
348349
public IContentTypeMatcher getContentTypeMatcher(Project project) throws CoreException {
349350
return projectContentTypes.getMatcherFor(project);
350351
}
@@ -370,9 +371,7 @@ public IContentDescription getDescriptionFor(File file, ResourceInfo info, boole
370371
if (inSync && getCacheState() != ABOUT_TO_FLUSH) {
371372
// first look for the flags in the resource info to avoid looking in the cache
372373
// don't need to copy the info because the modified bits are not in the deltas
373-
if (info == null)
374-
return null;
375-
if (info.isSet(ICoreConstants.M_NO_CONTENT_DESCRIPTION))
374+
if ((info == null) || info.isSet(ICoreConstants.M_NO_CONTENT_DESCRIPTION))
376375
// presumably, this file has no known content type
377376
return null;
378377
if (info.isSet(ICoreConstants.M_DEFAULT_CONTENT_DESCRIPTION)) {
@@ -480,6 +479,38 @@ public synchronized void invalidateCache(boolean flush, IProject project) {
480479
}
481480
}
482481

482+
private static String getCurrentPlatformState() {
483+
ResourcesPlugin plugin = ResourcesPlugin.getPlugin();
484+
if (plugin == null) {
485+
return ""; //$NON-NLS-1$
486+
}
487+
BundleContext bundleContext = plugin.getBundle().getBundleContext();
488+
if (bundleContext == null) {
489+
return ""; //$NON-NLS-1$
490+
}
491+
String ID = Arrays.stream(bundleContext.getBundles())
492+
.map(bundle -> String.format("%d %s %s", bundle.getBundleId(), bundle.getSymbolicName(), //$NON-NLS-1$
493+
bundle.getVersion()))
494+
.sorted().collect(Collectors.joining(System.lineSeparator()));
495+
try {
496+
MessageDigest digest = MessageDigest.getInstance("SHA-256"); //$NON-NLS-1$
497+
return HexFormat.of().formatHex(digest.digest(ID.getBytes(StandardCharsets.UTF_8)));
498+
} catch (NoSuchAlgorithmException e) {
499+
return Integer.toHexString(ID.hashCode());
500+
}
501+
}
502+
503+
/**
504+
* @return the cached platform state, only public for testing purpose!
505+
*/
506+
private String getCachedPlatformState() {
507+
try {
508+
return Objects.requireNonNullElse(workspace.getRoot().getPersistentProperty(CACHE_TIMESTAMP), ""); //$NON-NLS-1$
509+
} catch (CoreException e) {
510+
return e.toString();
511+
}
512+
}
513+
483514
/**
484515
* Tries to obtain a content description for the given file.
485516
*/
@@ -536,15 +567,11 @@ synchronized void setCacheState(byte newCacheState) throws CoreException {
536567
cacheState = newCacheState;
537568
}
538569

539-
private void setCacheTimeStamp(long timeStamp) throws CoreException {
540-
workspace.getRoot().setPersistentProperty(CACHE_TIMESTAMP, Long.toString(timeStamp));
541-
}
542-
543570
@Override
544571
public void shutdown(IProgressMonitor monitor) throws CoreException {
545-
if (getCacheState() != INVALID_CACHE)
546-
// remember the platform timestamp for which we have a valid cache
547-
setCacheTimeStamp(Platform.getStateStamp());
572+
if (getCacheState() != INVALID_CACHE) {
573+
workspace.getRoot().setPersistentProperty(CACHE_TIMESTAMP, getCurrentPlatformState());
574+
}
548575
IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
549576
//tolerate missing services during shutdown because they might be already gone
550577
if (contentTypeManager != null)
@@ -569,8 +596,9 @@ public void startup(IProgressMonitor monitor) throws CoreException {
569596
setCacheState(INVALID_CACHE);
570597
flushJob = new FlushJob(workspace);
571598
// the cache is stale (plug-ins that might be contributing content types were added/removed)
572-
if (getCacheTimestamp() != Platform.getStateStamp())
599+
if (!Objects.equals(getCachedPlatformState(), getCurrentPlatformState())) {
573600
invalidateCache(false, null);
601+
}
574602
// register a lifecycle listener
575603
workspace.addLifecycleListener(this);
576604
// register a content type change listener

0 commit comments

Comments
 (0)