All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.co.real_logic.aeron.Aeron Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014 - 2016 Real Logic Ltd.
 *
 * 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.
 */
package uk.co.real_logic.aeron;

import uk.co.real_logic.aeron.exceptions.DriverTimeoutException;
import uk.co.real_logic.agrona.*;
import uk.co.real_logic.agrona.concurrent.*;
import uk.co.real_logic.agrona.concurrent.broadcast.BroadcastReceiver;
import uk.co.real_logic.agrona.concurrent.broadcast.CopyBroadcastReceiver;
import uk.co.real_logic.agrona.concurrent.ringbuffer.ManyToOneRingBuffer;
import uk.co.real_logic.agrona.concurrent.ringbuffer.RingBuffer;

import java.nio.MappedByteBuffer;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static uk.co.real_logic.agrona.IoUtil.mapExistingFile;

/**
 * Aeron entry point for communicating to the Media Driver for creating {@link Publication}s and {@link Subscription}s.
 * Use an {@link Aeron.Context} to configure the Aeron object.
 * 

* A client application requires only one Aeron object per Media Driver. */ public final class Aeron implements AutoCloseable { /** * The Default handler for Aeron runtime exceptions. * When a {@link uk.co.real_logic.aeron.exceptions.DriverTimeoutException} is encountered, this handler will * exit the program. *

* The error handler can be overridden by supplying an {@link Aeron.Context} with a custom handler. * * @see Aeron.Context#errorHandler(ErrorHandler) */ public static final ErrorHandler DEFAULT_ERROR_HANDLER = (throwable) -> { throwable.printStackTrace(); if (throwable instanceof DriverTimeoutException) { System.err.printf("\n***\n*** Timeout from the Media Driver - is it currently running? Exiting.\n***\n"); System.exit(-1); } }; private static final long IDLE_SLEEP_NS = TimeUnit.MILLISECONDS.toNanos(4); private static final long KEEPALIVE_INTERVAL_NS = TimeUnit.MILLISECONDS.toNanos(500); private static final long INTER_SERVICE_TIMEOUT_NS = TimeUnit.SECONDS.toNanos(10); private static final long PUBLICATION_CONNECTION_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5); private final ClientConductor conductor; private final AgentRunner conductorRunner; private final Context ctx; Aeron(final Context ctx) { ctx.conclude(); this.ctx = ctx; conductor = new ClientConductor( ctx.epochClock, ctx.nanoClock, ctx.toClientBuffer, ctx.logBuffersFactory, ctx.countersValuesBuffer(), new DriverProxy(ctx.toDriverBuffer), ctx.errorHandler, ctx.availableImageHandler, ctx.unavailableImageHandler, ctx.keepAliveInterval(), ctx.driverTimeoutMs(), ctx.interServiceTimeout(), ctx.publicationConnectionTimeout()); conductorRunner = new AgentRunner(ctx.idleStrategy, ctx.errorHandler, null, conductor); } /** * Create an Aeron instance and connect to the media driver with a default {@link Context}. *

* Threads required for interacting with the media driver are created and managed within the Aeron instance. * * @return the new {@link Aeron} instance connected to the Media Driver. */ public static Aeron connect() { return new Aeron(new Context()).start(); } /** * Create an Aeron instance and connect to the media driver. *

* Threads required for interacting with the media driver are created and managed within the Aeron instance. * * @param ctx for configuration of the client. * @return the new {@link Aeron} instance connected to the Media Driver. */ public static Aeron connect(final Context ctx) { return new Aeron(ctx).start(); } /** * Clean up and release all Aeron internal resources and shutdown threads. */ public void close() { conductorRunner.close(); ctx.close(); } /** * Add a {@link Publication} for publishing messages to subscribers. * * @param channel for receiving the messages known to the media layer. * @param streamId within the channel scope. * @return the new Publication. */ public Publication addPublication(final String channel, final int streamId) { return conductor.addPublication(channel, streamId); } /** * Add a new {@link Subscription} for subscribing to messages from publishers. * * @param channel for receiving the messages known to the media layer. * @param streamId within the channel scope. * @return the {@link Subscription} for the channel and streamId pair. */ public Subscription addSubscription(final String channel, final int streamId) { return conductor.addSubscription(channel, streamId); } private Aeron start() { final Thread thread = new Thread(conductorRunner); thread.setName("aeron-client-conductor"); thread.start(); return this; } /** * This class provides configuration for the {@link Aeron} class via the {@link Aeron#connect(Aeron.Context)} * method and its overloads. It gives applications some control over the interactions with the Aeron Media Driver. * It can also set up error handling as well as application callbacks for image information from the * Media Driver. */ public static class Context extends CommonContext { private final AtomicBoolean isClosed = new AtomicBoolean(false); private EpochClock epochClock; private NanoClock nanoClock; private IdleStrategy idleStrategy; private CopyBroadcastReceiver toClientBuffer; private RingBuffer toDriverBuffer; private MappedByteBuffer cncByteBuffer; private DirectBuffer cncMetaDataBuffer; private LogBuffersFactory logBuffersFactory; private ErrorHandler errorHandler; private AvailableImageHandler availableImageHandler; private UnavailableImageHandler unavailableImageHandler; private long keepAliveInterval = KEEPALIVE_INTERVAL_NS; private long interServiceTimeout = INTER_SERVICE_TIMEOUT_NS; private long publicationConnectionTimeout = PUBLICATION_CONNECTION_TIMEOUT_MS; /** * This is called automatically by {@link Aeron#connect(Aeron.Context)} and its overloads. * There is no need to call it from a client application. It is responsible for providing default * values for options that are not individually changed through field setters. * * @return this Aeron.Context for method chaining. */ public Context conclude() { super.conclude(); try { if (null == epochClock) { epochClock = new SystemEpochClock(); } if (null == nanoClock) { nanoClock = new SystemNanoClock(); } if (null == idleStrategy) { idleStrategy = new SleepingIdleStrategy(IDLE_SLEEP_NS); } if (cncFile() != null) { cncByteBuffer = mapExistingFile(cncFile(), CncFileDescriptor.CNC_FILE); cncMetaDataBuffer = CncFileDescriptor.createMetaDataBuffer(cncByteBuffer); final int cncVersion = cncMetaDataBuffer.getInt(CncFileDescriptor.cncVersionOffset(0)); if (CncFileDescriptor.CNC_VERSION != cncVersion) { throw new IllegalStateException("aeron cnc file version not understood: version=" + cncVersion); } } if (null == toClientBuffer) { final BroadcastReceiver receiver = new BroadcastReceiver( CncFileDescriptor.createToClientsBuffer(cncByteBuffer, cncMetaDataBuffer)); toClientBuffer = new CopyBroadcastReceiver(receiver); } if (null == toDriverBuffer) { toDriverBuffer = new ManyToOneRingBuffer( CncFileDescriptor.createToDriverBuffer(cncByteBuffer, cncMetaDataBuffer)); } if (countersMetaDataBuffer() == null) { countersMetaDataBuffer(CncFileDescriptor.createCountersMetaDataBuffer(cncByteBuffer, cncMetaDataBuffer)); } if (countersValuesBuffer() == null) { countersValuesBuffer(CncFileDescriptor.createCountersValuesBuffer(cncByteBuffer, cncMetaDataBuffer)); } interServiceTimeout = CncFileDescriptor.clientLivenessTimeout(cncMetaDataBuffer); if (null == logBuffersFactory) { logBuffersFactory = new MappedLogBuffersFactory(); } if (null == errorHandler) { errorHandler = DEFAULT_ERROR_HANDLER; } if (null == availableImageHandler) { availableImageHandler = (image) -> { }; } if (null == unavailableImageHandler) { unavailableImageHandler = (image) -> { }; } } catch (final Exception ex) { System.err.printf("\n***\n*** Failed to connect to the Media Driver - is it currently running?\n***\n"); throw new IllegalStateException("Could not initialise communication buffers", ex); } return this; } /** * Set the {@link EpochClock} to be used for tracking wall clock time when interacting with the driver. * * @param clock {@link EpochClock} to be used for tracking wall clock time when interacting with the driver. * @return this Aeron.Context for method chaining */ public Context epochClock(final EpochClock clock) { this.epochClock = clock; return this; } /** * Set the {@link NanoClock} to be used for tracking high resolution time. * * @param clock {@link NanoClock} to be used for tracking high resolution time. * @return this Aeron.Context for method chaining */ public Context nanoClock(final NanoClock clock) { this.nanoClock = clock; return this; } /** * Provides an IdleStrategy for the thread responsible for communicating with the Aeron Media Driver. * * @param idleStrategy Thread idle strategy for communication with the Media Driver. * @return this Aeron.Context for method chaining. */ public Context idleStrategy(final IdleStrategy idleStrategy) { this.idleStrategy = idleStrategy; return this; } /** * This method is used for testing and debugging. * * @param toClientBuffer Injected CopyBroadcastReceiver * @return this Aeron.Context for method chaining. */ public Context toClientBuffer(final CopyBroadcastReceiver toClientBuffer) { this.toClientBuffer = toClientBuffer; return this; } /** * This method is used for testing and debugging. * * @param toDriverBuffer Injected RingBuffer. * @return this Aeron.Context for method chaining. */ public Context toDriverBuffer(final RingBuffer toDriverBuffer) { this.toDriverBuffer = toDriverBuffer; return this; } /** * This method is used for testing and debugging. * * @param logBuffersFactory Injected LogBuffersFactory * @return this Aeron.Context for method chaining. */ public Context bufferManager(final LogBuffersFactory logBuffersFactory) { this.logBuffersFactory = logBuffersFactory; return this; } /** * Handle Aeron exceptions in a callback method. The default behavior is defined by * {@link Aeron#DEFAULT_ERROR_HANDLER}. * * @param errorHandler Method to handle objects of type Throwable. * @return this Aeron.Context for method chaining. * @see uk.co.real_logic.aeron.exceptions.DriverTimeoutException * @see uk.co.real_logic.aeron.exceptions.RegistrationException */ public Context errorHandler(final ErrorHandler errorHandler) { this.errorHandler = errorHandler; return this; } /** * Set up a callback for when an {@link Image} is available. * * @param handler Callback method for handling available image notifications. * @return this Aeron.Context for method chaining. */ public Context availableImageHandler(final AvailableImageHandler handler) { this.availableImageHandler = handler; return this; } /** * Set up a callback for when an {@link Image} is unavailable. * * @param handler Callback method for handling unavailable image notifications. * @return this Aeron.Context for method chaining. */ public Context unavailableImageHandler(final UnavailableImageHandler handler) { this.unavailableImageHandler = handler; return this; } /** * Set the interval in nanoseconds for which the client will perform keep-alive operations. * * @param value the interval in nanoseconds for which the client will perform keep-alive operations. * @return this Aeron.Context for method chaining. */ public Context keepAliveInterval(final long value) { keepAliveInterval = value; return this; } /** * Get the interval in nanoseconds for which the client will perform keep-alive operations. * * @return the interval in nanoseconds for which the client will perform keep-alive operations. */ public long keepAliveInterval() { return keepAliveInterval; } /** * Set the amount of time, in milliseconds, that this client will wait until it determines the * Media Driver is unavailable. When this happens a * {@link uk.co.real_logic.aeron.exceptions.DriverTimeoutException} will be generated for the error handler. * * @param value Number of milliseconds. * @return this Aeron.Context for method chaining. * @see #errorHandler(ErrorHandler) */ public Context driverTimeoutMs(final long value) { super.driverTimeoutMs(value); return this; } /** * Return the timeout between service calls for the client. * * When exceeded, {@link #errorHandler} will be called and the active {@link Publication}s and {@link Image}s * closed. * * This value is controlled by the driver and included in the CnC file. * * @return the timeout between service calls in nanoseconds. */ public long interServiceTimeout() { return interServiceTimeout; } /** * @see CommonContext#aeronDirectoryName(String) */ public Context aeronDirectoryName(String dirName) { super.aeronDirectoryName(dirName); return this; } /** * Set the amount of time, in milliseconds, that this client will use to determine if a {@link Publication} * has active subscribers or not. * * @param value number of milliseconds. * @return this Aeron.Context for method chaining. */ public Context publicationConnectionTimeout(final long value) { publicationConnectionTimeout = value; return this; } /** * Return the timeout, in milliseconds, that this client will use to determine if a {@link Publication} * has active subscribers or not. * * @return timeout in milliseconds. */ public long publicationConnectionTimeout() { return publicationConnectionTimeout; } /** * Clean up all resources that the client uses to communicate with the Media Driver. */ public void close() { if (isClosed.compareAndSet(false, true)) { IoUtil.unmap(cncByteBuffer); super.close(); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy