mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
Experimental: ParallelResourceSet
This commit is contained in:
parent
6e192c7b40
commit
a5fb49354d
7 changed files with 1097 additions and 15 deletions
|
@ -47,10 +47,16 @@ import com.google.common.collect.Lists;
|
|||
*/
|
||||
public class ConcurrentAccessTest extends Assert {
|
||||
|
||||
private static final int RESOURCES = 1000;
|
||||
|
||||
private static final int EXPECTATION = RESOURCES + 1;
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private Resource resource;
|
||||
|
||||
private ThreadPools pools;
|
||||
|
||||
private GlobalStateMemento globalStateMemento;
|
||||
|
||||
|
@ -67,14 +73,14 @@ public class ConcurrentAccessTest extends Assert {
|
|||
resourceSet.getResources().add(resource);
|
||||
EPackage start = EcoreFactory.eINSTANCE.createEPackage();
|
||||
resource.getContents().add(start);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (int i = 0; i < RESOURCES; i++) {
|
||||
File tempFile = temporaryFolder.createTempFile("Package" + i, ".ecore");
|
||||
URI fileURI = URI.createFileURI(tempFile.getAbsolutePath());
|
||||
Resource toBeProxified = resourceSet.createResource(fileURI);
|
||||
EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
|
||||
ePackage.setNsURI("http://www.test.me/" + i);
|
||||
toBeProxified.getContents().add(ePackage);
|
||||
for (int j = 0; j < 100; j++) {
|
||||
for (int j = 0; j < RESOURCES; j++) {
|
||||
EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
|
||||
annotation.setSource("Source" + j);
|
||||
start.getEAnnotations().add(annotation);
|
||||
|
@ -86,23 +92,26 @@ public class ConcurrentAccessTest extends Assert {
|
|||
toBeProxified.save(null);
|
||||
}
|
||||
EcoreUtil.resolveAll(resourceSet);
|
||||
for (int i = 100; i >= 1; i--) {
|
||||
for (int i = RESOURCES; i >= 1; i--) {
|
||||
Resource toBeProxified = resourceSet.getResources().get(i);
|
||||
toBeProxified.unload();
|
||||
resourceSet.getResources().remove(toBeProxified);
|
||||
}
|
||||
pools = new ThreadPools();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
resource = null;
|
||||
pools.stop();
|
||||
pools = null;
|
||||
globalStateMemento.restoreGlobalState();
|
||||
}
|
||||
|
||||
@Test public void testDummy() {
|
||||
assertEquals(1, resource.getResourceSet().getResources().size());
|
||||
EcoreUtil.resolveAll(resource);
|
||||
assertEquals(101, resource.getResourceSet().getResources().size());
|
||||
assertEquals(EXPECTATION, resource.getResourceSet().getResources().size());
|
||||
}
|
||||
|
||||
@Test public void testResolveSingleThreaded() {
|
||||
|
@ -111,7 +120,7 @@ public class ConcurrentAccessTest extends Assert {
|
|||
assertEquals(1, resourceSet.getResources().size());
|
||||
EPackage pack = (EPackage) resource.getContents().get(0);
|
||||
doResolveAllReferences(pack);
|
||||
assertEquals(101, resourceSet.getResources().size());
|
||||
assertEquals(EXPECTATION, resourceSet.getResources().size());
|
||||
}
|
||||
|
||||
@Ignore @Test public void testMultiThreaded() throws InterruptedException {
|
||||
|
@ -119,7 +128,7 @@ public class ConcurrentAccessTest extends Assert {
|
|||
resourceSet.getResources().add(resource);
|
||||
boolean wasOk = resolveAllReferencesMultithreaded((EPackage) resource.getContents().get(0));
|
||||
if (wasOk)
|
||||
assertFalse(101 == resourceSet.getResources().size());
|
||||
assertFalse(EXPECTATION == resourceSet.getResources().size());
|
||||
assertFalse("unresolvedProxy", wasOk);
|
||||
}
|
||||
|
||||
|
@ -127,7 +136,25 @@ public class ConcurrentAccessTest extends Assert {
|
|||
ResourceSet resourceSet = new SynchronizedXtextResourceSet();
|
||||
resourceSet.getResources().add(resource);
|
||||
boolean wasOk = resolveAllReferencesMultithreaded((EPackage) resource.getContents().get(0));
|
||||
assertEquals(101, resourceSet.getResources().size());
|
||||
assertEquals(EXPECTATION, resourceSet.getResources().size());
|
||||
assertTrue("unresolvedProxy", wasOk);
|
||||
}
|
||||
|
||||
@Test public void testMultiThreadedParallel() throws InterruptedException {
|
||||
ResourceSet resourceSet = new ParallelResourceSet(pools);
|
||||
resourceSet.getResources().add(resource);
|
||||
boolean wasOk = resolveAllReferencesMultithreaded((EPackage) resource.getContents().get(0));
|
||||
assertEquals(EXPECTATION, resourceSet.getResources().size());
|
||||
assertTrue("unresolvedProxy", wasOk);
|
||||
}
|
||||
|
||||
@Test public void testMultiThreadedParallelOptimized() throws InterruptedException {
|
||||
ParallelResourceSet resourceSet = new ParallelResourceSet(pools);
|
||||
resourceSet.getResources().add(resource);
|
||||
List<Resource> resourceList = Lists.newArrayList(resource, resource, resource);
|
||||
List<Boolean> result = resourceSet.processResources(resourceList, r->doResolveAllReferences((EPackage)r.getContents().get(0)));
|
||||
boolean wasOk = result.stream().allMatch(failed->!failed);
|
||||
assertEquals(EXPECTATION, resourceSet.getResources().size());
|
||||
assertTrue("unresolvedProxy", wasOk);
|
||||
}
|
||||
|
||||
|
@ -136,7 +163,7 @@ public class ConcurrentAccessTest extends Assert {
|
|||
resourceSet.getResources().add(resource);
|
||||
boolean wasOk = resolveAllReferencesStateAccess((EPackage) resource.getContents().get(0));
|
||||
if (wasOk)
|
||||
assertFalse(101 == resourceSet.getResources().size());
|
||||
assertFalse(EXPECTATION == resourceSet.getResources().size());
|
||||
assertFalse("unresolvedProxy", wasOk);
|
||||
}
|
||||
|
||||
|
@ -144,7 +171,7 @@ public class ConcurrentAccessTest extends Assert {
|
|||
ResourceSet resourceSet = new SynchronizedXtextResourceSet();
|
||||
resourceSet.getResources().add(resource);
|
||||
boolean wasOk = resolveAllReferencesStateAccess((EPackage) resource.getContents().get(0));
|
||||
assertEquals(101, resourceSet.getResources().size());
|
||||
assertEquals(EXPECTATION, resourceSet.getResources().size());
|
||||
assertTrue("unresolvedProxy or concurrent modification or no such element", wasOk);
|
||||
}
|
||||
|
||||
|
@ -215,6 +242,55 @@ public class ConcurrentAccessTest extends Assert {
|
|||
assertEquals(2500, resources.size());
|
||||
assertEquals(2500, resourceSet.getURIResourceMap().size());
|
||||
}
|
||||
|
||||
@Test public void testMultiThreadedParallelListAccess() throws InterruptedException {
|
||||
XtextResourceSet resourceSet = new ParallelResourceSet(pools);
|
||||
final List<Resource> resources = resourceSet.getResources();
|
||||
List<List<Resource>> resourcesToAdd = Lists.newArrayList();
|
||||
for(int i = 0; i < 5; i++) {
|
||||
List<Resource> threadList = Lists.newArrayList();
|
||||
for(int j = 0; j < 500; j++) {
|
||||
threadList.add((new ResourceImpl(URI.createURI("file:/" + i + "_" + j + ".xmi"))));
|
||||
}
|
||||
resourcesToAdd.add(threadList);
|
||||
}
|
||||
List<Thread> threads = Lists.newArrayList();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final List<Resource> addUs = resourcesToAdd.get(i);
|
||||
threads.add(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
for(Resource addMe: addUs) {
|
||||
resources.add(addMe);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
assertEquals(2500, resources.size());
|
||||
assertEquals(2500, resourceSet.getURIResourceMap().size());
|
||||
}
|
||||
|
||||
@Test public void testMultiThreadedParallelListAccessOptimized() throws InterruptedException {
|
||||
ParallelResourceSet resourceSet = new ParallelResourceSet(pools);
|
||||
final List<Resource> resources = resourceSet.getResources();
|
||||
List<Resource> resourcesToAdd = Lists.newArrayList();
|
||||
for(int i = 0; i < 5; i++) {
|
||||
for(int j = 0; j < 500; j++) {
|
||||
resourcesToAdd.add((new ResourceImpl(URI.createURI("file:/" + i + "_" + j + ".xmi"))));
|
||||
}
|
||||
}
|
||||
resourceSet.processResources(resourcesToAdd, r->resources.add(r));
|
||||
|
||||
assertEquals(2500, resources.size());
|
||||
assertEquals(2500, resourceSet.getURIResourceMap().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if everything was ok.
|
||||
|
@ -239,7 +315,8 @@ public class ConcurrentAccessTest extends Assert {
|
|||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
return !wasExceptionOrProxy.get();
|
||||
boolean result = !wasExceptionOrProxy.get();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -285,15 +362,21 @@ public class ConcurrentAccessTest extends Assert {
|
|||
for(EAnnotation annotation: pack.getEAnnotations()) {
|
||||
EList<EObject> references = annotation.getReferences();
|
||||
for(EObject reference: references) {
|
||||
if (reference == null)
|
||||
if (reference == null) {
|
||||
failed = true;
|
||||
else if (reference.eIsProxy())
|
||||
System.out.println("REFERENCE IS NULL");
|
||||
}
|
||||
else if (reference.eIsProxy()) {
|
||||
failed = true;
|
||||
System.out.println("REFERENCE IS PROXY");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(ConcurrentModificationException e) {
|
||||
e.printStackTrace();
|
||||
failed = true;
|
||||
} catch(NoSuchElementException e) {
|
||||
e.printStackTrace();
|
||||
failed = true;
|
||||
}
|
||||
return failed;
|
||||
|
|
|
@ -18,6 +18,11 @@ import org.junit.Test
|
|||
|
||||
import static org.junit.Assert.*
|
||||
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.ResourceLocator
|
||||
import org.junit.Before
|
||||
import org.junit.After
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Suite
|
||||
import org.junit.runners.Suite.SuiteClasses
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
|
@ -351,7 +356,7 @@ class SynchronizedXtextResourceSetTest extends AbstractXtextResourceSetTest {
|
|||
|
||||
@Test
|
||||
def void testSynchronization() {
|
||||
val resourceSet = createEmptyResourceSet as SynchronizedXtextResourceSet
|
||||
val resourceSet = createEmptyResourceSet
|
||||
val Resource.Factory nullFactory = [ uri |
|
||||
val result = new NullResource
|
||||
result.URI = uri
|
||||
|
@ -383,4 +388,29 @@ class SynchronizedXtextResourceSetTest extends AbstractXtextResourceSetTest {
|
|||
assertEquals(resourceSet.resources.map[ getURI.toString ].toList.sort.join('\n'), resourceSet.getNormalizationMap.keySet.map[toString].toList.sort.join('\n'))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ParallelXtextResourceSetTest extends SynchronizedXtextResourceSetTest {
|
||||
ThreadPools pools;
|
||||
|
||||
@Before
|
||||
def void initPools() {
|
||||
pools = new ThreadPools()
|
||||
}
|
||||
|
||||
@After
|
||||
def void discardPools() {
|
||||
pools.stop();
|
||||
pools = null;
|
||||
}
|
||||
|
||||
override protected createEmptyResourceSet() {
|
||||
return new ParallelResourceSet(pools)
|
||||
}
|
||||
}
|
||||
|
||||
@SuiteClasses(SynchronizedXtextResourceSetTest, ParallelXtextResourceSetTest, XtextResourceSetTest)
|
||||
@RunWith(Suite)
|
||||
class AllResourceSetTests {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Copyright (c) 2012, 2018 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.resource;
|
||||
|
||||
import org.eclipse.xtext.resource.ParallelXtextResourceSetTest;
|
||||
import org.eclipse.xtext.resource.SynchronizedXtextResourceSetTest;
|
||||
import org.eclipse.xtext.resource.XtextResourceSetTest;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
@Suite.SuiteClasses({ SynchronizedXtextResourceSetTest.class, ParallelXtextResourceSetTest.class, XtextResourceSetTest.class })
|
||||
@RunWith(Suite.class)
|
||||
@SuppressWarnings("all")
|
||||
public class AllResourceSetTests {
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Copyright (c) 2012, 2018 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.resource;
|
||||
|
||||
import org.eclipse.xtext.resource.ParallelResourceSet;
|
||||
import org.eclipse.xtext.resource.SynchronizedXtextResourceSetTest;
|
||||
import org.eclipse.xtext.resource.ThreadPools;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class ParallelXtextResourceSetTest extends SynchronizedXtextResourceSetTest {
|
||||
private ThreadPools pools;
|
||||
|
||||
@Before
|
||||
public void initPools() {
|
||||
ThreadPools _threadPools = new ThreadPools();
|
||||
this.pools = _threadPools;
|
||||
}
|
||||
|
||||
@After
|
||||
public void discardPools() {
|
||||
try {
|
||||
this.pools.stop();
|
||||
this.pools = null;
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XtextResourceSet createEmptyResourceSet() {
|
||||
return new ParallelResourceSet(this.pools);
|
||||
}
|
||||
}
|
|
@ -37,8 +37,7 @@ public class SynchronizedXtextResourceSetTest extends AbstractXtextResourceSetTe
|
|||
@Test
|
||||
public void testSynchronization() {
|
||||
try {
|
||||
XtextResourceSet _createEmptyResourceSet = this.createEmptyResourceSet();
|
||||
final SynchronizedXtextResourceSet resourceSet = ((SynchronizedXtextResourceSet) _createEmptyResourceSet);
|
||||
final XtextResourceSet resourceSet = this.createEmptyResourceSet();
|
||||
final Resource.Factory _function = (URI uri) -> {
|
||||
NullResource _xblockexpression = null;
|
||||
{
|
||||
|
|
|
@ -0,0 +1,886 @@
|
|||
package org.eclipse.xtext.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.emf.common.notify.NotificationChain;
|
||||
import org.eclipse.emf.common.util.AbstractEList;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class ParallelResourceSet extends XtextResourceSet {
|
||||
|
||||
private final ExecutorService loadingPool;
|
||||
private final ExecutorService linkingPool;
|
||||
private final ReentrantReadWriteLock reentrantReadWriteLock;
|
||||
private final ReadLock readLock;
|
||||
private final WriteLock writeLock;
|
||||
private final Map<Resource, Future<Resource>> nowLoading;
|
||||
|
||||
@Inject
|
||||
public ParallelResourceSet(ThreadPools threadPools) {
|
||||
this.loadingPool = threadPools.loadingPool;
|
||||
this.linkingPool = threadPools.linkingPool;
|
||||
this.reentrantReadWriteLock = new ReentrantReadWriteLock();
|
||||
this.readLock = reentrantReadWriteLock.readLock();
|
||||
this.writeLock = reentrantReadWriteLock.writeLock();
|
||||
setURIResourceMap(new ConcurrentHashMap<>());
|
||||
this.normalizationMap = new ConcurrentHashMap<>();
|
||||
this.nowLoading = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public <Result> List<Result> processResources(List<Resource> resources,
|
||||
Function<? super Resource, ? extends Result> fun) {
|
||||
List<Future<Result>> futures = Lists.newArrayList();
|
||||
for (Resource resource : resources) {
|
||||
futures.add(linkingPool.submit(() -> fun.apply(resource)));
|
||||
}
|
||||
List<Result> result = Lists.newArrayList();
|
||||
for (Future<Result> future : futures) {
|
||||
try {
|
||||
result.add(future.get());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Resource> getResources(List<URI> uris, boolean loadOnDemand) {
|
||||
List<Future<Resource>> futures = Lists.newArrayList();
|
||||
|
||||
for (URI uri : uris) {
|
||||
Map<URI, Resource> map = getURIResourceMap();
|
||||
if (map == null || resourceLocator != null) {
|
||||
futures.add(CompletableFuture.completedFuture(super.getResource(uri, loadOnDemand)));
|
||||
continue;
|
||||
}
|
||||
Resource resource = map.get(uri);
|
||||
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()) {
|
||||
demandLoadHelper(resource);
|
||||
}
|
||||
futures.add(nowLoading.getOrDefault(resource, CompletableFuture.completedFuture(resource)));
|
||||
continue;
|
||||
}
|
||||
|
||||
Resource delegatedResource = delegatedGetResource(uri, loadOnDemand);
|
||||
if (delegatedResource != null) {
|
||||
futures.add(CompletableFuture.completedFuture(delegatedResource));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (loadOnDemand) {
|
||||
resource = demandCreateResource(uri);
|
||||
if (resource == null) {
|
||||
throw new RuntimeException(
|
||||
"Cannot create a resource for '" + uri + "'; a registered resource factory is needed");
|
||||
}
|
||||
|
||||
futures.add(nowLoading.computeIfAbsent(resource, (r) -> loadingPool.submit(() -> {
|
||||
if (!r.isLoaded())
|
||||
super.demandLoadHelper(r);
|
||||
nowLoading.remove(r);
|
||||
return r;
|
||||
})));
|
||||
}
|
||||
}
|
||||
List<Resource> result = Lists.newArrayList();
|
||||
for (Future<Resource> future : futures) {
|
||||
try {
|
||||
result.add(future.get());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(URI uri, boolean loadOnDemand) {
|
||||
Map<URI, Resource> map = getURIResourceMap();
|
||||
if (map == null || resourceLocator != null)
|
||||
return super.getResource(uri, loadOnDemand);
|
||||
Resource resource = map.get(uri);
|
||||
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()) {
|
||||
demandLoadHelper(resource);
|
||||
}
|
||||
try {
|
||||
return nowLoading.getOrDefault(resource, CompletableFuture.completedFuture(resource)).get();
|
||||
} catch(Exception e) {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
Resource delegatedResource = delegatedGetResource(uri, loadOnDemand);
|
||||
if (delegatedResource != null)
|
||||
{
|
||||
return delegatedResource;
|
||||
}
|
||||
|
||||
if (loadOnDemand)
|
||||
{
|
||||
resource = demandCreateResource(uri);
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("Cannot create a resource for '" + uri + "'; a registered resource factory is needed");
|
||||
}
|
||||
|
||||
demandLoadHelper(resource);
|
||||
|
||||
try {
|
||||
return nowLoading.getOrDefault(resource, CompletableFuture.completedFuture(resource)).get();
|
||||
} catch(Exception e) {
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void demandLoadHelper(Resource resource) {
|
||||
try {
|
||||
nowLoading.computeIfAbsent(resource, (r) -> loadingPool.submit(() -> {
|
||||
super.demandLoadHelper(r);
|
||||
return r;
|
||||
})).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource demandCreateResource(URI uri) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
Resource maybeCreated = getURIResourceMap().get(uri);
|
||||
if (maybeCreated != null) {
|
||||
return maybeCreated;
|
||||
}
|
||||
return super.demandCreateResource(uri);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4
|
||||
*/
|
||||
@Override
|
||||
protected ResourcesList createResourceList() {
|
||||
return new ResourcesList() {
|
||||
|
||||
private static final long serialVersionUID = -4217297874237993194L;
|
||||
|
||||
@Override
|
||||
protected NotificationChain inverseAdd(Resource resource, NotificationChain notifications) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.inverseAdd(resource, notifications);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.containsAll(c);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource set(int index, Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.set(index, object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.add(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.add(index, object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Resource> collection) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.addAll(collection);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends Resource> collection) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.addAll(index, collection);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.remove(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> collection) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.retainAll(collection);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(int index, Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.move(index, object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.equals(object);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hashCode();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.toString();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Resource> iterator() {
|
||||
return new SynchronizedEIterator();
|
||||
}
|
||||
|
||||
class SynchronizedEIterator extends AbstractEList<Resource>.EIterator<Resource> {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hasNext();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource next() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.next();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.remove();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SynchronizedEListIterator extends AbstractEList<Resource>.EListIterator<Resource> {
|
||||
|
||||
public SynchronizedEListIterator() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SynchronizedEListIterator(int index) {
|
||||
super(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.add(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hasNext();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hasPrevious();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource next() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.next();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource previous() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.previous();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.previousIndex();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.remove();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.set(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<Resource> listIterator() {
|
||||
return new SynchronizedEListIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<Resource> listIterator(int index) {
|
||||
readLock.lock();
|
||||
try {
|
||||
int size = size();
|
||||
if (index < 0 || index > size)
|
||||
throw new BasicIndexOutOfBoundsException(index, size);
|
||||
return new SynchronizedEListIterator(index);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object object) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.indexOf(object);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object object) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.lastIndexOf(object);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.toArray();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.toArray(array);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(int size, Object[] data) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.setData(size, data);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource get(int index) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.get(index);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource basicGet(int index) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.basicGet(index);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shrink() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.shrink();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grow(int minimumCapacity) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.grow(minimumCapacity);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.clone();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUnique(Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.addUnique(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUnique(int index, Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.addUnique(index, object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAllUnique(Collection<? extends Resource> collection) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.addAllUnique(collection);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAllUnique(int index, Collection<? extends Resource> collection) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.addAllUnique(index, collection);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAllUnique(Object[] objects, int start, int end) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.addAllUnique(objects, start, end);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAllUnique(int index, Object[] objects, int start, int end) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.addAllUnique(index, objects, start, end);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationChain basicAdd(Resource object, NotificationChain notifications) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.basicAdd(object, notifications);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource remove(int index) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.remove(index);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> collection) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.removeAll(collection);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationChain basicRemove(Object object, NotificationChain notifications) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.basicRemove(object, notifications);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.clear();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource setUnique(int index, Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.setUnique(index, object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationChain basicSet(int index, Resource object, NotificationChain notifications) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.basicSet(index, object, notifications);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource move(int targetIndex, int sourceIndex) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return super.move(targetIndex, sourceIndex);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> basicList() {
|
||||
return super.basicList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Resource> basicIterator() {
|
||||
return new SynchronizedNonResolvingEIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<Resource> basicListIterator() {
|
||||
return new SynchronizedNonResolvingEListIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<Resource> basicListIterator(int index) {
|
||||
readLock.lock();
|
||||
try {
|
||||
int size = size();
|
||||
if (index < 0 || index > size)
|
||||
throw new BasicIndexOutOfBoundsException(index, size);
|
||||
return new SynchronizedNonResolvingEListIterator(index);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
class SynchronizedNonResolvingEIterator extends AbstractEList<Resource>.NonResolvingEIterator<Resource> {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hasNext();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource next() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.next();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.remove();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SynchronizedNonResolvingEListIterator
|
||||
extends AbstractEList<Resource>.NonResolvingEListIterator<Resource> {
|
||||
|
||||
public SynchronizedNonResolvingEListIterator() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SynchronizedNonResolvingEListIterator(int index) {
|
||||
super(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.add(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hasNext();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.hasPrevious();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource next() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.next();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource previous() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.previous();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.previousIndex();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.remove();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Resource object) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
super.set(object);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
readLock.lock();
|
||||
try {
|
||||
return super.contains(object);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.eclipse.xtext.resource;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class ThreadPools {
|
||||
|
||||
public final ExecutorService loadingPool = Executors.newFixedThreadPool(3);
|
||||
public final ExecutorService linkingPool = Executors.newFixedThreadPool(5);
|
||||
|
||||
public void stop() throws Exception {
|
||||
loadingPool.shutdownNow();
|
||||
loadingPool.awaitTermination(10, TimeUnit.SECONDS);
|
||||
linkingPool.shutdownNow();
|
||||
linkingPool.awaitTermination(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue