mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-17 01:08:56 +00:00
[bug 432965] added caching of mappings between URI amd normalized URI
for loaded resources Change-Id: I431318bac1edca0c34107aa6c91b5d08ff60b270 Signed-off-by: akosyakov <anton.kosyakov@itemis.de>
This commit is contained in:
parent
96b3894fed
commit
0f9d1f4a32
4 changed files with 181 additions and 6 deletions
|
@ -10,7 +10,9 @@ package org.eclipse.xtext.resource;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.emf.common.notify.Notification;
|
||||
|
@ -35,6 +37,18 @@ import org.eclipse.emf.ecore.xmi.XMLResource;
|
|||
*/
|
||||
public class XtextResourceSet extends ResourceSetImpl {
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
protected Map<URI, URI> normalizationMap = new HashMap<URI, URI>();
|
||||
|
||||
/**
|
||||
* @since 2.7
|
||||
*/
|
||||
public Map<URI, URI> getNormalizationMap() {
|
||||
return Collections.unmodifiableMap(normalizationMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*/
|
||||
|
@ -45,10 +59,9 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
if (map != null && notification.getFeatureID(Resource.class) == Resource.RESOURCE__URI && notification.getNotifier() instanceof Resource) {
|
||||
URI oldOne = (URI) notification.getOldValue();
|
||||
map.remove(oldOne);
|
||||
if (oldOne != null) {
|
||||
URI oldNormalized = getURIConverter().normalize(oldOne);
|
||||
if (!oldOne.equals(oldNormalized))
|
||||
map.remove(oldNormalized);
|
||||
URI oldNormalized = normalizationMap.remove(oldOne);
|
||||
if (oldOne != null && !oldOne.equals(oldNormalized)) {
|
||||
map.remove(oldNormalized);
|
||||
}
|
||||
Resource resource = (Resource) notification.getNotifier();
|
||||
registerURI(resource);
|
||||
|
@ -81,6 +94,7 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
throw new IllegalStateException("A resource with the normalized URI '"+normalized+"' was already registered. The resource with the URI '"+previous+"' is no longer registered with the normalized form.");
|
||||
}
|
||||
}
|
||||
normalizationMap.put(uri, normalized);
|
||||
}
|
||||
Resource previous = map.put(uri, resource);
|
||||
if (previous != null && previous != resource) {
|
||||
|
@ -105,6 +119,16 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
|
||||
@Override
|
||||
protected NotificationChain inverseRemove(Resource resource, NotificationChain notifications) {
|
||||
URI uri = resource.getURI();
|
||||
if (uri != null) {
|
||||
URI normalize = getURIConverter().normalize(uri);
|
||||
Iterator<URI> i = normalizationMap.values().iterator();
|
||||
while(i.hasNext()) {
|
||||
if (i.next().equals(normalize)) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
final NotificationChain inverseRemove = super.inverseRemove(resource, notifications);
|
||||
resource.eAdapters().remove(getUriChangeListener());
|
||||
return inverseRemove;
|
||||
|
@ -118,6 +142,7 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
super.doClear();
|
||||
// don't iterate the values of the map per resource but just clear it all at once
|
||||
getURIResourceMap().clear();
|
||||
normalizationMap.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -177,6 +202,9 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
if (resource == null) {
|
||||
URI normalizedURI = getURIConverter().normalize(uri);
|
||||
resource = map.get(normalizedURI);
|
||||
if (resource != null) {
|
||||
normalizationMap.put(uri, normalizedURI);
|
||||
}
|
||||
}
|
||||
if (resource != null) {
|
||||
if (loadOnDemand && !resource.isLoaded()) {
|
||||
|
@ -212,7 +240,11 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
uriConverter = new ExtensibleURIConverterImpl() {
|
||||
@Override
|
||||
public URI normalize(URI uri) {
|
||||
if (ClasspathUriUtil.isClasspathUri(uri)) {
|
||||
URI normalizedURI = normalizationMap.get(uri);
|
||||
if (normalizedURI != null) {
|
||||
return normalizedURI;
|
||||
}
|
||||
if (ClasspathUriUtil.isClasspathUri(uri)) {
|
||||
URI result = XtextResourceSet.this.resolveClasspathURI(uri);
|
||||
if (ClasspathUriUtil.isClasspathUri(result))
|
||||
throw new ClasspathUriResolutionException(result);
|
||||
|
@ -275,4 +307,4 @@ public class XtextResourceSet extends ResourceSetImpl {
|
|||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import org.eclipse.emf.common.util.URI;
|
|||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet;
|
||||
import org.eclipse.emf.ecore.resource.URIConverter;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
|
@ -45,6 +46,10 @@ public class FlatResourceSetBasedAllContainersState extends AdapterImpl implemen
|
|||
public Collection<URI> getContainedURIs(String containerHandle) {
|
||||
if (!HANDLE.equals(containerHandle))
|
||||
return Collections.emptySet();
|
||||
if (resourceSet instanceof XtextResourceSet) {
|
||||
XtextResourceSet xtextResourceSet = (XtextResourceSet) resourceSet;
|
||||
return xtextResourceSet.getNormalizationMap().values();
|
||||
}
|
||||
List<URI> uris = Lists.newArrayListWithCapacity(resourceSet.getResources().size());
|
||||
URIConverter uriConverter = resourceSet.getURIConverter();
|
||||
for (Resource r : resourceSet.getResources())
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2014 itemis AG (http://www.itemis.eu) 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.xtext.linking;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.junit4.AbstractXtextTests;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.containers.FlatResourceSetBasedAllContainersState;
|
||||
import org.eclipse.xtext.util.internal.Stopwatches;
|
||||
import org.eclipse.xtext.util.internal.Stopwatches.StoppedTask;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
*/
|
||||
@Ignore
|
||||
public class FlatResourceSetBasedAllContainersStatePerformanceTest extends AbstractXtextTests {
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
with(new IgnoreCaseNamespacesTestLanguageStandaloneSetup() {
|
||||
|
||||
@Override
|
||||
public Injector createInjector() {
|
||||
return Guice.createInjector(new IgnoreCaseNamespacesTestLanguageRuntimeModule());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetContainedURIs() throws IOException {
|
||||
Stopwatches.setEnabled(true);
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
// File directory = null;
|
||||
// List<File> files = new ArrayList<File>();
|
||||
try {
|
||||
XtextResourceSet resourceSet = get(XtextResourceSet.class);
|
||||
resourceSet.setClasspathURIContext(getClass().getClassLoader());
|
||||
|
||||
// directory = new File("/Users/kosyakov/oomph/xtext/master/git/xtext/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/linking/ignorecasenamespacestestlanguage");
|
||||
// directory.mkdir();
|
||||
// Map<String, String> importedEntities = new HashMap<String, String>();
|
||||
|
||||
StoppedTask getResourceTask = Stopwatches.forTask("getResource");
|
||||
getResourceTask.start();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
// File file = new File(directory, (i + 1) + ".ignorecasenamespacestestlanguage");
|
||||
// files.add(file);
|
||||
// file.createNewFile();
|
||||
// PrintWriter printWriter = new PrintWriter(new FileWriter(file));
|
||||
// Set<String> keySet = importedEntities.keySet();
|
||||
// for (String importedKey : keySet) {
|
||||
// String importedValue = importedEntities.get(importedKey);
|
||||
// printWriter.print(importedKey);
|
||||
// printWriter.print(".");
|
||||
// printWriter.println(importedValue);
|
||||
// }
|
||||
// String exportedKey = "e" + i;
|
||||
// printWriter.print(exportedKey);
|
||||
// printWriter.println(" {");
|
||||
// Map<String, String> exportedEntities = new HashMap<String, String>();
|
||||
// int j = 0;
|
||||
// String exportedValue = exportedKey + "_" + j++;
|
||||
// exportedEntities.put(exportedKey, exportedValue);
|
||||
// printWriter.print(" ");
|
||||
// printWriter.print(exportedValue);
|
||||
// printWriter.println(" { }");
|
||||
// for (String importedKey : keySet) {
|
||||
// String importedValue = importedEntities.get(importedKey);
|
||||
//
|
||||
// exportedValue = exportedKey + "_" + j++;
|
||||
// exportedEntities.put(exportedKey, exportedValue);
|
||||
// printWriter.print(" ");
|
||||
// printWriter.print(exportedValue);
|
||||
// printWriter.print(" ");
|
||||
// printWriter.print(importedValue);
|
||||
// printWriter.println(" { }");
|
||||
// }
|
||||
// importedEntities.putAll(exportedEntities);
|
||||
// printWriter.println("}");
|
||||
// printWriter.close();
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
resourceSet.getResource(
|
||||
URI.createURI("classpath:/org/eclipse/xtext/linking/ignorecasenamespacestestlanguage/"
|
||||
+ (i + 1) + ".ignorecasenamespacestestlanguage"), true);
|
||||
}
|
||||
}
|
||||
getResourceTask.stop();
|
||||
|
||||
StoppedTask getContainedURIsTask = Stopwatches.forTask("getContainedURIs");
|
||||
getContainedURIsTask.start();
|
||||
FlatResourceSetBasedAllContainersState containersState = new FlatResourceSetBasedAllContainersState(resourceSet);
|
||||
for (int k = 0; k < 1000; k++) {
|
||||
Assert.assertEquals(1000, containersState.getContainedURIs(containersState.getContainerHandle(null)).size());
|
||||
}
|
||||
getContainedURIsTask.stop();
|
||||
|
||||
System.out.println(Stopwatches.getPrintableStopwatchData());
|
||||
Stopwatches.resetAll();
|
||||
} finally {
|
||||
// for (File file : files) {
|
||||
// file.delete();
|
||||
// }
|
||||
// if (directory != null) {
|
||||
// directory.delete();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -203,6 +203,8 @@ abstract class AbstractXtextResourceSetTest extends AbstractResourceSetTest {
|
|||
assertEquals(1, rs.URIResourceMap.size)
|
||||
assertEquals(resource, rs.URIResourceMap.get(null))
|
||||
|
||||
assertEquals(0, rs.getNormalizationMap.size)
|
||||
|
||||
// set the URI
|
||||
resource.URI = URI::createURI('/a/../foo')
|
||||
assertEquals(2, rs.URIResourceMap.size)
|
||||
|
@ -210,6 +212,9 @@ abstract class AbstractXtextResourceSetTest extends AbstractResourceSetTest {
|
|||
assertEquals(resource, rs.URIResourceMap.get(resource.URI))
|
||||
assertEquals(resource, rs.URIResourceMap.get(rs.URIConverter.normalize(resource.URI)))
|
||||
|
||||
assertEquals(1, rs.getNormalizationMap.size)
|
||||
assertEquals(rs.URIConverter.normalize(resource.URI), rs.getNormalizationMap.get(resource.URI))
|
||||
|
||||
// set the URI
|
||||
resource.URI = URI::createURI('/a/../bar')
|
||||
assertEquals(2, rs.URIResourceMap.size)
|
||||
|
@ -217,16 +222,23 @@ abstract class AbstractXtextResourceSetTest extends AbstractResourceSetTest {
|
|||
assertEquals(resource, rs.URIResourceMap.get(resource.URI))
|
||||
assertEquals(resource, rs.URIResourceMap.get(rs.URIConverter.normalize(resource.URI)))
|
||||
|
||||
assertEquals(1, rs.getNormalizationMap.size)
|
||||
assertEquals(rs.URIConverter.normalize(resource.URI), rs.getNormalizationMap.get(resource.URI))
|
||||
|
||||
// set the URI back to null
|
||||
resource.URI = null
|
||||
assertEquals(1, rs.URIResourceMap.size)
|
||||
assertEquals(resource, rs.URIResourceMap.get(null))
|
||||
|
||||
assertEquals(0, rs.getNormalizationMap.size)
|
||||
|
||||
// remove the resource
|
||||
rs.resources.remove(resource)
|
||||
|
||||
assertTrue(resource.eAdapters.empty)
|
||||
assertEquals(0, rs.URIResourceMap.size)
|
||||
|
||||
assertEquals(0, rs.getNormalizationMap.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in a new issue