blob: bfbb07d1ef23f57de92e47cc56eaae1cedf3e015 [file] [log] [blame]
/*
* Copyright (c) 2014, 2018 Eike Stepper (Loehne, 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.net4j.util.tests;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.concurrent.RWOLockManager;
import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
import org.eclipse.net4j.util.io.IOUtil;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Eike Stepper
*/
public class RWOLockManagerTest extends AbstractOMTest
{
private static final int USERS = 10;
private static final int ALLOCATIONS = 10;
private static final int RETRIES = 5;
private static final Set<Object> EXCLUSIVE_RESOURCE = Collections.singleton(new Object()
{
@Override
public String toString()
{
return "EXCLUSIVE_RESOURCE";
}
});
public void testRWOLockManager() throws Exception
{
AtomicInteger resource = new AtomicInteger(-1);
RWOLockManager<Object, User> lockManager = new RWOLockManager<>();
User[] users = new User[USERS];
User[] allocators = new User[USERS * ALLOCATIONS];
CountDownLatch started = new CountDownLatch(1);
CountDownLatch finished = new CountDownLatch(USERS);
for (int userID = 0; userID < USERS; userID++)
{
users[userID] = new User(userID, started, finished, allocators, lockManager, resource);
}
for (int userID = 0; userID < USERS; userID++)
{
users[userID].start();
}
started.countDown();
await(finished);
IOUtil.OUT().println("FINISHED");
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;
}
IOUtil.OUT().println("SUCCESS");
}
/**
* @author Eike Stepper
*/
private static final class User extends Thread
{
private final CountDownLatch started;
private final CountDownLatch finished;
private final User[] allocators;
private final RWOLockManager<Object, User> lockManager;
private final AtomicInteger resource;
private Exception exception;
public User(int userID, CountDownLatch started, CountDownLatch finished, User[] allocators, RWOLockManager<Object, User> lockManager,
AtomicInteger resource)
{
super("User-" + userID);
this.started = started;
this.finished = finished;
this.allocators = allocators;
this.lockManager = lockManager;
this.resource = resource;
}
public Exception getException()
{
return exception;
}
@Override
public void run()
{
await(started);
try
{
for (int allocation = 0; allocation < ALLOCATIONS; allocation++)
{
for (int retry = RETRIES; retry >= 0; --retry)
{
try
{
lockManager.lock(this, EXCLUSIVE_RESOURCE, LockType.WRITE, 1, 10000000, null, null);
break;
}
catch (TimeoutRuntimeException ex)
{
if (retry == 0)
{
exception = ex;
return;
}
msg("Lock timed out. Trying again...");
}
catch (InterruptedException ex)
{
exception = ex;
return;
}
}
try
{
int id = resource.get() + 1;
if (allocators[id] != null)
{
throw new IllegalStateException(id + " already allocated by " + allocators[id]);
}
allocators[id] = this;
resource.set(id);
msg("ALLOCATED " + id);
}
catch (Exception ex)
{
exception = ex;
return;
}
finally
{
lockManager.unlock(this, EXCLUSIVE_RESOURCE, LockType.WRITE, 1, null, null);
}
}
}
finally
{
finished.countDown();
}
}
@Override
public String toString()
{
return getName();
}
private void msg(String string)
{
IOUtil.OUT().println(getName() + ": " + string);
}
}
}