diff options
author | Eike Stepper | 2016-02-04 11:02:49 +0000 |
---|---|---|
committer | Eike Stepper | 2016-02-04 11:06:07 +0000 |
commit | 08257c866d21ff0592802c754820f9996d45802e (patch) | |
tree | 8f9f3f898c442cf6670f97339d5ab237b0c64d25 /plugins/org.eclipse.emf.cdo.tests/src | |
parent | 45b55081f4200d675e18ec5cbd4a120b1b52bfe4 (diff) | |
download | cdo-08257c866d21ff0592802c754820f9996d45802e.tar.gz cdo-08257c866d21ff0592802c754820f9996d45802e.tar.xz cdo-08257c866d21ff0592802c754820f9996d45802e.zip |
[486458] Provide support for optimized loading and notifying of object units
https://bugs.eclipse.org/bugs/show_bug.cgi?id=486458
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.tests/src')
15 files changed, 1724 insertions, 15 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java index 1598df139e..419531a15d 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java @@ -116,7 +116,7 @@ public class AllConfigs extends ConfigTestSuite testClasses.add(WorkspaceTest.class); testClasses.add(BackupTest.class); testClasses.add(ResourceModificationTrackingTest.class); - testClasses.add(CDOStaleReferencePolicyTests.class); + testClasses.add(CDOStaleReferencePolicyTest.class); // TODO testClasses.add(RemoteSessionManagerTest.class); // TODO testClasses.add(NonCDOResourceTest.class); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTests.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTest.java index 56500ab5a3..9d4634c2ea 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTests.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTest.java @@ -29,7 +29,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil; * * @author Esteban Dugueperoux */ -public class CDOStaleReferencePolicyTests extends AbstractCDOTest +public class CDOStaleReferencePolicyTest extends AbstractCDOTest { private static final String RESOURCE_NAME = "test1.model1"; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java index 352c77c0c6..6f9f3f209e 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java @@ -50,6 +50,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOSession; import java.util.Collection; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * @author Eike Stepper @@ -234,7 +235,7 @@ public class SessionTest extends AbstractCDOTest { try { - startLatch.await(); + startLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); msg("Committing NOW!"); commitTime[0] = transaction.commit().getTimeStamp(); @@ -251,7 +252,7 @@ public class SessionTest extends AbstractCDOTest CDOSession session2 = openSession(); startLatch.countDown(); - stopLatch.await(); + stopLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); assertEquals(true, session2.waitForUpdate(commitTime[0], DEFAULT_TIMEOUT)); transaction.getSession().close(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java new file mode 100644 index 0000000000..33e8c17d58 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2016 Eike Stepper (Berlin, Germany) 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 + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.tests; + +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration; +import org.eclipse.emf.cdo.net4j.CDONet4jUtil; +import org.eclipse.emf.cdo.server.net4j.CDONet4jServerUtil; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.tests.model1.Customer; +import org.eclipse.emf.cdo.tests.model1.Model1Factory; +import org.eclipse.emf.cdo.tests.model1.Model1Package; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.tests.model1.Product1; +import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; +import org.eclipse.emf.cdo.tests.model1.SalesOrder; +import org.eclipse.emf.cdo.tests.model1.Supplier; +import org.eclipse.emf.cdo.transaction.CDOTransaction; + +import org.eclipse.net4j.Net4jUtil; +import org.eclipse.net4j.connector.IConnector; +import org.eclipse.net4j.tcp.TCPUtil; +import org.eclipse.net4j.util.container.IPluginContainer; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.InternalEList; + +import java.util.Iterator; + +/** + * @author Eike Stepper + */ +public class UnitManagerMain +{ + private static final String RESOURCE_NAME = "test"; + + private static final boolean ADD_UNIQUE = true; + + private static long start; + + /** + * @author Eike Stepper + */ + public static final class FillRepository + { + public static void main(String[] args) throws Exception + { + CDOSession session = openSession(); + + try + { + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(RESOURCE_NAME); + + for (int i = 0; i < 1; i++) + { + start("Fill " + i); + Company company = Model1Factory.eINSTANCE.createCompany(); + add(resource.getContents(), company); + fillCompany(company); + stop(); + + start("Commit " + i); + transaction.commit(); + stop(); + } + } + finally + { + session.close(); + } + } + + private static void fillCompany(Company company) + { + for (int i = 0; i < 5; i++) + { + Category category = Model1Factory.eINSTANCE.createCategory(); + add(company.getCategories(), category); + fillCategory(category, 5); + } + + for (int i = 0; i < 1000; i++) + { + Supplier supplier = Model1Factory.eINSTANCE.createSupplier(); + add(company.getSuppliers(), supplier); + } + + for (int i = 0; i < 1000; i++) + { + Customer customer = Model1Factory.eINSTANCE.createCustomer(); + add(company.getCustomers(), customer); + } + + for (int i = 0; i < 1000; i++) + { + PurchaseOrder order = Model1Factory.eINSTANCE.createPurchaseOrder(); + order.setSupplier(company.getSuppliers().get(i)); + add(company.getPurchaseOrders(), order); + + for (int j = 0; j < 100; j++) + { + OrderDetail orderDetail = Model1Factory.eINSTANCE.createOrderDetail(); + add(order.getOrderDetails(), orderDetail); + } + } + + for (int i = 0; i < 1000; i++) + { + SalesOrder order = Model1Factory.eINSTANCE.createSalesOrder(); + order.setCustomer(company.getCustomers().get(i)); + add(company.getSalesOrders(), order); + + for (int j = 0; j < 100; j++) + { + OrderDetail orderDetail = Model1Factory.eINSTANCE.createOrderDetail(); + add(order.getOrderDetails(), orderDetail); + } + } + } + + private static void fillCategory(Category category, int depth) + { + for (int i = 0; i < 5; i++) + { + Category child = Model1Factory.eINSTANCE.createCategory(); + add(category.getCategories(), child); + if (depth > 1) + { + fillCategory(child, depth - 1); + } + } + + for (int i = 0; i < 20; i++) + { + Product1 product = Model1Factory.eINSTANCE.createProduct1(); + add(category.getProducts(), product); + } + } + + private static <T extends EObject> void add(EList<T> list, T object) + { + if (ADD_UNIQUE) + { + ((InternalEList<T>)list).addUnique(object); + } + else + { + list.add(object); + } + } + } + + /** + * @author Eike Stepper + */ + public static final class PrefetchResource + { + public static void main(String[] args) throws Exception + { + CDOSession session = openSession(); + + try + { + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(RESOURCE_NAME); + + start("Prefetch Resource"); + resource.cdoPrefetch(CDORevision.DEPTH_INFINITE); + stop(); + + iterateResource(resource); + } + finally + { + session.close(); + } + } + } + + /** + * @author Eike Stepper + */ + public static final class CreateUnit + { + public static void main(String[] args) throws Exception + { + CDOSession session = openSession(); + + try + { + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(RESOURCE_NAME); + + start("Create Unit"); + resource.cdoView().getUnitManager().createUnit(resource); + stop(); + + iterateResource(resource); + } + finally + { + session.close(); + } + } + } + + /** + * @author Eike Stepper + */ + public static final class OpenUnit + { + public static void main(String[] args) throws Exception + { + CDOSession session = openSession(); + + try + { + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(RESOURCE_NAME); + + start("Open Unit"); + resource.cdoView().getUnitManager().openUnit(resource); + stop(); + + iterateResource(resource); + } + finally + { + session.close(); + } + } + } + + private static CDOSession openSession() + { + IConnector connector = TCPUtil.getConnector(IPluginContainer.INSTANCE, "localhost"); + + CDONet4jSessionConfiguration configuration = CDONet4jUtil.createNet4jSessionConfiguration(); + configuration.setConnector(connector); + configuration.setRepositoryName("repo1"); + return configuration.openNet4jSession(); + } + + private static void iterateResource(CDOResource resource) + { + start("Iterate"); + for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();) + { + it.next(); + } + + stop(); + } + + private static void start(String msg) + { + start = System.currentTimeMillis(); + System.out.print(msg + ": "); + } + + private static void stop() + { + long stop = System.currentTimeMillis(); + System.out.println(stop - start); + start = stop; + } + + static + { + Model1Package.eINSTANCE.getClass(); + + Net4jUtil.prepareContainer(IPluginContainer.INSTANCE); + TCPUtil.prepareContainer(IPluginContainer.INSTANCE); + CDONet4jServerUtil.prepareContainer(IPluginContainer.INSTANCE); + CDONet4jUtil.prepareContainer(IPluginContainer.INSTANCE); + IPluginContainer.INSTANCE.activate(); + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java index 558d16f004..2fe86adfd0 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java @@ -31,6 +31,7 @@ import org.eclipse.net4j.util.io.IOUtil; import java.util.Map; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * LastCommitTimeStamp updated even when a serverSide Error occurred. @@ -82,9 +83,10 @@ public class Bugzilla_329254_Test extends AbstractCDOTest // grant the other session access to enter and // block until it has left again. enterLatch.countDown(); + try { - leaveLatch.await(); + leaveLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { @@ -244,7 +246,7 @@ public class Bugzilla_329254_Test extends AbstractCDOTest try { // wait until session 2 has entered write. - enterLatch.await(); + enterLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java index 98f48c2f1e..094c48b482 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java @@ -21,6 +21,7 @@ import org.eclipse.net4j.util.event.IEvent; import org.eclipse.net4j.util.event.IListener; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * @author Martin Fluegge @@ -70,7 +71,7 @@ public class Bugzilla_340709_Test extends AbstractCDOTest try { - latch.await(); + latch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java index d974bc46c7..3d2694de88 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java @@ -24,6 +24,7 @@ import org.eclipse.net4j.util.event.IEvent; import org.eclipse.net4j.util.event.IListener; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * @author Egidijus Vaisnora @@ -55,7 +56,7 @@ public class Bugzilla_349793_Test extends AbstractCDOTest try { testExecutionLatch.countDown(); - invalidationLatch.await(); + invalidationLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { @@ -66,7 +67,7 @@ public class Bugzilla_349793_Test extends AbstractCDOTest }); long timestamp = doSecondSessionSync(); - testExecutionLatch.await(); + testExecutionLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); CDOTransaction freshTransaction = session.openTransaction(); invalidationLatch.countDown(); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java index f2408663bf..4fd143d666 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java @@ -4,7 +4,7 @@ * 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 - * + * * Contributors: * Eike Stepper - initial API and implementation */ @@ -38,7 +38,6 @@ import java.util.LinkedHashSet; */ public class Bugzilla_423699_Test extends AbstractLockingTest { - private CDOSession session; private InternalCDOTransaction tx; @@ -112,6 +111,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest { tx.enableDurableLocking(); } + CDOID containerID = container.cdoID(); CDOID childID = child.cdoID(); @@ -119,6 +119,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest Collection<CDOObject> objectsToLock = new LinkedHashSet<CDOObject>(); objectsToLock.add(container); objectsToLock.add(child); + tx.lockObjects(objectsToLock, LockType.WRITE, 10000); assertIsLocked(durableLocking, true, containerID); assertIsLocked(durableLocking, true, childID); @@ -128,8 +129,10 @@ public class Bugzilla_423699_Test extends AbstractLockingTest // Step 4: commit tx.commit(new NullProgressMonitor()); + // Lock should be deleted on detached object assertIsLocked(durableLocking, false, childID); + // Lock should be deleted only if lock autorelease is enabled assertIsLocked(durableLocking, !autoReleaseLocksEnabled, containerID); @@ -142,6 +145,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest session = openSession(); tx = (InternalCDOTransaction)session.openTransaction(durableLockingID); tx.options().setAutoReleaseLocksEnabled(autoReleaseLocksEnabled); + // Lock states should not have changed assertIsLocked(durableLocking, false, childID); assertIsLocked(durableLocking, !autoReleaseLocksEnabled, containerID); @@ -165,6 +169,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest if (durably) { LockGrade durableLock = null; + try { InternalSession session = getRepository().getSessionManager().getSession(tx.getSessionID()); @@ -177,12 +182,14 @@ public class Bugzilla_423699_Test extends AbstractLockingTest { StoreThreadLocal.release(); } + assertEquals(elementID + " has not the expected durable lock status", shouldBeLocked, durableLock != null); } // Step 2: check lock ArrayList<CDOID> elementIDs = new ArrayList<CDOID>(); elementIDs.add(elementID); + CDOLockState cdoLockState = tx.getLockStates(elementIDs)[0]; assertEquals(elementID + " has wrong lock status", shouldBeLocked, cdoLockState.getWriteLockOwner() != null); } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java index 33ca285381..1408bb950d 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java @@ -32,8 +32,6 @@ public class Bugzilla_427773_Test extends AbstractCDOTest @Override public void setUp() throws Exception { - SUPPRESS_OUTPUT = true; - UserManager userManager = new UserManager(); userManager.activate(); userManager.addUser(USER_1_CREDENTIALS.getUserID(), USER_1_CREDENTIALS.getPassword()); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java index 7abbea6672..92c0c44cce 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java @@ -54,13 +54,12 @@ public class Bugzilla_485961_Test extends AbstractCDOTest InternalRepository repository = getRepository(); CDORevisionProvider revisionProvider = new ManagedRevisionProvider(repository.getRevisionManager(), repository.getBranchManager().getMainBranch().getHead()); - CDOID rootResourceID = repository.getRootResourceID(); StoreThreadLocal.setSession(repository.getSessionManager().getSession(session.getSessionID())); try { - assertEquals(8, traverse(revisionProvider, rootResourceID)); + assertEquals(4, traverse(revisionProvider, res1.cdoID())); } finally { diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java new file mode 100644 index 0000000000..015d974929 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2016 Eike Stepper (Berlin, Germany) 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 + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.CDOState; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.util.CDOException; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.server.IRepository.Props; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.spi.server.InternalSession; +import org.eclipse.emf.cdo.spi.server.InternalView; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.tests.model1.Customer; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.tests.model1.Product1; +import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; +import org.eclipse.emf.cdo.tests.model1.SalesOrder; +import org.eclipse.emf.cdo.tests.model1.Supplier; +import org.eclipse.emf.cdo.tests.util.TestAdapter; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CDOUtil; +import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.ConcurrentAccessException; +import org.eclipse.emf.cdo.view.CDOAdapterPolicy; +import org.eclipse.emf.cdo.view.CDOUnit; + +import org.eclipse.emf.common.notify.impl.AdapterImpl; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.InternalEList; +import org.eclipse.emf.spi.cdo.InternalCDOView; + +import java.util.Iterator; +import java.util.Map; + +/** + * Bug 486458 - Provide support for optimized loading and notifying of object units + * + * @author Eike Stepper + */ +@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" }) +@Skips(IRepositoryConfig.CAPABILITY_BRANCHING) +@CleanRepositoriesBefore(reason = "Instrumented repository") +@CleanRepositoriesAfter(reason = "Instrumented repository") +public class Bugzilla_486458_Test extends AbstractCDOTest +{ + @Override + protected void doSetUp() throws Exception + { + Map<String, Object> map = getTestProperties(); + map.put(Props.SUPPORTING_UNITS, Boolean.toString(true)); + + super.doSetUp(); + } + + public void testPrefetchBigModel() throws Exception + { + fillRepository(); + clearCache(getRepository().getRevisionManager()); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + long start = System.currentTimeMillis(); + resource.cdoPrefetch(CDORevision.DEPTH_INFINITE); + long stop = System.currentTimeMillis(); + System.out.println("Prefetched: " + (stop - start)); + + int count = iterateResource(resource); + assertEquals(7714, count); + } + + public void testCreateUnit() throws Exception + { + fillRepository(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + assertEquals(false, transaction.getUnitManager().isUnit(resource)); + assertEquals(0, transaction.getUnitManager().getOpenUnits().length); + + InternalSession serverSession = getRepository().getSessionManager().getSession(session.getSessionID()); + InternalView serverView = serverSession.getView(transaction.getViewID()); + CDOID childID = CDOUtil.getCDOObject(resource.getContents().get(0)).cdoID(); + assertEquals(false, serverView.isInOpenUnit(childID)); + + long start = System.currentTimeMillis(); + CDOUnit unit = transaction.getUnitManager().createUnit(resource); + long stop = System.currentTimeMillis(); + System.out.println("Created Unit: " + (stop - start)); + + assertEquals(true, transaction.getUnitManager().isUnit(resource)); + assertEquals(1, transaction.getUnitManager().getOpenUnits().length); + assertSame(unit, transaction.getUnitManager().getOpenUnits()[0]); + assertSame(unit, transaction.getUnitManager().getOpenUnit(resource)); + assertEquals(true, serverView.isInOpenUnit(childID)); + + int count = iterateResource(resource); + assertEquals(7714, count); + + unit.close(); + assertEquals(true, transaction.getUnitManager().isUnit(resource)); + assertEquals(0, transaction.getUnitManager().getOpenUnits().length); + assertEquals(null, transaction.getUnitManager().getOpenUnit(resource)); + assertEquals(false, serverView.isInOpenUnit(childID)); + } + + public void testDetectNestedUnit() throws Exception + { + fillRepository(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + CDOUnit unit = transaction.getUnitManager().createUnit(resource); + EObject parent = resource.getFolder(); + EObject child = resource.getContents().get(0); + + try + { + transaction.getUnitManager().createUnit(parent); + fail("CDOException expected"); + } + catch (CDOException expected) + { + // SUCCESS + } + + try + { + transaction.getUnitManager().createUnit(child); + fail("CDOException expected"); + } + catch (CDOException expected) + { + // SUCCESS + } + + assertEquals(true, transaction.getUnitManager().isUnit(resource)); + assertEquals(false, transaction.getUnitManager().isUnit(parent)); + assertEquals(false, transaction.getUnitManager().isUnit(child)); + + assertEquals(1, transaction.getUnitManager().getOpenUnits().length); + assertSame(unit, transaction.getUnitManager().getOpenUnits()[0]); + } + + public void testOpenUnit() throws Exception + { + fillRepository(); + + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + CDOUnit createdUnit = transaction.getUnitManager().createUnit(resource); + assertEquals(7714, createdUnit.getElements()); + + session.close(); + } + + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + assertEquals(true, transaction.getUnitManager().isUnit(resource)); + assertEquals(0, transaction.getUnitManager().getOpenUnits().length); + + long start = System.currentTimeMillis(); + CDOUnit openedUnit = transaction.getUnitManager().openUnit(resource); + assertEquals(7714, openedUnit.getElements()); + long stop = System.currentTimeMillis(); + System.out.println("Opened Unit: " + (stop - start)); + + assertEquals(true, transaction.getUnitManager().isUnit(resource)); + assertEquals(1, transaction.getUnitManager().getOpenUnits().length); + assertSame(openedUnit, transaction.getUnitManager().getOpenUnits()[0]); + + int count = iterateResource(resource); + assertEquals(7714, count); + } + } + + public void testUpdateUnit() throws Exception + { + fillRepository(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + CDOUnit unit = transaction.getUnitManager().createUnit(resource); + int elements = unit.getElements(); + + Company company = (Company)resource.getContents().get(0); + Category category = getModel1Factory().createCategory(); + company.getCategories().add(category); + assertEquals(elements + 1, unit.getElements()); + + transaction.commit(); + transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL); + + category.eAdapters().add(new AdapterImpl()); + assertEquals(false, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(category).cdoID())); + + company.getCategories().remove(category); + assertEquals(elements, unit.getElements()); + } + + public void testNotificationsAfterOpenUnit() throws Exception + { + fillRepository(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL); + + CDOResource resource = transaction.getResource(getResourcePath("test")); + Company root = (Company)resource.getContents().get(0); + Category child = (Category)root.eContents().get(0); + Company sibling = (Company)resource.getContents().get(1); + + CDOUnit unit = transaction.getUnitManager().createUnit(root); + + TestAdapter adapter = new TestAdapter(); + root.eAdapters().add(adapter); + child.eAdapters().add(adapter); + sibling.eAdapters().add(adapter); + + assertEquals(false, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(root).cdoID())); + assertEquals(false, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(child).cdoID())); + assertEquals(true, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(sibling).cdoID())); + + InternalSession serverSession = getRepository().getSessionManager().getSession(session.getSessionID()); + InternalView serverView = serverSession.getView(transaction.getViewID()); + assertEquals(false, serverView.hasSubscription(CDOUtil.getCDOObject(root).cdoID())); + assertEquals(false, serverView.hasSubscription(CDOUtil.getCDOObject(child).cdoID())); + assertEquals(true, serverView.hasSubscription(CDOUtil.getCDOObject(sibling).cdoID())); + + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + CDOResource resource2 = transaction2.getResource(getResourcePath("test")); + + Company root2 = (Company)resource2.getContents().get(0); + root2.setName("Name"); + commitAndSync(transaction2, transaction); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(root).cdoState()); + assertEquals("Name", root.getName()); + + Category child2 = (Category)root2.eContents().get(0); + child2.setName("Name"); + commitAndSync(transaction2, transaction); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(child2).cdoState()); + assertEquals("Name", child.getName()); + + Company sibling2 = (Company)resource2.getContents().get(1); + sibling2.setName("Name"); + commitAndSync(transaction2, transaction); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(sibling2).cdoState()); + assertEquals("Name", sibling.getName()); + + unit.close(); + + root2.setName("Name2"); + commitAndSync(transaction2, transaction); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(root).cdoState()); + assertEquals("Name2", root.getName()); + + child2.setName("Name2"); + commitAndSync(transaction2, transaction); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(child2).cdoState()); + assertEquals("Name2", child.getName()); + + sibling2.setName("Name2"); + commitAndSync(transaction2, transaction); + assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(sibling2).cdoState()); + assertEquals("Name2", sibling.getName()); + } + + private void fillRepository() throws ConcurrentAccessException, CommitException + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("test")); + + for (int i = 0; i < 3; i++) + { + Company company = getModel1Factory().createCompany(); + addUnique(resource.getContents(), company); + fillCompany(company); + + long start = System.currentTimeMillis(); + transaction.commit(); + long stop = System.currentTimeMillis(); + System.out.println("Committed: " + (stop - start)); + } + + session.close(); + } + + private void fillCompany(Company company) + { + for (int i = 0; i < 5; i++) + { + Category category = getModel1Factory().createCategory(); + addUnique(company.getCategories(), category); + fillCategory(category, 3); + } + + for (int i = 0; i < 10; i++) + { + Supplier supplier = getModel1Factory().createSupplier(); + addUnique(company.getSuppliers(), supplier); + } + + for (int i = 0; i < 10; i++) + { + Customer customer = getModel1Factory().createCustomer(); + addUnique(company.getCustomers(), customer); + } + + for (int i = 0; i < 10; i++) + { + PurchaseOrder order = getModel1Factory().createPurchaseOrder(); + order.setSupplier(company.getSuppliers().get(i)); + addUnique(company.getPurchaseOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + + for (int i = 0; i < 10; i++) + { + SalesOrder order = getModel1Factory().createSalesOrder(); + order.setCustomer(company.getCustomers().get(i)); + addUnique(company.getSalesOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + } + + private void fillCategory(Category category, int depth) + { + for (int i = 0; i < 5; i++) + { + Category child = getModel1Factory().createCategory(); + addUnique(category.getCategories(), child); + if (depth > 1) + { + fillCategory(child, depth - 1); + } + } + + for (int i = 0; i < 10; i++) + { + Product1 product = getModel1Factory().createProduct1(); + addUnique(category.getProducts(), product); + } + } + + private static <T extends EObject> void addUnique(EList<T> list, T object) + { + ((InternalEList<T>)list).addUnique(object); + } + + private static int iterateResource(CDOResource resource) + { + int count = 1; + long start = System.currentTimeMillis(); + + for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();) + { + it.next(); + ++count; + } + + long stop = System.currentTimeMillis(); + System.out.println("Iterated: " + (stop - start)); + + return count; + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java new file mode 100644 index 0000000000..a4c7b06814 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2016 Eike Stepper (Berlin, Germany) 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 + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.server.Repository; +import org.eclipse.emf.cdo.internal.server.TransactionCommitContext; +import org.eclipse.emf.cdo.internal.server.UnitManager; +import org.eclipse.emf.cdo.server.IRepository.Props; +import org.eclipse.emf.cdo.server.IUnit; +import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.spi.server.InternalCommitContext; +import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalTransaction; +import org.eclipse.emf.cdo.spi.server.InternalUnitManager; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.tests.model1.Customer; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.tests.model1.Product1; +import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; +import org.eclipse.emf.cdo.tests.model1.SalesOrder; +import org.eclipse.emf.cdo.tests.model1.Supplier; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.ConcurrentAccessException; + +import org.eclipse.net4j.util.om.monitor.OMMonitor; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.InternalEList; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Bug 486458 - Provide support for optimized loading and notifying of object units + * <p> + * Tests that a createUnit() that starts slightly before a commit() considers the newly attached objects. + * + * @author Eike Stepper + */ +@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" }) +@Skips(IRepositoryConfig.CAPABILITY_BRANCHING) +@CleanRepositoriesBefore(reason = "Instrumented repository") +@CleanRepositoriesAfter(reason = "Instrumented repository") +public class Bugzilla_486458a_Test extends AbstractCDOTest +{ + private CountDownLatch unitRegistered; + + private CountDownLatch startInitializeUnit; + + public void testCreateUnitWithParallelCommit() throws Exception + { + fillRepository(); + + unitRegistered = new CountDownLatch(1); + startInitializeUnit = new CountDownLatch(1); + + final int[] committed = { 0 }; + + Thread committer = new Thread("Committer") + { + @Override + public void run() + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + Company company = (Company)resource.getContents().get(0); + Category category = company.getCategories().get(0); + + committed[0] = fillCategory(category, 3); + + try + { + unitRegistered.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (InterruptedException ex) + { + return; + } + + try + { + transaction.commit(); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + + session.close(); + } + }; + + committer.setDaemon(true); + committer.start(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + transaction.getUnitManager().createUnit(resource); + committer.join(DEFAULT_TIMEOUT); + + session = openSession(); + transaction = session.openTransaction(); + resource = transaction.getResource(getResourcePath("test")); + + int count = iterateResource(resource); + int expected = 7714 + committed[0]; + assertEquals(expected, count); + + session = openSession(); + transaction = session.openTransaction(); + resource = transaction.getResource(getResourcePath("test")); + + transaction.getUnitManager().openUnit(resource); + + session = openSession(); + transaction = session.openTransaction(); + resource = transaction.getResource(getResourcePath("test")); + + count = iterateResource(resource); + assertEquals(expected, count); + } + + @Override + public synchronized Map<String, Object> getTestProperties() + { + Map<String, Object> map = super.getTestProperties(); + map.put(Props.SUPPORTING_UNITS, Boolean.toString(true)); + return map; + } + + @Override + protected void doSetUp() throws Exception + { + createRepository(); + super.doSetUp(); + } + + private void createRepository() + { + Repository repository = new Repository.Default() + { + @Override + public InternalCommitContext createCommitContext(InternalTransaction transaction) + { + return new TransactionCommitContext(transaction) + { + @Override + public void write(OMMonitor monitor) + { + if (startInitializeUnit != null) + { + startInitializeUnit.countDown(); + } + + super.write(monitor); + } + }; + } + + @Override + protected InternalUnitManager createUnitManager() + { + return new UnitManager(this) + { + @Override + protected UnitInitializer createUnitInitializer(CDOID rootID, IView view, CDORevisionHandler revisionHandler) + { + return new UnitInitializer(rootID, view, revisionHandler) + { + @Override + public IUnit initialize() + { + if (unitRegistered != null) + { + unitRegistered.countDown(); + } + + try + { + startInitializeUnit.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (InterruptedException ex) + { + return null; + } + + return super.initialize(); + } + }; + } + }; + } + }; + + Map<String, String> props = getRepositoryProperties(); + ((InternalRepository)repository).setProperties(props); + + repository.setName(IRepositoryConfig.REPOSITORY_NAME); + + Map<String, Object> map = getTestProperties(); + map.put(RepositoryConfig.PROP_TEST_REPOSITORY, repository); + } + + private void fillRepository() throws ConcurrentAccessException, CommitException + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("test")); + + for (int i = 0; i < 3; i++) + { + Company company = getModel1Factory().createCompany(); + addUnique(resource.getContents(), company); + fillCompany(company); + + long start = System.currentTimeMillis(); + transaction.commit(); + long stop = System.currentTimeMillis(); + System.out.println("Committed: " + (stop - start)); + } + + session.close(); + } + + private void fillCompany(Company company) + { + for (int i = 0; i < 5; i++) + { + Category category = getModel1Factory().createCategory(); + addUnique(company.getCategories(), category); + fillCategory(category, 3); + } + + for (int i = 0; i < 10; i++) + { + Supplier supplier = getModel1Factory().createSupplier(); + addUnique(company.getSuppliers(), supplier); + } + + for (int i = 0; i < 10; i++) + { + Customer customer = getModel1Factory().createCustomer(); + addUnique(company.getCustomers(), customer); + } + + for (int i = 0; i < 10; i++) + { + PurchaseOrder order = getModel1Factory().createPurchaseOrder(); + order.setSupplier(company.getSuppliers().get(i)); + addUnique(company.getPurchaseOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + + for (int i = 0; i < 10; i++) + { + SalesOrder order = getModel1Factory().createSalesOrder(); + order.setCustomer(company.getCustomers().get(i)); + addUnique(company.getSalesOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + } + + private int fillCategory(Category category, int depth) + { + int count = 0; + + for (int i = 0; i < 5; i++) + { + Category child = getModel1Factory().createCategory(); + addUnique(category.getCategories(), child); + ++count; + + if (depth > 1) + { + count += fillCategory(child, depth - 1); + } + } + + for (int i = 0; i < 10; i++) + { + Product1 product = getModel1Factory().createProduct1(); + addUnique(category.getProducts(), product); + ++count; + } + + return count; + } + + private static <T extends EObject> void addUnique(EList<T> list, T object) + { + ((InternalEList<T>)list).addUnique(object); + } + + private static int iterateResource(CDOResource resource) + { + int count = 1; + long start = System.currentTimeMillis(); + + for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();) + { + it.next(); + ++count; + } + + long stop = System.currentTimeMillis(); + System.out.println("Iterated: " + (stop - start)); + + return count; + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java new file mode 100644 index 0000000000..e6bfa290ed --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2016 Eike Stepper (Berlin, Germany) 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 + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.server.Repository; +import org.eclipse.emf.cdo.internal.server.UnitManager; +import org.eclipse.emf.cdo.server.IRepository.Props; +import org.eclipse.emf.cdo.server.IUnit; +import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalUnitManager; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.tests.model1.Customer; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.tests.model1.Product1; +import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; +import org.eclipse.emf.cdo.tests.model1.SalesOrder; +import org.eclipse.emf.cdo.tests.model1.Supplier; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.ConcurrentAccessException; +import org.eclipse.emf.cdo.view.CDOUnit; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.InternalEList; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Bug 486458 - Provide support for optimized loading and notifying of object units + * <p> + * Tests that a commit() that starts slightly before a createUnit() contributes to the new unit. + * + * @author Eike Stepper + */ +@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" }) +@Skips(IRepositoryConfig.CAPABILITY_BRANCHING) +@CleanRepositoriesBefore(reason = "Instrumented repository") +@CleanRepositoriesAfter(reason = "Instrumented repository") +public class Bugzilla_486458b_Test extends AbstractCDOTest +{ + private CountDownLatch analyzeStarted; + + private CountDownLatch initializeFinished; + + private boolean longCommit; + + public void testShortCommitWithParallelCreateUnit() throws Exception + { + fillRepository(); + + analyzeStarted = new CountDownLatch(1); + + final int[] committed = { 0 }; + + Thread committer = new Thread("Committer") + { + @Override + public void run() + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + Company company = (Company)resource.getContents().get(0); + Category category = company.getCategories().get(0); + + committed[0] = fillCategory(category, 3); + + try + { + transaction.commit(); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + + session.close(); + } + }; + + committer.setDaemon(true); + committer.start(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + transaction.getUnitManager().createUnit(resource); + committer.join(DEFAULT_TIMEOUT); + + session = openSession(); + transaction = session.openTransaction(); + resource = transaction.getResource(getResourcePath("test")); + + int count = iterateResource(resource); + int expected = 7714 + committed[0]; + assertEquals(expected, count); + + session = openSession(); + transaction = session.openTransaction(); + resource = transaction.getResource(getResourcePath("test")); + + CDOUnit unit = transaction.getUnitManager().openUnit(resource); + assertEquals(expected, unit.getElements()); + + session = openSession(); + transaction = session.openTransaction(); + resource = transaction.getResource(getResourcePath("test")); + + count = iterateResource(resource); + assertEquals(expected, count); + } + + public void testLongCommitWithParallelCreateUnit() throws Exception + { + longCommit = true; + testShortCommitWithParallelCreateUnit(); + } + + @Override + public synchronized Map<String, Object> getTestProperties() + { + Map<String, Object> map = super.getTestProperties(); + map.put(Props.SUPPORTING_UNITS, Boolean.toString(true)); + return map; + } + + @Override + protected void doSetUp() throws Exception + { + createRepository(); + super.doSetUp(); + } + + private void createRepository() + { + Repository repository = new Repository.Default() + { + @Override + protected InternalUnitManager createUnitManager() + { + return new UnitManager(this) + { + @Override + protected void attachObjectsHook1() + { + try + { + Thread.sleep(2000); + } + catch (InterruptedException ex) + { + return; + } + + if (analyzeStarted != null) + { + analyzeStarted.countDown(); + } + } + + @Override + public IUnit createUnit(CDOID rootID, IView view, CDORevisionHandler revisionHandler) + { + if (analyzeStarted != null) + { + try + { + analyzeStarted.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (InterruptedException ex) + { + return null; + } + } + + return super.createUnit(rootID, view, revisionHandler); + } + + @Override + protected UnitInitializer createUnitInitializer(CDOID rootID, IView view, CDORevisionHandler revisionHandler) + { + return new UnitInitializer(rootID, view, revisionHandler) + { + @Override + public IUnit initialize() + { + if (longCommit) + { + initializeFinished = new CountDownLatch(1); + } + + try + { + return super.initialize(); + } + finally + { + if (initializeFinished != null) + { + initializeFinished.countDown(); + } + } + } + }; + } + + @Override + public void objectAttacherFinishedCommit(ObjectAttacher objectAttacher) + { + if (initializeFinished != null) + { + try + { + initializeFinished.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + Thread.sleep(2000); + } + catch (InterruptedException ex) + { + return; + } + } + + super.objectAttacherFinishedCommit(objectAttacher); + } + }; + } + }; + + Map<String, String> props = getRepositoryProperties(); + ((InternalRepository)repository).setProperties(props); + + repository.setName(IRepositoryConfig.REPOSITORY_NAME); + + Map<String, Object> map = getTestProperties(); + map.put(RepositoryConfig.PROP_TEST_REPOSITORY, repository); + } + + private void fillRepository() throws ConcurrentAccessException, CommitException + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("test")); + + for (int i = 0; i < 3; i++) + { + Company company = getModel1Factory().createCompany(); + addUnique(resource.getContents(), company); + fillCompany(company); + + long start = System.currentTimeMillis(); + transaction.commit(); + long stop = System.currentTimeMillis(); + System.out.println("Committed: " + (stop - start)); + } + + session.close(); + } + + private void fillCompany(Company company) + { + for (int i = 0; i < 5; i++) + { + Category category = getModel1Factory().createCategory(); + addUnique(company.getCategories(), category); + fillCategory(category, 3); + } + + for (int i = 0; i < 10; i++) + { + Supplier supplier = getModel1Factory().createSupplier(); + addUnique(company.getSuppliers(), supplier); + } + + for (int i = 0; i < 10; i++) + { + Customer customer = getModel1Factory().createCustomer(); + addUnique(company.getCustomers(), customer); + } + + for (int i = 0; i < 10; i++) + { + PurchaseOrder order = getModel1Factory().createPurchaseOrder(); + order.setSupplier(company.getSuppliers().get(i)); + addUnique(company.getPurchaseOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + + for (int i = 0; i < 10; i++) + { + SalesOrder order = getModel1Factory().createSalesOrder(); + order.setCustomer(company.getCustomers().get(i)); + addUnique(company.getSalesOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + } + + private int fillCategory(Category category, int depth) + { + int count = 0; + + for (int i = 0; i < 5; i++) + { + Category child = getModel1Factory().createCategory(); + addUnique(category.getCategories(), child); + ++count; + + if (depth > 1) + { + count += fillCategory(child, depth - 1); + } + } + + for (int i = 0; i < 10; i++) + { + Product1 product = getModel1Factory().createProduct1(); + addUnique(category.getProducts(), product); + ++count; + } + + return count; + } + + private static <T extends EObject> void addUnique(EList<T> list, T object) + { + ((InternalEList<T>)list).addUnique(object); + } + + private static int iterateResource(CDOResource resource) + { + int count = 1; + long start = System.currentTimeMillis(); + + for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();) + { + it.next(); + ++count; + } + + long stop = System.currentTimeMillis(); + System.out.println("Iterated: " + (stop - start)); + + return count; + } +} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java new file mode 100644 index 0000000000..e37086b265 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2016 Eike Stepper (Berlin, Germany) 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 + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.server.Repository; +import org.eclipse.emf.cdo.internal.server.UnitManager; +import org.eclipse.emf.cdo.server.IRepository.Props; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalUnitManager; +import org.eclipse.emf.cdo.tests.AbstractCDOTest; +import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips; +import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig; +import org.eclipse.emf.cdo.tests.model1.Category; +import org.eclipse.emf.cdo.tests.model1.Company; +import org.eclipse.emf.cdo.tests.model1.Customer; +import org.eclipse.emf.cdo.tests.model1.OrderDetail; +import org.eclipse.emf.cdo.tests.model1.Product1; +import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; +import org.eclipse.emf.cdo.tests.model1.SalesOrder; +import org.eclipse.emf.cdo.tests.model1.Supplier; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CommitException; +import org.eclipse.emf.cdo.util.ConcurrentAccessException; +import org.eclipse.emf.cdo.view.CDOUnit; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.InternalEList; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Bug 486458 - Provide support for optimized loading and notifying of object units + * <p> + * Tests that a createUnit() that starts slightly before another createUnit() creates/opens the same new unit. + * + * @author Eike Stepper + */ +@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" }) +@Skips(IRepositoryConfig.CAPABILITY_BRANCHING) +@CleanRepositoriesBefore(reason = "Instrumented repository") +@CleanRepositoriesAfter(reason = "Instrumented repository") +public class Bugzilla_486458c_Test extends AbstractCDOTest +{ + private CountDownLatch createStarted; + + public void testParallelCreateUnits() throws Exception + { + fillRepository(); + + createStarted = new CountDownLatch(1); + + final int[] secondCreated = { 0 }; + + Thread secondCreator = new Thread("Committer") + { + @Override + public void run() + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + try + { + createStarted.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (InterruptedException ex) + { + ex.printStackTrace(); + return; + } + + CDOUnit unit = transaction.getUnitManager().createUnit(resource); + secondCreated[0] = unit.getElements(); + + session.close(); + } + }; + + secondCreator.setDaemon(true); + secondCreator.start(); + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getResource(getResourcePath("test")); + + CDOUnit unit = transaction.getUnitManager().createUnit(resource); + int created = unit.getElements(); + assertEquals(7714, created); + + secondCreator.join(DEFAULT_TIMEOUT); + assertEquals(7714, secondCreated[0]); + } + + @Override + public synchronized Map<String, Object> getTestProperties() + { + Map<String, Object> map = super.getTestProperties(); + map.put(Props.SUPPORTING_UNITS, Boolean.toString(true)); + return map; + } + + @Override + protected void doSetUp() throws Exception + { + createRepository(); + super.doSetUp(); + } + + private void createRepository() + { + Repository repository = new Repository.Default() + { + @Override + protected InternalUnitManager createUnitManager() + { + return new UnitManager(this) + { + @Override + protected void createUnitHook1() + { + if (createStarted != null) + { + createStarted.countDown(); + } + } + }; + } + }; + + Map<String, String> props = getRepositoryProperties(); + ((InternalRepository)repository).setProperties(props); + + repository.setName(IRepositoryConfig.REPOSITORY_NAME); + + Map<String, Object> map = getTestProperties(); + map.put(RepositoryConfig.PROP_TEST_REPOSITORY, repository); + } + + private void fillRepository() throws ConcurrentAccessException, CommitException + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource(getResourcePath("test")); + + for (int i = 0; i < 3; i++) + { + Company company = getModel1Factory().createCompany(); + addUnique(resource.getContents(), company); + fillCompany(company); + + long start = System.currentTimeMillis(); + transaction.commit(); + long stop = System.currentTimeMillis(); + System.out.println("Committed: " + (stop - start)); + } + + session.close(); + } + + private void fillCompany(Company company) + { + for (int i = 0; i < 5; i++) + { + Category category = getModel1Factory().createCategory(); + addUnique(company.getCategories(), category); + fillCategory(category, 3); + } + + for (int i = 0; i < 10; i++) + { + Supplier supplier = getModel1Factory().createSupplier(); + addUnique(company.getSuppliers(), supplier); + } + + for (int i = 0; i < 10; i++) + { + Customer customer = getModel1Factory().createCustomer(); + addUnique(company.getCustomers(), customer); + } + + for (int i = 0; i < 10; i++) + { + PurchaseOrder order = getModel1Factory().createPurchaseOrder(); + order.setSupplier(company.getSuppliers().get(i)); + addUnique(company.getPurchaseOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + + for (int i = 0; i < 10; i++) + { + SalesOrder order = getModel1Factory().createSalesOrder(); + order.setCustomer(company.getCustomers().get(i)); + addUnique(company.getSalesOrders(), order); + + for (int j = 0; j < 10; j++) + { + OrderDetail orderDetail = getModel1Factory().createOrderDetail(); + addUnique(order.getOrderDetails(), orderDetail); + } + } + } + + private int fillCategory(Category category, int depth) + { + int count = 0; + + for (int i = 0; i < 5; i++) + { + Category child = getModel1Factory().createCategory(); + addUnique(category.getCategories(), child); + ++count; + + if (depth > 1) + { + count += fillCategory(child, depth - 1); + } + } + + for (int i = 0; i < 10; i++) + { + Product1 product = getModel1Factory().createProduct1(); + addUnique(category.getProducts(), product); + ++count; + } + + return count; + } + + private static <T extends EObject> void addUnique(EList<T> list, T object) + { + ((InternalEList<T>)list).addUnique(object); + } +} 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 d0f55e331f..2d657e0222 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 @@ -51,6 +51,7 @@ import org.eclipse.emf.cdo.spi.server.InternalRepositorySynchronizer; 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.tests.config.IRepositoryConfig; import org.eclipse.emf.cdo.tests.config.IScenario; import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter; @@ -106,6 +107,8 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf public static final String PROP_TEST_REVISION_MANAGER = "test.repository.RevisionManager"; + public static final String PROP_TEST_UNIT_MANAGER = "test.repository.UnitManager"; + public static final String PROP_TEST_SESSION_MANAGER = "test.repository.SessionManager"; public static final String PROP_TEST_AUTHENTICATOR = "test.repository.Authenticator"; @@ -604,6 +607,12 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf repository.setRevisionManager(revisionManager); + InternalUnitManager unitManager = getTestUnitManager(); + if (unitManager != null) + { + repository.setUnitManager(unitManager); + } + InternalSessionManager sessionManager = getTestSessionManager(); if (sessionManager == null) { @@ -652,6 +661,11 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf return (InternalCDORevisionManager)getTestProperty(PROP_TEST_REVISION_MANAGER); } + protected InternalUnitManager getTestUnitManager() + { + return (InternalUnitManager)getTestProperty(PROP_TEST_UNIT_MANAGER); + } + protected InternalSessionManager getTestSessionManager() { return (InternalSessionManager)getTestProperty(PROP_TEST_SESSION_MANAGER); |