/*- * #%L * RPC Benchmark: Aeron with SBE * %% * Copyright (C) 2016 - 2020 Acegi Technology Pty Limited * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package au.com.acegi.rpcbench.aeron; import static au.com.acegi.rpcbench.aeron.codecs.MessageHeaderEncoder.ENCODED_LENGTH; import static java.lang.System.setProperty; import static org.agrona.BitUtil.CACHE_LINE_LENGTH; import static org.agrona.BufferUtil.allocateDirectAligned; import static org.agrona.concurrent.UnsafeBuffer.DISABLE_BOUNDS_CHECKS_PROP_NAME; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; import au.com.acegi.rpcbench.aeron.codecs.MessageHeaderDecoder; import au.com.acegi.rpcbench.aeron.codecs.MessageHeaderEncoder; import au.com.acegi.rpcbench.aeron.codecs.PingDecoder; import au.com.acegi.rpcbench.aeron.codecs.PongEncoder; import au.com.acegi.rpcbench.aeron.codecs.PriceEncoder; import au.com.acegi.rpcbench.aeron.codecs.SizeDecoder; import io.aeron.Aeron; import io.aeron.FragmentAssembler; import io.aeron.Publication; import io.aeron.Subscription; import io.aeron.driver.MediaDriver; import io.aeron.logbuffer.FragmentHandler; import io.aeron.logbuffer.Header; import org.agrona.CloseHelper; import org.agrona.DirectBuffer; import org.agrona.concurrent.BusySpinIdleStrategy; import org.agrona.concurrent.IdleStrategy; import org.agrona.concurrent.SigInt; import org.agrona.concurrent.UnsafeBuffer; @SuppressWarnings("checkstyle:JavadocType") public final class BenchServer { private static final UnsafeBuffer BUFFER; private static final boolean EMBEDDED_MEDIA_DRIVER = false; private static final int FRAGMENT_LIMIT = 256; private static final MessageHeaderDecoder HDR_D; private static final MessageHeaderEncoder HDR_E; private static final IdleStrategy IDLE = new BusySpinIdleStrategy(); private static final PingDecoder PING_D; private static final int PING_LEN; private static final PongEncoder PONG_E; private static final PriceEncoder PRICE_E; private static final int PRICE_LEN; private static final String REP_CHAN = Configuration.REP_CHANNEL; private static final int REP_STREAM_ID = Configuration.REP_STREAM_ID; private static final String REQ_CHAN = Configuration.REQ_CHANNEL; private static final int REQ_STREAM_ID = Configuration.REQ_STREAM_ID; private static final SizeDecoder SIZE_D; private final Aeron aeron; private final Aeron.Context ctx; private final MediaDriver driver; private final FragmentHandler fragmentHandler; private final Publication publication; private final AtomicBoolean running; private final Subscription subscription; static { setProperty(DISABLE_BOUNDS_CHECKS_PROP_NAME, "true"); PING_LEN = ENCODED_LENGTH + PongEncoder.BLOCK_LENGTH; PRICE_LEN = ENCODED_LENGTH + PriceEncoder.BLOCK_LENGTH; final ByteBuffer bb = allocateDirectAligned(PRICE_LEN, CACHE_LINE_LENGTH); BUFFER = new UnsafeBuffer(bb); HDR_D = new MessageHeaderDecoder(); HDR_E = new MessageHeaderEncoder(); PING_D = new PingDecoder(); PONG_E = new PongEncoder(); PRICE_E = new PriceEncoder(); SIZE_D = new SizeDecoder(); HDR_E.wrap(BUFFER, 0); PONG_E.wrap(BUFFER, ENCODED_LENGTH); PRICE_E.wrap(BUFFER, ENCODED_LENGTH); HDR_E.schemaId(PongEncoder.SCHEMA_ID); HDR_E.version(PongEncoder.SCHEMA_VERSION); } @SuppressWarnings("PMD.NullAssignment") public BenchServer() { running = new AtomicBoolean(true); SigInt.register(() -> running.set(false)); driver = EMBEDDED_MEDIA_DRIVER ? MediaDriver.launchEmbedded() : null; ctx = new Aeron.Context(); if (EMBEDDED_MEDIA_DRIVER) { ctx.aeronDirectoryName(driver.aeronDirectoryName()); } fragmentHandler = new FragmentAssembler(this::onMessage); aeron = Aeron.connect(ctx); publication = aeron.addPublication(REP_CHAN, REP_STREAM_ID); subscription = aeron.addSubscription(REQ_CHAN, REQ_STREAM_ID); } @SuppressWarnings("checkstyle:UncommentedMain") public static void main(final String... args) throws InterruptedException { final BenchServer svr = new BenchServer(); svr.execute(); svr.shutdown(); } public void shutdown() throws InterruptedException { CloseHelper.quietClose(subscription); CloseHelper.quietClose(publication); CloseHelper.quietClose(aeron); CloseHelper.quietClose(ctx); CloseHelper.quietClose(driver); } private void execute() { final IdleStrategy idleStrategy = new BusySpinIdleStrategy(); while (running.get()) { idleStrategy.idle(subscription.poll(fragmentHandler, FRAGMENT_LIMIT)); } } @SuppressWarnings("PMD.UnusedFormalParameter") private void onMessage(final DirectBuffer buffer, final int offset, final int length, final Header header) { final int msgOffset = ENCODED_LENGTH + offset; HDR_D.wrap(buffer, offset); switch (HDR_D.templateId()) { case PingDecoder.TEMPLATE_ID: onPing(buffer, msgOffset, HDR_D.blockLength(), HDR_D.version()); break; case SizeDecoder.TEMPLATE_ID: onSize(buffer, msgOffset, HDR_D.blockLength(), HDR_D.version()); break; default: throw new IllegalStateException("Unknown message template"); } } private void onPing(final DirectBuffer buffer, final int offset, final int actingBlockLength, final int actingVersion) { PING_D.wrap(buffer, offset, actingBlockLength, actingVersion); HDR_E.blockLength(PongEncoder.BLOCK_LENGTH); HDR_E.templateId(PongEncoder.TEMPLATE_ID); PONG_E.timestamp(PING_D.timestamp()); sendBuffer(PING_LEN); } private void onSize(final DirectBuffer buffer, final int offset, final int actingBlockLength, final int actingVersion) { SIZE_D.wrap(buffer, offset, actingBlockLength, actingVersion); HDR_E.blockLength(PriceEncoder.BLOCK_LENGTH); HDR_E.templateId(PriceEncoder.TEMPLATE_ID); final long tod = SIZE_D.tod(); final int msgs = SIZE_D.messages(); for (int i = 0; i < msgs; i++) { PRICE_E.tod(tod); PRICE_E.iid(i); PRICE_E.bid(2); PRICE_E.ask(3); PRICE_E.trd(4); PRICE_E.vol(5); sendBuffer(PRICE_LEN); } } @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") private void sendBuffer(final int len) { if (publication.offer(BUFFER, 0, len) > 0L) { return; } IDLE.reset(); while (publication.offer(BUFFER, 0, len) < 0L) { IDLE.idle(); } } }