blob: adc69f302135bf17daf710094a8186e1c7eadc65 [file] [log] [blame]
/*
* Copyright (c) 2015 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.CDOLock;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.tests.config.IModelConfig;
import org.eclipse.emf.cdo.tests.config.ISessionConfig;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires;
import org.eclipse.emf.cdo.tests.model1.Category;
import org.eclipse.emf.cdo.tests.model1.Company;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.net4j.util.io.IOUtil;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Implementation based on LockingSequenceTest.
*
* @author Eike Stepper
*/
@Requires({ ISessionConfig.CAPABILITY_NET4J_JVM, IModelConfig.CAPABILITY_NATIVE })
public class Locking_SequenceWithChildListTest_DISABLED extends AbstractLockingTest
{
private static final int USERS = 10;
private static final int ADDITIONS = 100;
private static final int RETRIES = 5;
private static final long LOCK_TIMEOUT = 5000;
private static final boolean LOG = false;
@Override
protected void doSetUp() throws Exception
{
disableConsole();
super.doSetUp();
}
@Override
protected void doTearDown() throws Exception
{
disableConsole();
super.doTearDown();
}
public void testSafeCounter() throws Exception
{
disableConsole();
final Company company = getModel1Factory().createCompany();
final CDOSession session = openSession();
CDOTransaction transaction = session.openTransaction();
CDOResource resource = transaction.createResource(getResourcePath("/res1"));
resource.getContents().add(company);
transaction.commit();
CountDownLatch latch = new CountDownLatch(USERS);
User[] users = new User[USERS];
for (int userID = 0; userID < USERS; userID++)
{
users[userID] = new User(userID, latch, company);
}
for (int userID = 0; userID < USERS; userID++)
{
users[userID].start();
}
// A maximum of USERS x ADDITIONS x RETRIES calls to .lock() : should not last more than USERS x ADDITIONS x
// RETRIES x LOCK_TIMEOUT milliseconds...
// Let's leave them twice as long, just to be sure!
long TIMEOUT = 2 * USERS * ADDITIONS * RETRIES * LOCK_TIMEOUT;
latch.await(TIMEOUT, TimeUnit.MILLISECONDS);
IOUtil.OUT().println("FINISHED");
//
// CHECK UP TIME!
//
CDOObject cdoObject = CDOUtil.getCDOObject(company);
CDOLock lock = cdoObject.cdoWriteLock();
assertEquals("Lock hasn't been released!", false, lock.isLockedByOthers());
assertEquals("There are unfinished users", 0, latch.getCount());
Exception exception = null;
for (int userID = 0; userID < USERS; userID++)
{
Exception ex = users[userID].getException();
if (ex != null)
{
exception = ex;
ex.printStackTrace();
}
}
if (exception != null)
{
throw exception;
}
for (User user : users)
{
if (null == user.getException())
{
assertEquals(ADDITIONS, user.getAdditions());
}
}
IOUtil.OUT().println("SUCCESS");
}
private final class User extends Thread
{
private final CountDownLatch latch;
private Company c;
private int additions;
private Exception exception;
public User(int userID, CountDownLatch latch, Company company)
{
super("User" + userID);
this.latch = latch;
c = company;
}
public Exception getException()
{
return exception;
}
public int getAdditions()
{
return additions;
}
@Override
public void run()
{
try
{
for (int allocation = 0; allocation < ADDITIONS; allocation++)
{
CDOSession session = Locking_SequenceWithChildListTest_DISABLED.this.openSession();
CDOTransaction transaction = session.openTransaction();
try
{
synchronized (transaction)
{
for (int retry = 0; retry < RETRIES; ++retry)
{
Company company = transaction.getObject(c);
CDOObject cdoObject = CDOUtil.getCDOObject(company);
CDOLock lock = cdoObject.cdoWriteLock();
TimerThread timerThread = new TimerThread(getName() + ": lock(" + LOCK_TIMEOUT + ")");
try
{
timerThread.start();
lock.lock(LOCK_TIMEOUT);
Category category = getModel1Factory().createCategory();
company.getCategories().add(category);
try
{
int version = cdoObject.cdoRevision().getVersion() + 1;
System.out.println(getName() + ": committing version " + version);
transaction.setCommitComment(getName() + ": version " + version);
transaction.commit();
++additions;
msg("Category added " + getAdditions());
break; // No more retries.
}
catch (Exception ex)
{
exception = ex;
return;
}
}
catch (TimeoutException ex)
{
msg("Lock timed out.");
exception = ex;
if (retry == RETRIES - 1)
{
msg("Exhausted!");
return;
}
msg("Trying again...");
}
finally
{
timerThread.done();
}
}
}
}
finally
{
session.close();
}
}
}
finally
{
latch.countDown();
}
}
private void msg(String string)
{
if (LOG)
{
IOUtil.OUT().println(getName() + ": " + string);
}
}
}
private final class TimerThread extends Thread
{
private final long timeout = LOCK_TIMEOUT * 4;
private boolean done;
public TimerThread(String name)
{
super(name);
}
public void done()
{
done = true;
}
@Override
public void run()
{
long start = System.currentTimeMillis();
while (!done)
{
long now = System.currentTimeMillis();
if (now - start > timeout)
{
System.out.println();
System.out.println(
getName() + " is taking more time than required : " + (now - start) + " ms > " + timeout + " ms.");
}
try
{
sleep(10);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
if (LOG)
{
System.out.println(getName() + " : interrupted");
}
return;
}
}
long end = System.currentTimeMillis();
if (LOG)
{
System.out.println("" + getName() + " took " + (end - start) + " ms.");
}
}
}
}