blob: 5d97b56edabe45655456adcbdac24e59cc0525f1 [file] [log] [blame]
/*
* Copyright (c) 2009-2012 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:
* Simon McDuff - initial API and implementation
*/
package org.eclipse.emf.cdo.tests.bugzilla;
import org.eclipse.emf.cdo.common.id.CDOID;
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.model1.OrderDetail;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.net4j.util.transaction.TransactionException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Concurrency problem: attribute of enumeration type not updated correctly between two clients
* <p>
* See bug 273565
*
* @author Simon McDuff
*/
public class Bugzilla_273565_Test extends AbstractCDOTest
{
/**
* Thread A: Update the value to 3 and 2 only if the value is at 1.<br>
* Thread B: Update the value to 1 only if the value is at 2.
* <p>
* Thread B will load objects.<br>
* But at the same time will update remote changes.<br>
* Causing not to have the latest version.
* <p>
* See bug 273565
*/
public void _testBugzilla_273565() throws Exception
{
final CountDownLatch start = new CountDownLatch(1);
final boolean[] done = { false };
final Exception exception[] = { null };
final OrderDetail orderDetail = getModel1Factory().createOrderDetail();
orderDetail.setPrice(2);
final CDOSession session = openSession();
final CDOTransaction transaction = session.openTransaction();
CDOResource resource = transaction.createResource(getResourcePath("/test1"));
resource.getContents().add(orderDetail);
transaction.commit();
final CDOID id = CDOUtil.getCDOObject(orderDetail).cdoID();
Thread threadA = new Thread()
{
@Override
public void run()
{
CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
OrderDetail orderDetail = (OrderDetail)CDOUtil.getEObject(transaction.getObject(id));
try
{
start.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
while (!done[0])
{
while (orderDetail.getPrice() != 1 && !done[0])
{
sleep(1);
}
try
{
orderDetail.setPrice(3);
transaction.commit();
}
catch (CommitException ex)
{
transaction.rollback();
continue;
}
try
{
orderDetail.setPrice(2);
transaction.commit();
}
catch (CommitException ex)
{
transaction.rollback();
continue;
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
exception[0] = ex;
}
finally
{
session.close();
}
}
};
threadA.setDaemon(true);
threadA.start();
Thread threadB = new Thread()
{
@Override
public void run()
{
try
{
start.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
for (int i = 0; i < 50 && exception[0] == null; i++)
{
try
{
orderDetail.setPrice(1);
transaction.commit();
}
catch (TransactionException ex)
{
transaction.rollback();
continue;
}
while (orderDetail.getPrice() != 2)
{
sleep(1);
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
exception[0] = ex;
}
done[0] = true;
}
};
threadB.setDaemon(true);
threadB.start();
start.countDown();
threadA.join(DEFAULT_TIMEOUT);
threadA.interrupt();
threadB.join(DEFAULT_TIMEOUT);
threadB.interrupt();
if (exception[0] != null)
{
throw exception[0];
}
}
/**
* See bug 273565
*/
public void _testBugzilla_273565_Lock() throws Exception
{
disableConsole();
OrderDetail orderDetail = getModel1Factory().createOrderDetail();
orderDetail.setPrice(2);
CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
CDOResource resource = transaction.createResource(getResourcePath("/test1"));
resource.getContents().add(orderDetail);
transaction.commit();
final CDOID id = CDOUtil.getCDOObject(orderDetail).cdoID();
session.close();
final CountDownLatch start = new CountDownLatch(1);
final Exception exception[] = { null };
class Modifier extends Thread
{
private float price;
public Modifier(float price)
{
setDaemon(true);
this.price = price;
}
@Override
public void run()
{
CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
OrderDetail orderDetail = (OrderDetail)transaction.getObject(id);
try
{
start.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
for (int i = 0; i < 5000 && exception[0] == null; i++)
{
CDOUtil.getCDOObject(orderDetail).cdoWriteLock().lock(DEFAULT_TIMEOUT);
System.out.println("\nGot lock: " + price + " --> " + CDOUtil.getCDOObject(orderDetail).cdoRevision());
sleep(1L);
orderDetail.setPrice(price);
System.out.println("Committing: " + price);
transaction.commit();
sleep(1L);
}
}
catch (Exception ex)
{
ex.printStackTrace();
exception[0] = ex;
}
finally
{
session.close();
}
}
}
Modifier threadA = new Modifier(1);
threadA.start();
Modifier threadB = new Modifier(2);
threadB.start();
start.countDown();
threadA.join(DEFAULT_TIMEOUT);
threadA.interrupt();
threadB.join(DEFAULT_TIMEOUT);
threadB.interrupt();
if (exception[0] != null)
{
throw exception[0];
}
}
/**
* See bug 273565
*/
public void testBugzilla_273565_NoThreads() throws Exception
{
OrderDetail orderDetail = getModel1Factory().createOrderDetail();
orderDetail.setPrice(1);
CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
CDOResource resource = transaction.createResource(getResourcePath("/test1"));
resource.getContents().add(orderDetail);
transaction.commit();
CDOTransaction transaction2 = session.openTransaction();
OrderDetail orderDetail2 = (OrderDetail)CDOUtil.getEObject(transaction2.getObject(orderDetail));
CDOUtil.getCDOObject(orderDetail).cdoWriteLock().lock(DEFAULT_TIMEOUT);
orderDetail.setPrice(2);
boolean locked = CDOUtil.getCDOObject(orderDetail2).cdoWriteLock()
.tryLock(DEFAULT_TIMEOUT_EXPECTED, TimeUnit.MILLISECONDS);
assertEquals(false, locked);
}
}