Experimental: ParallelResourceSet

This commit is contained in:
Sebastian Zarnekow 2019-01-20 16:02:46 +01:00
parent 6e192c7b40
commit a5fb49354d
7 changed files with 1097 additions and 15 deletions

View file

@ -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;

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -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);
}
}

View file

@ -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;
{

View file

@ -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();
}
}
};
}
}

View file

@ -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);
}
}