use of io.servicetalk.concurrent.PublisherSource.Subscription in project servicetalk by apple.
the class ConnectableBufferOutputStreamTest method multiThreadedProducerConsumer.
@Test
void multiThreadedProducerConsumer() throws Exception {
final Random r = new Random();
// capture seed to have repeatable tests
final long seed = r.nextLong();
r.setSeed(seed);
// 3% of heap or max of 100 MiB
final int dataSize = (int) min(getRuntime().maxMemory() * 0.03, 100 * 1024 * 1024);
LOGGER.info("Test seed = {} – data size = {}", seed, dataSize);
final AtomicReference<Throwable> error = new AtomicReference<>();
final byte[] data = new byte[dataSize];
final byte[] received = new byte[dataSize];
r.nextBytes(data);
final Publisher<Buffer> pub = cbos.connect();
final Thread producerThread = new Thread(() -> {
int writeIndex = 0;
try {
while (writeIndex < dataSize) {
// write at most 25% of remaining bytes
final int length = (int) max(1, r.nextInt(dataSize - (writeIndex - 1)) * 0.25);
LOGGER.debug("Writing {} bytes - writeIndex = {}", length, writeIndex);
cbos.write(data, writeIndex, length);
writeIndex += length;
if (r.nextDouble() < 0.4) {
LOGGER.debug("Flushing - writeIndex = {}", writeIndex);
cbos.flush();
}
}
LOGGER.debug("Closing - writeIndex = {}", writeIndex);
cbos.close();
} catch (Throwable t) {
error.compareAndSet(null, t);
}
});
final Thread consumerThread = new Thread(() -> {
try {
final CountDownLatch consumerDone = new CountDownLatch(1);
toSource(pub).subscribe(new Subscriber<Buffer>() {
@Nullable
private Subscription sub;
private int writeIndex;
@Override
public void onSubscribe(final Subscription s) {
sub = s;
sub.request(1);
}
@Override
public void onNext(final Buffer buffer) {
final int readingBytes = buffer.readableBytes();
LOGGER.debug("Reading {} bytes, writeIndex = {}", readingBytes, writeIndex);
buffer.readBytes(received, writeIndex, readingBytes);
writeIndex += readingBytes;
assert sub != null : "Subscription can not be null in onNext.";
sub.request(1);
}
@Override
public void onError(final Throwable t) {
error.compareAndSet(null, t);
consumerDone.countDown();
}
@Override
public void onComplete() {
consumerDone.countDown();
}
});
consumerDone.await();
} catch (Throwable t) {
error.compareAndSet(null, t);
}
});
producerThread.start();
consumerThread.start();
// make sure both threads exit
producerThread.join();
// provides visibility for received from consumerThread
consumerThread.join();
assertNull(error.get());
// assertThat() times out
assertArrayEquals(data, received);
}
use of io.servicetalk.concurrent.PublisherSource.Subscription in project servicetalk by apple.
the class InlinePublisherFirstStep method expectSubscriptionConsumed.
@Override
public PublisherStep<T> expectSubscriptionConsumed(Consumer<? super Subscription> consumer) {
requireNonNull(consumer);
events.add(new OnSubscriptionEvent() {
@Override
void subscription(Subscription subscription) {
consumer.accept(subscription);
}
@Override
String description() {
return "expectSubscription(" + consumer + ")";
}
});
return this;
}
use of io.servicetalk.concurrent.PublisherSource.Subscription in project servicetalk by apple.
the class ConcurrentSubscriptionTest method singleThreadInvalidRequestN.
@Test
void singleThreadInvalidRequestN() {
Subscription concurrent = ConcurrentSubscription.wrap(subscription);
final long invalidN = ThreadLocalRandom.current().nextLong(Long.MIN_VALUE, 1);
concurrent.request(invalidN);
assertThat("unexpected requested with invalidN: " + invalidN, subscription.requested(), lessThanOrEqualTo(0L));
}
use of io.servicetalk.concurrent.PublisherSource.Subscription in project servicetalk by apple.
the class ConcurrentSubscriptionTest method multiThread.
private void multiThread(final int threads, boolean cancel) throws ExecutionException, InterruptedException {
ExecutorService executorService = newFixedThreadPool(threads);
try {
List<Future<?>> futures = new ArrayList<>(threads);
Subscription concurrent = ConcurrentSubscription.wrap(subscription);
CyclicBarrier barrier = new CyclicBarrier(threads);
for (int i = 0; i < threads; ++i) {
final int finalI = i;
futures.add(executorService.submit(() -> {
try {
barrier.await();
} catch (Exception e) {
throw new AssertionError(e);
}
concurrent.request(1);
if (cancel && finalI % 2 == 0) {
concurrent.cancel();
}
}));
}
for (Future<?> f : futures) {
f.get();
}
if (cancel) {
assertTrue(subscription.isCancelled());
} else {
subscription.awaitRequestN(threads);
assertFalse(subscription.isCancelled());
}
} finally {
executorService.shutdown();
}
}
use of io.servicetalk.concurrent.PublisherSource.Subscription in project servicetalk by apple.
the class ConcurrentSubscriptionTest method multiThreadReentrant.
@Test
void multiThreadReentrant() throws Exception {
ExecutorService executorService = newFixedThreadPool(1);
try {
final ReentrantSubscription reentrantSubscription = new ReentrantSubscription(50);
final Subscription concurrent = ConcurrentSubscription.wrap(reentrantSubscription);
CyclicBarrier barrier = new CyclicBarrier(2);
reentrantSubscription.outerSubscription(concurrent);
Future<?> f = executorService.submit(() -> {
try {
barrier.await();
} catch (Exception e) {
throw new AssertionError(e);
}
concurrent.request(1);
});
barrier.await();
concurrent.request(1);
f.get();
// wait for the expected demand to be delivered.
reentrantSubscription.innerSubscription.awaitRequestN(reentrantSubscription.reentrantLimit + 1);
} finally {
executorService.shutdown();
}
}
Aggregations