package com.epickrram.workshop.perf.app.processors; ////////////////////////////////////////////////////////////////////////////////// // Copyright 2015 Mark Price mark at epickrram.com // // // // 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. // ////////////////////////////////////////////////////////////////////////////////// import com.epickrram.workshop.perf.config.CommandLineArgs; import com.epickrram.workshop.perf.app.message.JournalEntry; import com.epickrram.workshop.perf.app.message.Packet; import com.epickrram.workshop.perf.support.NanoTimer; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import static java.nio.ByteBuffer.allocateDirect; public final class Journaller { private final NanoTimer nanoTimer; private final CommandLineArgs commandLineArgs; private final JournalEntry journalEntry = new JournalEntry(); private final boolean enabled; private FileChannel channel; private long position = 0; public Journaller(final NanoTimer nanoTimer, final CommandLineArgs commandLineArgs, final boolean enabled) { this.nanoTimer = nanoTimer; this.commandLineArgs = commandLineArgs; this.enabled = enabled; } public void init() throws IOException { final File journalFile = new File(commandLineArgs.getJournalFile()); if(!journalFile.exists()) { journalFile.createNewFile(); } final RandomAccessFile randomAccessFile = new RandomAccessFile(commandLineArgs.getJournalFile(), "rw"); channel = randomAccessFile.getChannel(); channel.truncate(0L); final int totalNumberOfJournalEntries = commandLineArgs.getNumberOfRecords() * commandLineArgs.getNumberOfIterations(); final long expectedMaximumJournalLength = JournalEntry.ENTRY_SIZE * totalNumberOfJournalEntries; channel.truncate(expectedMaximumJournalLength); final ByteBuffer nullEntry = allocateDirect(JournalEntry.ENTRY_SIZE); for(int i = 0; i < totalNumberOfJournalEntries; i++) { nullEntry.clear(); channel.position(i * JournalEntry.ENTRY_SIZE); channel.write(nullEntry); } channel.force(false); } public void process(final Packet packet) { if(!enabled) { return; } final long journallerNanoTime = nanoTimer.nanoTime(); final long deltaNanos = journallerNanoTime - packet.getReceivedNanoTime(); writeEntry(packet.getReceivedNanoTime(), journallerNanoTime, deltaNanos, packet.getSequenceInFile()); position += JournalEntry.ENTRY_SIZE; if(packet.isLastInStream()) { closeChannel(); } } private void writeEntry(final long publisherNanoTime, final long nanoTime, final long deltaNanos, final int sequenceInFile) { try { journalEntry.set(publisherNanoTime, nanoTime, deltaNanos, sequenceInFile); channel.position(position); journalEntry.writeTo(channel); } catch (IOException e) { throw new RuntimeException("File operation failed", e); } } private void closeChannel() { try { channel.close(); } catch (IOException e) { throw new RuntimeException("File operation failed", e); } } }