use of co.paralleluniverse.common.util.Function2 in project quasar by puniverse.
the class TransformingChannelTest method testTakeThreadToFibers.
@Test
@SuppressWarnings("null")
public void testTakeThreadToFibers() throws Exception {
// TODO Reorg to try with blocking channel at least meaningful parts
assumeThat(mailboxSize, greaterThan(0));
final Channel<Object> takeSourceCh = newChannel();
// Test 2 fibers failing immediately on take 0 of 1
final ReceivePort<Object> take0RP = Channels.take((ReceivePort<Object>) takeSourceCh, 0);
final SuspendableRunnable take0SR = new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
assertThat(take0RP.receive(), is(nullValue()));
assertThat(take0RP.tryReceive(), is(nullValue()));
long start = System.nanoTime();
assertThat(take0RP.receive(10, TimeUnit.SECONDS), is(nullValue()));
long end = System.nanoTime();
// Should be immediate
assertThat(end - start, lessThan(new Long(5 * 1000 * 1000 * 1000)));
start = System.nanoTime();
assertThat(take0RP.receive(new Timeout(10, TimeUnit.SECONDS)), is(nullValue()));
end = System.nanoTime();
// Should be immediate
assertThat(end - start, lessThan(new Long(5 * 1000 * 1000 * 1000)));
}
};
final Fiber take0Of1Fiber1 = new Fiber("take-0-of-1_fiber1", scheduler, take0SR).start();
final Fiber take0Of1Fiber2 = new Fiber("take-0-of-1_fiber2", scheduler, take0SR).start();
takeSourceCh.send(new Object());
take0Of1Fiber1.join();
take0Of1Fiber2.join();
// 1 left in source, check and cleanup
assertThat(takeSourceCh.receive(), is(notNullValue()));
// Test tryReceive failing immediately when fiber blocked in receive on take 1 of 2
final ReceivePort<Object> take1Of2RP = Channels.take((ReceivePort<Object>) takeSourceCh, 1);
final Fiber timeoutSucceedingTake1Of2 = new Fiber("take-1-of-2_timeout_success", scheduler, new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
final long start = System.nanoTime();
assertThat(take1Of2RP.receive(1, TimeUnit.SECONDS), is(notNullValue()));
final long end = System.nanoTime();
assertThat(end - start, lessThan(new Long(500 * 1000 * 1000)));
}
}).start();
// Let the fiber blocks in receive before starting the try
Thread.sleep(100);
final Fiber tryFailingTake1Of2 = new Fiber("take-1-of-2_try_fail", scheduler, new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
final long start = System.nanoTime();
assertThat(take1Of2RP.tryReceive(), is(nullValue()));
final long end = System.nanoTime();
// Should be immediate
assertThat(end - start, lessThan(new Long(500 * 1000 * 1000)));
}
}).start();
Thread.sleep(100);
// Make messages available
takeSourceCh.send(new Object());
takeSourceCh.send(new Object());
timeoutSucceedingTake1Of2.join();
tryFailingTake1Of2.join();
// 1 left in source, check and cleanup
assertThat(takeSourceCh.receive(), is(notNullValue()));
// Comprehensive take + contention test:
//
// - 1 message available immediately, 2 messages available in a burst on the source after 1s
// - take 2
// - 5 fibers competing on the take source (1 in front)
//
// - one front fiber receiving with 200ms timeout => immediate success
// - one more front fiber receiving with 200ms timeout => fail
// - 3rd fiber taking over, receiving with 200ms timeout => fail
// - 4th fiber taking over, receiving with 1s timeout => success
// - 5th fiber asking untimed receive, waiting in monitor, will bail out because of take threshold
final ReceivePort<Object> take2Of3RPComprehensive = Channels.take((ReceivePort<Object>) takeSourceCh, 2);
final Function2<Long, Integer, Fiber> take1SRFun = new Function2<Long, Integer, Fiber>() {
@Override
public Fiber apply(final Long timeoutMS, final Integer position) {
return new Fiber("take-1-of-2_comprehensive_receiver_" + (timeoutMS >= 0 ? timeoutMS : "unlimited") + "ms-" + position, scheduler, new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
final long start = System.nanoTime();
final Object res = (timeoutMS >= 0 ? take2Of3RPComprehensive.receive(timeoutMS, TimeUnit.MILLISECONDS) : take2Of3RPComprehensive.receive());
final long end = System.nanoTime();
switch(position) {
case 1:
assertThat(res, is(notNullValue()));
assertThat(end - start, lessThan(new Long(300 * 1000 * 1000)));
break;
case 2:
assertThat(res, is(nullValue()));
assertThat(end - start, greaterThan(new Long(300 * 1000 * 1000)));
break;
case 3:
assertThat(res, is(nullValue()));
assertThat(end - start, greaterThan(new Long(200 * 1000 * 1000)));
break;
case 4:
assertThat(res, is(notNullValue()));
assertThat(end - start, lessThan(new Long(1000 * 1000 * 1000)));
break;
case 5:
assertThat(res, is(nullValue()));
// Should be almost instantaneous
assertThat(end - start, lessThan(new Long(1000 * 1000 * 1000)));
break;
default:
fail();
break;
}
}
});
}
};
final Fiber[] competing = new Fiber[5];
// First front fiber winning first message
competing[0] = take1SRFun.apply(300l, 1).start();
// Make 1 message available immediately for the first front fiber to consume
takeSourceCh.send(new Object());
Thread.sleep(100);
// Second front fiber losing (waiting too little for second message)
competing[1] = take1SRFun.apply(300l, 2).start();
Thread.sleep(100);
// First waiter, will fail (not waiting enough)
competing[2] = take1SRFun.apply(200l, 3).start();
// First waiter takeover
Thread.sleep(300);
// Second waiter, will win second message (waiting enough)
competing[3] = take1SRFun.apply(1000l, 4).start();
// Second waiter takeover
Thread.sleep(300);
// Third waiter, will try after take threshold and will bail out
competing[4] = take1SRFun.apply(-1l, 5).start();
// Make 2 more messages available
takeSourceCh.send(new Object());
takeSourceCh.send(new Object());
// Wait fibers to finsh
for (final Fiber f : competing) f.join();
// 1 left in source, check and cleanup
assertThat(takeSourceCh.receive(), is(notNullValue()));
// Explicit (and uncoupled from source) closing of TakeSP
final ReceivePort<Object> take1Of0ExplicitClose = Channels.take((ReceivePort<Object>) takeSourceCh, 1);
final SuspendableRunnable explicitCloseSR = new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
final long start = System.nanoTime();
final Object ret = take1Of0ExplicitClose.receive();
final long end = System.nanoTime();
assertThat(ret, is(nullValue()));
assertTrue(take1Of0ExplicitClose.isClosed());
assertFalse(takeSourceCh.isClosed());
assertThat(end - start, lessThan(new Long(500 * 1000 * 1000)));
}
};
final Fiber explicitCloseF1 = new Fiber("take-explicit-close-1", scheduler, explicitCloseSR);
final Fiber explicitCloseF2 = new Fiber("take-explicit-close-2", scheduler, explicitCloseSR);
Thread.sleep(100);
take1Of0ExplicitClose.close();
}
Aggregations