/* * Copyright 2014-2017 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 io.aeron.archiver; import io.aeron.Aeron; import org.agrona.CloseHelper; import org.agrona.concurrent.*; import java.io.File; import static io.aeron.driver.MediaDriver.loadPropertiesFiles; public class Archiver implements AutoCloseable { private final Context ctx; private AgentRunner runner; private Aeron aeron; /** * Start an ArchiverConductor as a stand-alone process. * * @param args command line arguments * @throws Exception if an error occurs */ public static void main(final String[] args) throws Exception { loadPropertiesFiles(args); try (Archiver ignore = Archiver.launch()) { new ShutdownSignalBarrier().await(); System.out.println("Shutdown Archiver..."); } } public Archiver(final Context ctx) { this.ctx = ctx; } public void close() throws Exception { CloseHelper.close(runner); CloseHelper.close(aeron); } public Archiver start() { ctx.clientContext.driverAgentInvoker(ctx.driverAgentInvoker()); aeron = Aeron.connect(ctx.clientContext); ctx.conclude(); final ArchiveConductor archiveConductor = new ArchiveConductor(aeron, ctx); runner = new AgentRunner( ctx.clientContext.idleStrategy(), ctx.clientContext.errorHandler(), null, archiveConductor); AgentRunner.startOnThread(runner, ctx.clientContext.threadFactory()); return this; } public static Archiver launch() { return launch(new Context()); } public static Archiver launch(final Context ctx) { return new Archiver(ctx).start(); } public static class Context { private Aeron.Context clientContext; private File archiveDir; private String controlRequestChannel; private int controlRequestStreamId; private String recordingEventsChannel; private int recordingEventsStreamId; private IdleStrategy idleStrategy; private EpochClock epochClock; private int segmentFileLength = 128 * 1024 * 1024; private boolean forceMetadataUpdates = true; private boolean forceWrites = true; private AgentInvoker driverAgentInvoker; public Context() { this(new Aeron.Context(), new File("archive")); } public Context(final Aeron.Context clientContext, final File archiveDir) { clientContext.useConductorAgentInvoker(true); clientContext.clientLock(new NoOpLock()); this.clientContext = clientContext; this.archiveDir = archiveDir; controlRequestChannel = "aeron:udp?endpoint=localhost:8010"; controlRequestStreamId = 0; recordingEventsChannel = "aeron:udp?endpoint=localhost:8011"; recordingEventsStreamId = 0; } void conclude() { if (!archiveDir.exists() && !archiveDir.mkdirs()) { throw new IllegalArgumentException( "Failed to create archive dir: " + archiveDir.getAbsolutePath()); } if (idleStrategy == null) { idleStrategy = new SleepingIdleStrategy(Aeron.IDLE_SLEEP_NS); } if (epochClock == null) { epochClock = clientContext.epochClock(); } } public File archiveDir() { return archiveDir; } public Context archiveDir(final File archiveDir) { this.archiveDir = archiveDir; return this; } public Aeron.Context clientContext() { return clientContext; } public Context clientContext(final Aeron.Context ctx) { this.clientContext = ctx; return this; } public String controlRequestChannel() { return controlRequestChannel; } public Context controlRequestChannel(final String controlRequestChannel) { this.controlRequestChannel = controlRequestChannel; return this; } public int controlRequestStreamId() { return controlRequestStreamId; } public Context controlRequestStreamId(final int controlRequestStreamId) { this.controlRequestStreamId = controlRequestStreamId; return this; } public String recordingEventsChannel() { return recordingEventsChannel; } public Context recordingEventsChannel(final String recordingEventsChannel) { this.recordingEventsChannel = recordingEventsChannel; return this; } public int recordingEventsStreamId() { return recordingEventsStreamId; } public Context recordingEventsStreamId(final int recordingEventsStreamId) { this.recordingEventsStreamId = recordingEventsStreamId; return this; } /** * Provides an IdleStrategy for the thread responsible for publication/subscription backoff. * * @param idleStrategy Thread idle strategy for publication/subscription backoff. * @return this Context for method chaining. */ public Context idleStrategy(final IdleStrategy idleStrategy) { this.idleStrategy = idleStrategy; return this; } public IdleStrategy idleStrategy() { return idleStrategy; } /** * Set the {@link EpochClock} to be used for tracking wall clock time when interacting with the archiver. * * @param clock {@link EpochClock} to be used for tracking wall clock time when interacting with the archiver. * @return this Context for method chaining */ public Context epochClock(final EpochClock clock) { this.epochClock = clock; return this; } public EpochClock epochClock() { return epochClock; } int segmentFileLength() { return segmentFileLength; } public Context segmentFileLength(final int segmentFileLength) { this.segmentFileLength = segmentFileLength; return this; } boolean forceMetadataUpdates() { return forceMetadataUpdates; } public Context forceMetadataUpdates(final boolean forceMetadataUpdates) { this.forceMetadataUpdates = forceMetadataUpdates; return this; } boolean forceWrites() { return forceWrites; } public Context forceWrites(final boolean forceWrites) { this.forceWrites = forceWrites; return this; } /** * Get the {@link AgentInvoker} that should be used for the Media Driver if running in a lightweight mode. * * @return the {@link AgentInvoker} that should be used for the Media Driver if running in a lightweight mode. */ AgentInvoker driverAgentInvoker() { return driverAgentInvoker; } /** * Set the {@link AgentInvoker} that should be used for the Media Driver if running in a lightweight mode. * * @param driverAgentInvoker that should be used for the Media Driver if running in a lightweight mode. * @return this for a fluent API. */ public Context driverAgentInvoker(final AgentInvoker driverAgentInvoker) { this.driverAgentInvoker = driverAgentInvoker; return this; } } }