diff options
author | Eike Stepper | 2021-01-18 09:11:03 +0000 |
---|---|---|
committer | Eike Stepper | 2021-01-18 09:11:03 +0000 |
commit | 59809ad7a0ed977e3bf724831979731a7b5fe7f3 (patch) | |
tree | dfef72070e34841fe3eec34d9abbe1922d50aeac /plugins | |
parent | b12d8415cfc75a3aa7cba16459f295137c3bb879 (diff) | |
download | cdo-59809ad7a0ed977e3bf724831979731a7b5fe7f3.tar.gz cdo-59809ad7a0ed977e3bf724831979731a7b5fe7f3.tar.xz cdo-59809ad7a0ed977e3bf724831979731a7b5fe7f3.zip |
[562241] [DB] Connection leak when query is cancelled
https://bugs.eclipse.org/bugs/show_bug.cgi?id=562241
Diffstat (limited to 'plugins')
17 files changed, 427 insertions, 219 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF index cdb63db848..a96fdca92f 100644 --- a/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.server/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.server;singleton:=true -Bundle-Version: 4.11.1.qualifier +Bundle-Version: 4.12.0.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -10,17 +10,17 @@ Bundle-Activator: org.eclipse.emf.cdo.internal.server.bundle.OM$Activator Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ClassPath: . Require-Bundle: org.eclipse.emf.cdo;bundle-version="[4.0.0,5.0.0)";visibility:=reexport -Export-Package: org.eclipse.emf.cdo.internal.server;version="4.11.1"; +Export-Package: org.eclipse.emf.cdo.internal.server;version="4.12.0"; x-friends:="org.eclipse.emf.cdo.server.db, org.eclipse.emf.cdo.server.net4j, org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.workspace, org.eclipse.emf.cdo.server.embedded", - org.eclipse.emf.cdo.internal.server.bundle;version="4.11.1";x-internal:=true, - org.eclipse.emf.cdo.internal.server.mem;version="4.11.1";x-friends:="org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.internal.server.messages;version="4.11.1";x-internal:=true, - org.eclipse.emf.cdo.internal.server.syncing;version="4.11.1";x-friends:="org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.server;version="4.11.1", - org.eclipse.emf.cdo.server.mem;version="4.11.1", - org.eclipse.emf.cdo.spi.server;version="4.11.1" + org.eclipse.emf.cdo.internal.server.bundle;version="4.12.0";x-internal:=true, + org.eclipse.emf.cdo.internal.server.mem;version="4.12.0";x-friends:="org.eclipse.emf.cdo.tests", + org.eclipse.emf.cdo.internal.server.messages;version="4.12.0";x-internal:=true, + org.eclipse.emf.cdo.internal.server.syncing;version="4.12.0";x-friends:="org.eclipse.emf.cdo.tests", + org.eclipse.emf.cdo.server;version="4.12.0", + org.eclipse.emf.cdo.server.mem;version="4.12.0", + org.eclipse.emf.cdo.spi.server;version="4.12.0" Automatic-Module-Name: org.eclipse.emf.cdo.server diff --git a/plugins/org.eclipse.emf.cdo.server/pom.xml b/plugins/org.eclipse.emf.cdo.server/pom.xml index 52e057af02..86e76c4cd2 100644 --- a/plugins/org.eclipse.emf.cdo.server/pom.xml +++ b/plugins/org.eclipse.emf.cdo.server/pom.xml @@ -25,7 +25,7 @@ <groupId>org.eclipse.emf.cdo</groupId> <artifactId>org.eclipse.emf.cdo.server</artifactId> - <version>4.11.1-SNAPSHOT</version> + <version>4.12.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/QueryManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/QueryManager.java index adade52ce4..a844166de6 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/QueryManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/QueryManager.java @@ -191,21 +191,9 @@ public class QueryManager extends Lifecycle implements InternalQueryManager * @author Simon McDuff * @since 2.0 */ - private class QueryContext implements IQueryContext, Runnable + private final class QueryContext implements IQueryContext, Runnable { - private CDOBranchPoint branchPoint; - - private InternalQueryResult queryResult; - - private boolean started; - - private boolean cancelled; - - private int resultCount; - - private Future<?> future; - - private IListener sessionListener = new IListener() + private final IListener sessionListener = new IListener() { @Override public void notifyEvent(IEvent event) @@ -223,21 +211,24 @@ public class QueryManager extends Lifecycle implements InternalQueryManager } }; + private CDOBranchPoint branchPoint; + + private InternalQueryResult queryResult; + + private boolean started; + + private volatile boolean cancelled; + + private int resultCount; + + private Future<?> future; + public QueryContext(InternalQueryResult queryResult) { this.queryResult = queryResult; // Remember the branchPoint because it can change InternalView view = getView(); - - // long timeStamp = view.getTimeStamp(); - // if (timeStamp == CDOBranchPoint.UNSPECIFIED_DATE && repository.isSupportingAudits()) - // { - // timeStamp = repository.getTimeStamp(); - // } - // - // branchPoint = view.getBranch().getPoint(timeStamp); - branchPoint = CDOBranchUtil.copyBranchPoint(view); } @@ -274,17 +265,27 @@ public class QueryManager extends Lifecycle implements InternalQueryManager this.future = future; } + @Override + public boolean isCancelled() + { + return cancelled; + } + public void cancel() { - cancelled = true; - if (future != null) + if (!cancelled) { - future.cancel(allowInterruptRunningQueries); - } + cancelled = true; - if (!started) - { - unregister(this); + if (future != null) + { + future.cancel(allowInterruptRunningQueries); + } + + if (!started) + { + unregister(this); + } } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java index 3b6c996ef6..d2a02c5b2e 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java @@ -25,7 +25,6 @@ import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.common.revision.CDORevisionCacheAdder; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.common.util.CDOQueryInfo; -import org.eclipse.emf.cdo.server.IQueryContext; import org.eclipse.emf.cdo.server.IQueryHandler; import org.eclipse.emf.cdo.server.ISession; import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2; @@ -39,7 +38,6 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.emf.cdo.spi.server.InternalCommitContext; import org.eclipse.emf.cdo.spi.server.LongIDStoreAccessor; -import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.collection.Pair; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.om.monitor.OMMonitor; @@ -69,110 +67,6 @@ public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw2, Durab { private final MEMStore store; - private final IQueryHandler testQueryHandler = new IQueryHandler() - { - @Override - public void executeQuery(CDOQueryInfo info, IQueryContext queryContext) - { - List<Object> filters = new ArrayList<>(); - Object context = info.getParameters().get("context"); //$NON-NLS-1$ - Long sleep = (Long)info.getParameters().get("sleep"); //$NON-NLS-1$ - Integer integers = (Integer)info.getParameters().get("integers"); //$NON-NLS-1$ - Integer error = (Integer)info.getParameters().get("error"); //$NON-NLS-1$ - - if (integers != null) - { - executeQuery(integers, error, queryContext); - return; - } - - if (context != null) - { - if (context instanceof EClass) - { - final EClass eClass = (EClass)context; - filters.add(new Object() - { - @Override - public int hashCode() - { - return eClass.hashCode(); - } - - @Override - public boolean equals(Object obj) - { - InternalCDORevision revision = (InternalCDORevision)obj; - return revision.getEClass().equals(eClass); - } - }); - } - } - - int i = 0; - for (InternalCDORevision revision : store.getCurrentRevisions()) - { - if (sleep != null) - { - try - { - Thread.sleep(sleep); - } - catch (InterruptedException ex) - { - throw WrappedException.wrap(ex); - } - } - - if (isValid(revision, filters)) - { - throwExceptionAt(error, ++i); - - if (!queryContext.addResult(revision)) - { - // No more results allowed - break; - } - } - } - } - - private void throwExceptionAt(Integer error, int i) - { - if (error != null && i == error) - { - throw new RuntimeException("Simulated problem in query execution at result " + i); - } - } - - private void executeQuery(int integers, Integer error, IQueryContext queryContext) - { - for (int i = 1; i <= integers; ++i) - { - throwExceptionAt(error, i); - - if (!queryContext.addResult(i)) - { - // No more results allowed - break; - } - } - } - - private boolean isValid(InternalCDORevision revision, List<Object> filters) - { - for (Object filter : filters) - { - if (!filter.equals(revision)) - { - return false; - } - } - - return true; - } - }; - private List<InternalCDORevision> newRevisions; public MEMStoreAccessor(MEMStore store, ISession session) @@ -448,11 +342,6 @@ public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw2, Durab @Override public IQueryHandler getQueryHandler(CDOQueryInfo info) { - if ("TEST".equals(info.getQueryLanguage())) //$NON-NLS-1$ - { - return testQueryHandler; - } - return null; } @@ -601,12 +490,6 @@ public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw2, Durab } @Override - protected void doActivate() throws Exception - { - // Do nothing - } - - @Override protected void doDeactivate() throws Exception { if (newRevisions != null) @@ -614,17 +497,7 @@ public class MEMStoreAccessor extends LongIDStoreAccessor implements Raw2, Durab newRevisions.clear(); newRevisions = null; } - } - @Override - protected void doPassivate() throws Exception - { - // Pooling of store accessors not supported - } - - @Override - protected void doUnpassivate() throws Exception - { - // Pooling of store accessors not supported + super.doDeactivate(); } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IQueryContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IQueryContext.java index 3ae21e8dc7..e61d0726fc 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IQueryContext.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IQueryContext.java @@ -27,6 +27,11 @@ public interface IQueryContext extends CDOBranchPoint public IView getView(); /** + * @since 4.12 + */ + public boolean isCancelled(); + + /** * @since 4.0 */ public int getResultCount(); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/StoreThreadLocal.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/StoreThreadLocal.java index c7684c6792..ea5b3a4e76 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/StoreThreadLocal.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/StoreThreadLocal.java @@ -47,7 +47,7 @@ public final class StoreThreadLocal public static Runnable wrap(ISession session, Runnable runnable) { return () -> { - StoreThreadLocal.setSession((InternalSession)session); + setSession((InternalSession)session); try { @@ -55,7 +55,7 @@ public final class StoreThreadLocal } finally { - StoreThreadLocal.release(); + release(); } }; } @@ -66,7 +66,7 @@ public final class StoreThreadLocal public static <T> Callable<T> wrap(ISession session, Callable<T> callable) { return () -> { - StoreThreadLocal.setSession((InternalSession)session); + setSession((InternalSession)session); try { @@ -74,7 +74,7 @@ public final class StoreThreadLocal } finally { - StoreThreadLocal.release(); + release(); } }; } diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java index ee7f6720fc..a7ae42d08e 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java +++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/SQLQueryTest.java @@ -255,15 +255,16 @@ public class SQLQueryTest extends AbstractCDOTest { msg("Query for products"); CDOQuery productQuery = transaction.createQuery("sql", "SELECT CDO_ID FROM MODEL1_PRODUCT1"); - final CloseableIterator<Product1> iterator = productQuery.getResultAsync(Product1.class); + CloseableIterator<Product1> iterator = productQuery.getResultAsync(Product1.class); int counter = 0; while (iterator.hasNext()) { - final Product1 product = iterator.next(); - // meaningless but do something + Product1 product = iterator.next(); + + // Meaningless but do something. assertEquals(true, product != null); - counter++; - if (counter == NUM_OF_PRODUCTS / 2) + + if (counter++ == NUM_OF_PRODUCTS / 2) { iterator.close(); } @@ -273,6 +274,21 @@ public class SQLQueryTest extends AbstractCDOTest transaction.commit(); } + public void testIteratorCancelation() throws Exception + { + CDOSession session = openSession(); + createTestSet(session); + + CDOView view = session.openView(); + + // Query many times to see whether we run out of store accessors. + for (int i = 0; i < 2000; i++) + { + CDOQuery query = view.createQuery("sql", "SELECT CDO_ID FROM MODEL1_PRODUCT1"); + query.getResultAsync(Product1.class).close(); + } + } + public void _testNonCdoObjectQueries() throws Exception { msg("Opening session"); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MEMStoreQueryTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MEMStoreQueryTest.java index 09ab7be4d9..3a29ba63f4 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MEMStoreQueryTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MEMStoreQueryTest.java @@ -14,6 +14,9 @@ package org.eclipse.emf.cdo.tests; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig.MEMConfig; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig.MEMConfig.MEMStoreAccessor_UT; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig.MEMConfig.MEMStore_UT; import org.eclipse.emf.cdo.tests.model1.Category; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -57,7 +60,7 @@ public class MEMStoreQueryTest extends AbstractCDOTest transaction.commit(); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); List<Object> result = query.getResult(Object.class); assertEquals(5, result.size()); for (Object object : result) @@ -73,7 +76,7 @@ public class MEMStoreQueryTest extends AbstractCDOTest { CDOSession session = openSession(); CDOTransaction transaction = session.openTransaction(); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); query.setParameter("error", 5000); query.setParameter("integers", 10000); @@ -125,7 +128,7 @@ public class MEMStoreQueryTest extends AbstractCDOTest transaction.commit(); System.out.println(category1.eClass().getEPackage().getNsURI()); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); query.setParameter("context", getModel1Package().getCategory()); List<Category> result = query.getResult(Category.class); @@ -139,7 +142,7 @@ public class MEMStoreQueryTest extends AbstractCDOTest public void testQueryCancel_successful() throws Exception { CDOTransaction transaction = initialize(500); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); query.setParameter("sleep", 1000L); final CloseableIterator<Object> result = query.getResultAsync(Object.class); result.close(); @@ -161,7 +164,7 @@ public class MEMStoreQueryTest extends AbstractCDOTest public void testQueryCancel_ViewClose() throws Exception { CDOTransaction transaction = initialize(500); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); query.setParameter("sleep", 1000L); final CloseableIterator<Object> result = query.getResultAsync(Object.class); CDOSession session = transaction.getSession(); @@ -181,7 +184,7 @@ public class MEMStoreQueryTest extends AbstractCDOTest public void testQueryCancel_SessionClose() throws Exception { CDOTransaction transaction = initialize(500); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); query.setParameter("sleep", 1000L); final CloseableIterator<Object> result = query.getResultAsync(Object.class); transaction.getSession().close(); @@ -196,6 +199,27 @@ public class MEMStoreQueryTest extends AbstractCDOTest }.assertNoTimeOut(); } + public void testQueryCancel_storeAccessorLeak() throws Exception + { + MEMStoreAccessor_UT.testQueryLatchCreate(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, null); + + Set<MEMStoreAccessor_UT> accessors = ((MEMStore_UT)getRepository().getStore()).getStoreAccessors(); + int originalAccessors = accessors.size(); + + CloseableIterator<Object> result = query.getResultAsync(Object.class); + sleep(100); // Give the store accessor of this query a chance to become active. + result.close(); + + MEMStoreAccessor_UT.testQueryLatchCountDown(); + + int leakedAccessors = accessors.size() - originalAccessors; + assertEquals("Store accessor leak detected", 0, leakedAccessors); + } + public void testQueryAsync_UnsupportedLanguage() throws Exception { CDOTransaction transaction = initialize(100); @@ -205,10 +229,11 @@ public class MEMStoreQueryTest extends AbstractCDOTest { CloseableIterator<Object> result = query.getResultAsync(Object.class); result.hasNext(); - fail("Should throw an exception"); + fail("Exception expected"); } catch (Exception expected) { + // SUCCESS. } } @@ -220,10 +245,11 @@ public class MEMStoreQueryTest extends AbstractCDOTest try { query.getResult(Object.class); - fail("Should throw an exception"); + fail("Exception expected"); } catch (Exception expected) { + // SUCCESS. } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248915_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248915_Test.java index f848b5ffa5..61ebfcd47b 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248915_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248915_Test.java @@ -67,9 +67,9 @@ public class Bugzilla_248915_Test extends AbstractCDOTest mySupplier = null; myPurchaseOrder = null; - /* #### End first phase of persisting the data in the CDO Server #### */ + /* End first phase of persisting the data in the CDO Server */ - /* #### Start of second phase where the data is fetched from the CDO Server #### */ + /* Start of second phase where the data is fetched from the CDO Server */ /* 7) Open a completely new session and transaction onto the persisted data */ CDOSession session2 = openSession(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_260756_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_260756_Test.java index 0e0f82430f..ba66d77772 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_260756_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_260756_Test.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.tests.bugzilla; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig.MEMConfig; import org.eclipse.emf.cdo.tests.model1.Category; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -31,8 +32,6 @@ import java.util.Set; */ public class Bugzilla_260756_Test extends AbstractCDOTest { - private static final String LANGUAGE = "TEST"; - @Requires("MEM") public void testBugzilla_260756() throws Exception { @@ -58,7 +57,7 @@ public class Bugzilla_260756_Test extends AbstractCDOTest transaction.commit(); System.out.println(category1.eClass().getEPackage().getNsURI()); - CDOQuery cdoQuery = transaction.createQuery(LANGUAGE, "QUERYSTRING"); + CDOQuery cdoQuery = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); cdoQuery.setParameter("context", getModel1Package().getCategory()); List<Category> queryResult = cdoQuery.getResult(Category.class); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_397948_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_397948_Test.java index 8b318ee85c..33078a21d9 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_397948_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_397948_Test.java @@ -14,6 +14,7 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.AbstractCDOTest; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig.MEMConfig; import org.eclipse.emf.cdo.tests.model1.Category; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.transaction.CDOTransaction; @@ -124,7 +125,7 @@ public class Bugzilla_397948_Test extends AbstractCDOTest transaction.commit(); - CDOQuery query = transaction.createQuery("TEST", "QUERYSTRING"); + CDOQuery query = transaction.createQuery(MEMConfig.TEST_QUERY_LANGUAGE, "QUERYSTRING"); query.setParameter("context", getModel1Package().getCategory()); List<Category> result = query.getResult(Category.class); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485487_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485487_Test.java index f12fcadc92..4b22a66497 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485487_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485487_Test.java @@ -94,7 +94,7 @@ public class Bugzilla_485487_Test extends AbstractCDOTest transaction.options().setCommitInfoTimeout(1000); transaction.createResource(getResourcePath("/test1")); - msg("#### Commit-1"); + msg("--> Commit-1"); try { @@ -108,14 +108,14 @@ public class Bugzilla_485487_Test extends AbstractCDOTest assertEquals(true, expected.getMessage().contains("Timeout after")); } - msg("#### Rollback"); + msg("--> Rollback"); forceTimeout = false; transaction.rollback(); transaction.createResource(getResourcePath("/test2")); - msg("#### Commit-2"); + msg("--> Commit-2"); transaction.setCommitComment("test2"); transaction.commit(); } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java index 771a1b5ac7..7fdd04e018 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java @@ -19,16 +19,21 @@ import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler; import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager; import org.eclipse.emf.cdo.common.protocol.CDOProtocol.CommitNotificationInfo; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.common.util.CDOQueryInfo; import org.eclipse.emf.cdo.common.util.CountedTimeProvider; import org.eclipse.emf.cdo.internal.common.revision.NOOPRevisionCache; import org.eclipse.emf.cdo.internal.net4j.CDONet4jSessionConfigurationImpl; import org.eclipse.emf.cdo.internal.net4j.CDONet4jSessionImpl; +import org.eclipse.emf.cdo.internal.server.mem.MEMStore; +import org.eclipse.emf.cdo.internal.server.mem.MEMStoreAccessor; import org.eclipse.emf.cdo.internal.server.syncing.OfflineClone; import org.eclipse.emf.cdo.internal.server.syncing.RepositorySynchronizer; import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration; import org.eclipse.emf.cdo.server.CDOServerBrowser; import org.eclipse.emf.cdo.server.CDOServerUtil; import org.eclipse.emf.cdo.server.IPermissionManager; +import org.eclipse.emf.cdo.server.IQueryContext; +import org.eclipse.emf.cdo.server.IQueryHandler; import org.eclipse.emf.cdo.server.IQueryHandlerProvider; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IRepository.Handler; @@ -59,6 +64,7 @@ import org.eclipse.emf.cdo.spi.server.InternalSessionManager; import org.eclipse.emf.cdo.spi.server.InternalStore; import org.eclipse.emf.cdo.spi.server.InternalSynchronizableRepository; import org.eclipse.emf.cdo.spi.server.InternalUnitManager; +import org.eclipse.emf.cdo.spi.server.StoreAccessorBase; import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.config.IScenario; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; @@ -72,6 +78,7 @@ import org.eclipse.net4j.connector.IConnector; import org.eclipse.net4j.jvm.JVMUtil; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.ReflectUtil; +import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.concurrent.ConcurrencyUtil; import org.eclipse.net4j.util.concurrent.DelegatingExecutorService; import org.eclipse.net4j.util.concurrent.ExecutorServiceFactory; @@ -90,6 +97,7 @@ import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.security.IAuthenticator; import org.eclipse.net4j.util.tests.AbstractOMTest; +import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.spi.cdo.InternalCDOSession; import org.junit.Assert; @@ -103,11 +111,14 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; /** * @author Eike Stepper @@ -1260,6 +1271,8 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf { public static final String STORE_NAME = "MEM"; + public static final String TEST_QUERY_LANGUAGE = "TEST_LANGUAGE"; + private static final long serialVersionUID = 1L; public MEMConfig(String name) @@ -1287,7 +1300,257 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf @Override public IStore createStore(String repoName) { - return MEMStoreUtil.createMEMStore(); + return new MEMStore_UT(); + } + + /** + * @author Eike Stepper + */ + public static class MEMStore_UT extends MEMStore + { + private final Set<MEMStoreAccessor_UT> storeAccessors = Collections.synchronizedSet(new HashSet<>()); + + public MEMStore_UT() + { + } + + public MEMStore_UT(int listLimit) + { + super(listLimit); + } + + public Set<MEMStoreAccessor_UT> getStoreAccessors() + { + return Collections.unmodifiableSet(storeAccessors); + } + + @Override + public MEMStoreAccessor createReader(ISession session) + { + return acquireAccessor(new MEMStoreAccessor_UT(this, session)); + } + + @Override + public MEMStoreAccessor createWriter(ITransaction transaction) + { + return new MEMStoreAccessor_UT(this, transaction); + } + + private MEMStoreAccessor acquireAccessor(MEMStoreAccessor_UT accessor) + { + storeAccessors.add(accessor); + return accessor; + } + + @Override + protected void releaseAccessor(StoreAccessorBase accessor) + { + storeAccessors.remove(accessor); + super.releaseAccessor(accessor); + } + } + + /** + * @author Eike Stepper + */ + public static class MEMStoreAccessor_UT extends MEMStoreAccessor + { + private static CountDownLatch testQueryLatch; + + private final IQueryHandler testQueryHandler = new IQueryHandler() + { + @Override + public void executeQuery(CDOQueryInfo info, IQueryContext queryContext) + { + if (testQueryLatch != null) + { + try + { + testQueryLatch.await(5000L, TimeUnit.MILLISECONDS); + } + catch (InterruptedException ex) + { + Thread.currentThread().interrupt(); + } + finally + { + testQueryLatch = null; + } + + return; + } + + List<Object> filters = new ArrayList<>(); + Object context = info.getParameters().get("context"); //$NON-NLS-1$ + Long sleep = (Long)info.getParameters().get("sleep"); //$NON-NLS-1$ + Integer integers = (Integer)info.getParameters().get("integers"); //$NON-NLS-1$ + Integer error = (Integer)info.getParameters().get("error"); //$NON-NLS-1$ + + if (integers != null) + { + executeQuery(integers, error, queryContext); + return; + } + + if (context != null) + { + if (context instanceof EClass) + { + final EClass eClass = (EClass)context; + filters.add(new Object() + { + @Override + public int hashCode() + { + return eClass.hashCode(); + } + + @Override + public boolean equals(Object obj) + { + InternalCDORevision revision = (InternalCDORevision)obj; + return revision.getEClass().equals(eClass); + } + }); + } + } + + int i = 0; + for (InternalCDORevision revision : getStore().getCurrentRevisions()) + { + if (sleep != null) + { + try + { + Thread.sleep(sleep); + } + catch (InterruptedException ex) + { + throw WrappedException.wrap(ex); + } + } + + if (isValid(revision, filters)) + { + throwExceptionAt(error, ++i); + + if (!queryContext.addResult(revision)) + { + // No more results allowed + break; + } + } + } + } + + private void throwExceptionAt(Integer error, int i) + { + if (error != null && i == error) + { + throw new RuntimeException("Simulated problem in query execution at result " + i); + } + } + + private void executeQuery(int integers, Integer error, IQueryContext queryContext) + { + for (int i = 1; i <= integers; ++i) + { + throwExceptionAt(error, i); + + if (!queryContext.addResult(i)) + { + // No more results allowed + break; + } + } + } + + private boolean isValid(InternalCDORevision revision, List<Object> filters) + { + for (Object filter : filters) + { + if (!filter.equals(revision)) + { + return false; + } + } + + return true; + } + }; + + private boolean passivated; + + public MEMStoreAccessor_UT(MEMStore store, ISession session) + { + super(store, session); + } + + public MEMStoreAccessor_UT(MEMStore store, ITransaction transaction) + { + super(store, transaction); + } + + @Override + public IQueryHandler getQueryHandler(CDOQueryInfo info) + { + if (TEST_QUERY_LANGUAGE.equals(info.getQueryLanguage())) + { + return testQueryHandler; + } + + return super.getQueryHandler(info); + } + + public boolean isPassivated() + { + return passivated; + } + + @Override + protected void doPassivate() throws Exception + { + passivated = true; + } + + @Override + protected void doUnpassivate() throws Exception + { + passivated = false; + } + + @Override + protected void doDeactivate() throws Exception + { + if (Thread.currentThread().isInterrupted()) + { + throw new InterruptedException("Thread is interrupted"); + } + + super.doDeactivate(); + } + + public static void testQueryLatchCreate() + { + testQueryLatch = new CountDownLatch(1); + } + + public static void testQueryLatchCountDown() + { + try + { + testQueryLatch.countDown(); + } + catch (NullPointerException ex) + { + //$FALL-THROUGH$ + } + finally + { + // Give the store accessor of this query a chance to become inactive. + ConcurrencyUtil.sleep(100); + } + } } /** diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java index f6380160fa..64e4771e7b 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java @@ -34,8 +34,10 @@ import org.eclipse.net4j.Net4jUtil; import org.eclipse.net4j.acceptor.IAcceptor; import org.eclipse.net4j.connector.IConnector; import org.eclipse.net4j.jvm.JVMUtil; +import org.eclipse.net4j.signal.SignalProtocol; import org.eclipse.net4j.tcp.TCPUtil; import org.eclipse.net4j.tcp.ssl.SSLUtil; +import org.eclipse.net4j.util.ReflectUtil; import org.eclipse.net4j.util.concurrent.DelegatingExecutorService; import org.eclipse.net4j.util.concurrent.ExecutorServiceFactory; import org.eclipse.net4j.util.container.ContainerUtil; @@ -58,6 +60,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import java.io.File; +import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; import java.util.Date; @@ -360,6 +363,8 @@ public abstract class SessionConfig extends Config implements ISessionConfig { private static final long serialVersionUID = 1L; + private static final Field PROTOCOL_TESTING_FIELD = ReflectUtil.getField(SignalProtocol.class, "testing"); + private transient CDOViewProvider viewProvider; public Net4j(String name) @@ -466,7 +471,16 @@ public abstract class SessionConfig extends Config implements ISessionConfig CDOViewProviderRegistry.INSTANCE.removeViewProvider(viewProvider); } - super.tearDown(); + ReflectUtil.setValue(PROTOCOL_TESTING_FIELD, null, true); + + try + { + super.tearDown(); + } + finally + { + ReflectUtil.setValue(PROTOCOL_TESTING_FIELD, null, false); + } } public abstract IAcceptor getAcceptor(); diff --git a/plugins/org.eclipse.net4j/META-INF/MANIFEST.MF b/plugins/org.eclipse.net4j/META-INF/MANIFEST.MF index 732b39d389..cbcd167755 100644 --- a/plugins/org.eclipse.net4j/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.net4j/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.net4j;singleton:=true -Bundle-Version: 4.11.0.qualifier +Bundle-Version: 4.11.1.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -11,7 +11,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ClassPath: . Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)";resolution:=optional, org.eclipse.net4j.util;bundle-version="[3.0.0,4.0.0)";visibility:=reexport -Export-Package: org.eclipse.internal.net4j;version="4.11.0"; +Export-Package: org.eclipse.internal.net4j;version="4.11.1"; x-friends:="org.eclipse.net4j.http.server, org.eclipse.net4j.jvm, org.eclipse.net4j.tcp, @@ -21,7 +21,7 @@ Export-Package: org.eclipse.internal.net4j;version="4.11.0"; org.eclipse.net4j.http.tests, org.eclipse.net4j.tests, org.eclipse.net4j.trace", - org.eclipse.internal.net4j.buffer;version="4.11.0"; + org.eclipse.internal.net4j.buffer;version="4.11.1"; x-friends:="org.eclipse.net4j.http.server, org.eclipse.net4j.jvm, org.eclipse.net4j.tcp, @@ -31,18 +31,18 @@ Export-Package: org.eclipse.internal.net4j;version="4.11.0"; org.eclipse.net4j.http.tests, org.eclipse.net4j.tests, org.eclipse.net4j.trace", - org.eclipse.internal.net4j.bundle;version="4.11.0";x-internal:=true, - org.eclipse.net4j;version="4.11.0", - org.eclipse.net4j.acceptor;version="4.11.0", - org.eclipse.net4j.buffer;version="4.11.0", - org.eclipse.net4j.channel;version="4.11.0", - org.eclipse.net4j.connector;version="4.11.0", - org.eclipse.net4j.protocol;version="4.11.0", - org.eclipse.net4j.signal;version="4.11.0", - org.eclipse.net4j.signal.confirmation;version="4.11.0", - org.eclipse.net4j.signal.heartbeat;version="4.11.0", - org.eclipse.net4j.signal.security;version="4.11.0", - org.eclipse.net4j.signal.wrapping;version="4.11.0", - org.eclipse.spi.net4j;version="4.11.0" + org.eclipse.internal.net4j.bundle;version="4.11.1";x-internal:=true, + org.eclipse.net4j;version="4.11.1", + org.eclipse.net4j.acceptor;version="4.11.1", + org.eclipse.net4j.buffer;version="4.11.1", + org.eclipse.net4j.channel;version="4.11.1", + org.eclipse.net4j.connector;version="4.11.1", + org.eclipse.net4j.protocol;version="4.11.1", + org.eclipse.net4j.signal;version="4.11.1", + org.eclipse.net4j.signal.confirmation;version="4.11.1", + org.eclipse.net4j.signal.heartbeat;version="4.11.1", + org.eclipse.net4j.signal.security;version="4.11.1", + org.eclipse.net4j.signal.wrapping;version="4.11.1", + org.eclipse.spi.net4j;version="4.11.1" Eclipse-BuddyPolicy: registered Automatic-Module-Name: org.eclipse.net4j diff --git a/plugins/org.eclipse.net4j/pom.xml b/plugins/org.eclipse.net4j/pom.xml index 43ce3019d5..3d85005857 100644 --- a/plugins/org.eclipse.net4j/pom.xml +++ b/plugins/org.eclipse.net4j/pom.xml @@ -25,7 +25,7 @@ <groupId>org.eclipse.emf.cdo</groupId> <artifactId>org.eclipse.net4j</artifactId> - <version>4.11.0-SNAPSHOT</version> + <version>4.11.1-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/SignalProtocol.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/SignalProtocol.java index e768919546..e76ee87ffe 100644 --- a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/SignalProtocol.java +++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/SignalProtocol.java @@ -100,6 +100,11 @@ public class SignalProtocol<INFRA_STRUCTURE> extends Protocol<INFRA_STRUCTURE> i private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_SIGNAL, SignalProtocol.class); + /** + * This field can only be set via reflection, e.g., by SessionConfig.Net4j. + */ + private static boolean testing; + private long timeout = DEFAULT_TIMEOUT; private IStreamWrapper streamWrapper; @@ -341,16 +346,21 @@ public class SignalProtocol<INFRA_STRUCTURE> extends Protocol<INFRA_STRUCTURE> i @Override protected void doBeforeDeactivate() throws Exception { - synchronized (signals) + if (!testing) { - // Wait at most 10 seconds for running signals to finish - int waitMillis = 10 * 1000; - long stop = System.currentTimeMillis() + waitMillis; - while (!signals.isEmpty() && System.currentTimeMillis() < stop) + synchronized (signals) { - signals.wait(1000L); + // Wait at most 10 seconds for running signals to finish + int waitMillis = 10 * 1000; + long stop = System.currentTimeMillis() + waitMillis; + while (!signals.isEmpty() && System.currentTimeMillis() < stop) + { + signals.wait(1000L); + } } } + + super.doBeforeDeactivate(); } @Override |