diff --git a/.gitignore b/.gitignore index 71af624862..ce574854cc 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,4 @@ ratReport.txt **/cmake_install.cmake # this file is generated -artemis-native/src/main/c/org_apache_activemq_artemis_core_libaio_Native.h +artemis-native/src/main/c/org_apache_activemq_artemis_jlibaio_LibaioContext.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..4681205240 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SUBDIRS(artemis-native) diff --git a/README.md b/README.md index 65155f32ef..195441f815 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This file describes some minimum 'stuff one needs to know' to get started coding ## Source -For details about the modifying the code, building the project, running tests, IDE integration, etc. see +For details about the modifying the code, building the project, running tests, IDE integration, etc. see our [Hacking Guide](./docs/hacking-guide/en/SUMMARY.md). ## Examples diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java index 7495ce278c..2fdf5f205a 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Create.java @@ -26,6 +26,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.attribute.PosixFilePermission; +import java.text.DecimalFormat; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -36,8 +37,10 @@ import java.util.regex.Pattern; import io.airlift.airline.Arguments; import io.airlift.airline.Command; import io.airlift.airline.Option; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; +import org.apache.activemq.artemis.cli.commands.util.SyncCalculation; import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType; +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.jlibaio.LibaioFile; import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE; import static java.nio.file.attribute.PosixFilePermission.GROUP_READ; @@ -84,6 +87,7 @@ public class Create extends InputAbstract public static final String ETC_CLUSTER_SETTINGS_TXT = "etc/cluster-settings.txt"; public static final String ETC_CONNECTOR_SETTINGS_TXT = "etc/connector-settings.txt"; public static final String ETC_BOOTSTRAP_WEB_SETTINGS_TXT = "etc/bootstrap-web-settings.txt"; + public static final String ETC_JOURNAL_BUFFER_SETTINGS = "etc/journal-buffer-settings.txt"; @Arguments(description = "The instance directory to hold the broker's configuration and data. Path must be writable.", required = true) File directory; @@ -142,6 +146,9 @@ public class Create extends InputAbstract @Option(name = "--require-login", description = "This will configure security to require user / password, opposite of --allow-anonymous") Boolean requireLogin = null; + @Option(name = "--no-sync-test", description = "Disable the calculation for the buffer") + boolean noSyncTest; + @Option(name = "--user", description = "The username (Default: input)") String user; @@ -529,12 +536,16 @@ public class Create extends InputAbstract filters.put("${shared-store.settings}", ""); } - if (IS_WINDOWS || !AsynchronousFileImpl.isLoaded()) + boolean aio; + + if (IS_WINDOWS || !supportsLibaio()) { + aio = false; filters.put("${journal.settings}", "NIO"); } else { + aio = true; filters.put("${journal.settings}", "ASYNCIO"); } @@ -590,7 +601,8 @@ public class Create extends InputAbstract new File(directory, "etc").mkdirs(); new File(directory, "log").mkdirs(); new File(directory, "tmp").mkdirs(); - new File(directory, "data").mkdirs(); + File dataFolder = new File(directory, "data"); + dataFolder.mkdirs(); if (javaOptions == null || javaOptions.length() == 0) { @@ -638,7 +650,7 @@ public class Create extends InputAbstract filters.put("${bootstrap-web-settings}", applyFilters(readTextFile(ETC_BOOTSTRAP_WEB_SETTINGS_TXT), filters)); } - + performSyncCalc(filters, aio, dataFolder); write(ETC_BOOTSTRAP_XML, filters, false); write(ETC_BROKER_XML, filters, false); @@ -694,6 +706,76 @@ public class Create extends InputAbstract return null; } + private void performSyncCalc(HashMap filters, boolean aio, File dataFolder) + { + if (noSyncTest) + { + filters.put("${journal-buffer.settings}", ""); + } + else + { + try + { + int writes = 250; + System.out.println(""); + System.out.println("Performing write sync calculation..."); + + long time = SyncCalculation.syncTest(dataFolder, 4096, writes, 5, verbose, aio); + long nanoseconds = SyncCalculation.toNanos(time, writes); + double writesPerMillisecond = (double)writes / (double) time; + + String writesPerMillisecondStr = new DecimalFormat("###.##").format(writesPerMillisecond); + + HashMap syncFilter = new HashMap(); + syncFilter.put("${nanoseconds}", Long.toString(nanoseconds)); + syncFilter.put("${writesPerMillisecond}", writesPerMillisecondStr); + + System.out.println("done! Your system can make " + writesPerMillisecondStr + + " writes per millisecond, your journal-buffer-timeout will be " + nanoseconds); + + filters.put("${journal-buffer.settings}", applyFilters(readTextFile(ETC_JOURNAL_BUFFER_SETTINGS), syncFilter)); + + } + catch (Exception e) + { + filters.put("${journal-buffer.settings}", ""); + e.printStackTrace(); + System.err.println("Couldn't perform sync calculation, using default values"); + } + } + } + + private boolean supportsLibaio() + { + if (LibaioContext.isLoaded()) + { + try (LibaioContext context = new LibaioContext(1, true)) + { + File tmpFile = new File(directory, "validateAIO.bin"); + boolean supportsLibaio = true; + try + { + LibaioFile file = context.openFile(tmpFile, true); + file.close(); + } + catch (Exception e) + { + supportsLibaio = false; + } + tmpFile.delete(); + if (!supportsLibaio) + { + System.err.println("The filesystem used on " + directory + " doesn't support libAIO and O_DIRECT files, switching journal-type to NIO"); + } + return supportsLibaio; + } + } + else + { + return false; + } + } + private void makeExec(String path) throws IOException { try diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/CompactJournal.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/CompactJournal.java index 0239998984..38fb785609 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/CompactJournal.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/CompactJournal.java @@ -22,9 +22,9 @@ import io.airlift.airline.Command; import org.apache.activemq.artemis.cli.commands.Action; import org.apache.activemq.artemis.cli.commands.ActionContext; import org.apache.activemq.artemis.core.config.Configuration; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; @Command(name = "compact", description = "Compacts the journal of a non running server") public final class CompactJournal extends DataAbstract implements Action @@ -54,7 +54,7 @@ public final class CompactJournal extends DataAbstract implements Action final int fileSize, final IOCriticalErrorListener listener) throws Exception { - NIOSequentialFileFactory nio = new NIOSequentialFileFactory(directory, listener); + NIOSequentialFileFactory nio = new NIOSequentialFileFactory(directory, listener, 1); JournalImpl journal = new JournalImpl(fileSize, minFiles, 0, 0, nio, journalPrefix, journalSuffix, 1); diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/DecodeJournal.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/DecodeJournal.java index 5b28a18ca3..6b608c3480 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/DecodeJournal.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/DecodeJournal.java @@ -35,7 +35,7 @@ import org.apache.activemq.artemis.cli.commands.Configurable; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.core.journal.impl.JournalRecord; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.utils.Base64; @Command(name = "decode", description = "Decode a journal's internal format into a new journal set of files") @@ -117,7 +117,7 @@ public class DecodeJournal extends Configurable implements Action System.err.println("Could not create directory " + directory); } - NIOSequentialFileFactory nio = new NIOSequentialFileFactory(new File(directory), null); + NIOSequentialFileFactory nio = new NIOSequentialFileFactory(new File(directory), null, 1); JournalImpl journal = new JournalImpl(fileSize, minFiles, 0, 0, nio, journalPrefix, journalSuffix, 1); diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/EncodeJournal.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/EncodeJournal.java index 8b0721b497..a408951f72 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/EncodeJournal.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/EncodeJournal.java @@ -28,11 +28,11 @@ import org.apache.activemq.artemis.cli.commands.Action; import org.apache.activemq.artemis.cli.commands.ActionContext; import org.apache.activemq.artemis.cli.commands.Configurable; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.core.journal.impl.JournalReaderCallback; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.utils.Base64; @Command(name = "encode", description = "Encode a set of journal files into an internal encoded data format") @@ -113,7 +113,7 @@ public class EncodeJournal extends Configurable implements Action final int fileSize, final PrintStream out) throws Exception { - NIOSequentialFileFactory nio = new NIOSequentialFileFactory(new File(directory), null); + NIOSequentialFileFactory nio = new NIOSequentialFileFactory(new File(directory), null, 1); JournalImpl journal = new JournalImpl(fileSize, minFiles, 0, 0, nio, journalPrefix, journalSuffix, 1); diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/XmlDataExporter.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/XmlDataExporter.java index e099a0ba0e..cf5be129ca 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/XmlDataExporter.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/XmlDataExporter.java @@ -52,10 +52,10 @@ import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.message.BodyEncoder; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagingManager; @@ -345,7 +345,7 @@ public final class XmlDataExporter extends DataAbstract implements Action private void getJmsBindings() throws Exception { - SequentialFileFactory bindingsJMS = new NIOSequentialFileFactory(config.getBindingsLocation()); + SequentialFileFactory bindingsJMS = new NIOSequentialFileFactory(config.getBindingsLocation(), 1); Journal jmsJournal = new JournalImpl(1024 * 1024, 2, diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/util/SyncCalculation.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/util/SyncCalculation.java new file mode 100644 index 0000000000..b5a88453b6 --- /dev/null +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/util/SyncCalculation.java @@ -0,0 +1,190 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.cli.commands.util; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.text.DecimalFormat; +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.utils.ReusableLatch; + +/** + * It will perform a simple test to evaluate how many syncs a disk can make per second + * * * + */ +public class SyncCalculation +{ + /** + * It will perform a write test of blockSize * bocks, sinc on each write, for N tries. + * It will return the lowest spent time from the tries. + */ + public static long syncTest(File datafolder, int blockSize, int blocks, int tries, boolean verbose, boolean aio) throws Exception + { + SequentialFileFactory factory = newFactory(datafolder, aio); + SequentialFile file = factory.createSequentialFile("test.tmp"); + + try + { + file.delete(); + file.open(); + + file.fill(blockSize * blocks); + + long[] result = new long[tries]; + + byte[] block = new byte[blockSize]; + + for (int i = 0; i < block.length; i++) + { + block[i] = (byte) 't'; + } + + ByteBuffer bufferBlock = factory.newBuffer(blockSize); + bufferBlock.put(block); + bufferBlock.position(0); + + final ReusableLatch latch = new ReusableLatch(0); + + IOCallback callback = new IOCallback() + { + @Override + public void done() + { + latch.countDown(); + } + + @Override + public void onError(int errorCode, String errorMessage) + { + + } + }; + + DecimalFormat dcformat = new DecimalFormat("###.##"); + for (int ntry = 0; ntry < tries; ntry++) + { + + if (verbose) + { + System.out.println("**************************************************"); + System.out.println(ntry + " of " + tries + " calculation"); + } + file.position(0); + long start = System.currentTimeMillis(); + for (int i = 0; i < blocks; i++) + { + bufferBlock.position(0); + latch.countUp(); + file.writeDirect(bufferBlock, true, callback); + if (!latch.await(5, TimeUnit.SECONDS)) + { + throw new IOException("Callback wasn't called"); + } + } + long end = System.currentTimeMillis(); + + result[ntry] = (end - start); + + if (verbose) + { + double writesPerMillisecond = (double)blocks / (double) result[ntry]; + System.out.println("Time = " + result[ntry]); + System.out.println("Writes / millisecond = " + dcformat.format(writesPerMillisecond)); + System.out.println("bufferTimeout = " + toNanos(result[ntry], blocks)); + System.out.println("**************************************************"); + } + } + + factory.releaseDirectBuffer(bufferBlock); + + long totalTime = Long.MAX_VALUE; + for (int i = 0; i < tries; i++) + { + if (result[i] < totalTime) + { + totalTime = result[i]; + } + } + + return totalTime; + } + finally + { + try + { + file.close(); + } + catch (Exception e) + { + } + try + { + file.delete(); + } + catch (Exception e) + { + } + try + { + factory.stop(); + } + catch (Exception e) + { + } + } + } + + + public static long toNanos(long time, long blocks) + { + + double blocksPerMillisecond = (double) blocks / (double) (time); + + long nanoSeconds = TimeUnit.NANOSECONDS.convert(1, TimeUnit.MILLISECONDS); + + long timeWait = (long) (nanoSeconds / blocksPerMillisecond); + + return timeWait; + } + + private static SequentialFileFactory newFactory(File datafolder, boolean aio) + { + if (aio && LibaioContext.isLoaded()) + { + SequentialFileFactory factory = new AIOSequentialFileFactory(datafolder, 1); + factory.start(); + ((AIOSequentialFileFactory) factory).disableBufferReuse(); + + return factory; + } + else + { + SequentialFileFactory factory = new NIOSequentialFileFactory(datafolder, 1); + factory.start(); + return factory; + } + } +} diff --git a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/broker.xml b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/broker.xml index 52d665ed47..1cd32456e4 100644 --- a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/broker.xml +++ b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/broker.xml @@ -42,6 +42,7 @@ under the License. ${data.dir}/large-messages 10 +${journal-buffer.settings} ${connector-config.settings} diff --git a/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/journal-buffer-settings.txt b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/journal-buffer-settings.txt new file mode 100644 index 0000000000..566c29ea78 --- /dev/null +++ b/artemis-cli/src/main/resources/org/apache/activemq/artemis/cli/commands/etc/journal-buffer-settings.txt @@ -0,0 +1,8 @@ + + + ${nanoseconds} diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java index 99c8f23145..3aed71e79e 100644 --- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java +++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java @@ -25,6 +25,8 @@ import java.util.concurrent.TimeUnit; import org.apache.activemq.artemis.cli.Artemis; import org.apache.activemq.artemis.cli.commands.Run; +import org.apache.activemq.artemis.cli.commands.util.SyncCalculation; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQDestination; import org.junit.After; @@ -68,6 +70,20 @@ public class ArtemisTest testCli("create","/rawr"); } + @Test + public void testSync() throws Exception + { + int writes = 2560; + int tries = 10; + long totalAvg = SyncCalculation.syncTest(temporaryFolder.getRoot(), 4096, writes, tries, true, true); + System.out.println(); + System.out.println("TotalAvg = " + totalAvg); + long nanoTime = SyncCalculation.toNanos(totalAvg, writes); + System.out.println("nanoTime avg = " + nanoTime); + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); + + } + @Test public void testSimpleRun() throws Exception { @@ -75,9 +91,9 @@ public class ArtemisTest Artemis.main("create", temporaryFolder.getRoot().getAbsolutePath(), "--force", "--silent-input", "--no-web"); System.setProperty("artemis.instance", temporaryFolder.getRoot().getAbsolutePath()); // Some exceptions may happen on the initialization, but they should be ok on start the basic core protocol - Artemis.main("run"); - Assert.assertEquals(Integer.valueOf(70), Artemis.execute("producer", "--txt-size", "50", "--message-count", "70", "--verbose")); - Assert.assertEquals(Integer.valueOf(70), Artemis.execute("consumer", "--txt-size", "50", "--verbose", "--break-on-null", "--receive-timeout", "100")); + Artemis.execute("run"); + Assert.assertEquals(Integer.valueOf(1000), Artemis.execute("producer", "--message-count", "1000", "--verbose")); + Assert.assertEquals(Integer.valueOf(1000), Artemis.execute("consumer", "--verbose", "--break-on-null", "--receive-timeout", "100")); ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = cf.createConnection(); @@ -116,6 +132,7 @@ public class ArtemisTest Artemis.execute("stop"); Assert.assertTrue(Run.latchRunning.await(5, TimeUnit.SECONDS)); + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); } diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/StreamClassPathTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/StreamClassPathTest.java index 632e2c06b6..0ee3afbcf5 100644 --- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/StreamClassPathTest.java +++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/StreamClassPathTest.java @@ -49,6 +49,7 @@ public class StreamClassPathTest openStream(Create.ETC_CLUSTER_SETTINGS_TXT); openStream(Create.ETC_CONNECTOR_SETTINGS_TXT); openStream(Create.ETC_BOOTSTRAP_WEB_SETTINGS_TXT); + openStream(Create.ETC_JOURNAL_BUFFER_SETTINGS); } diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/api/core/ActiveMQNativeIOError.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/api/core/ActiveMQNativeIOError.java index 8a47dfa5bb..e69a7fd3f5 100644 --- a/artemis-commons/src/main/java/org/apache/activemq/artemis/api/core/ActiveMQNativeIOError.java +++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/api/core/ActiveMQNativeIOError.java @@ -34,4 +34,9 @@ public final class ActiveMQNativeIOError extends ActiveMQException { super(ActiveMQExceptionType.NATIVE_ERROR_CANT_INITIALIZE_AIO, msg); } + + public ActiveMQNativeIOError(String msg, Throwable e) + { + super(ActiveMQExceptionType.NATIVE_ERROR_CANT_INITIALIZE_AIO, msg, e); + } } diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/persistence/impl/journal/JMSJournalStorageManagerImpl.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/persistence/impl/journal/JMSJournalStorageManagerImpl.java index b3ef03854d..2d884e7aec 100644 --- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/persistence/impl/journal/JMSJournalStorageManagerImpl.java +++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/persistence/impl/journal/JMSJournalStorageManagerImpl.java @@ -29,9 +29,9 @@ import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.replication.ReplicatedJournal; import org.apache.activemq.artemis.core.replication.ReplicationManager; import org.apache.activemq.artemis.core.server.JournalType; @@ -87,7 +87,7 @@ public final class JMSJournalStorageManagerImpl implements JMSStorageManager createDir = config.isCreateBindingsDir(); - SequentialFileFactory bindingsJMS = new NIOSequentialFileFactory(config.getBindingsLocation()); + SequentialFileFactory bindingsJMS = new NIOSequentialFileFactory(config.getBindingsLocation(), 1); Journal localJMS = new JournalImpl(1024 * 1024, 2, diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/AsynchronousFile.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/AsynchronousFile.java deleted file mode 100644 index 52b8e053d9..0000000000 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/AsynchronousFile.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.activemq.artemis.core.asyncio; - -import java.nio.ByteBuffer; - -import org.apache.activemq.artemis.api.core.ActiveMQException; - -public interface AsynchronousFile -{ - void close() throws InterruptedException, ActiveMQException; - - /** - * - * Note: If you are using a native Linux implementation, maxIO can't be higher than what's defined on /proc/sys/fs/aio-max-nr, or you would get an error - * @param fileName - * @param maxIO The number of max concurrent asynchronous IO operations. It has to be balanced between the size of your writes and the capacity of your disk. - * @throws ActiveMQException - */ - void open(String fileName, int maxIO) throws ActiveMQException; - - /** - * Warning: This function will perform a synchronous IO, probably translating to a fstat call - * @throws ActiveMQException - * */ - long size() throws ActiveMQException; - - /** Any error will be reported on the callback interface */ - void write(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioCallback); - - /** - * Performs an internal direct write. - * @throws ActiveMQException - */ - void writeInternal(long positionToWrite, long size, ByteBuffer bytes) throws ActiveMQException; - - void read(long position, long size, ByteBuffer directByteBuffer, AIOCallback aioCallback) throws ActiveMQException; - - void fill(long position, int blocks, long size, byte fillChar) throws ActiveMQException; - - void setBufferCallback(BufferCallback callback); - - int getBlockSize(); -} diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/impl/AsynchronousFileImpl.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/impl/AsynchronousFileImpl.java deleted file mode 100644 index be4d885f51..0000000000 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/impl/AsynchronousFileImpl.java +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.activemq.artemis.core.asyncio.impl; - -import java.nio.ByteBuffer; -import java.nio.channels.FileLock; -import java.util.PriorityQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.activemq.artemis.api.core.ActiveMQException; -import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; -import org.apache.activemq.artemis.core.asyncio.AIOCallback; -import org.apache.activemq.artemis.core.asyncio.AsynchronousFile; -import org.apache.activemq.artemis.core.asyncio.BufferCallback; -import org.apache.activemq.artemis.core.asyncio.IOExceptionListener; -import org.apache.activemq.artemis.core.libaio.Native; -import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; -import org.apache.activemq.artemis.utils.ReusableLatch; - -/** - * AsynchronousFile implementation - * - * Warning: Case you refactor the name or the package of this class - * You need to make sure you also rename the C++ native calls - */ -public class AsynchronousFileImpl implements AsynchronousFile -{ - // Static ---------------------------------------------------------------------------- - - private static final AtomicInteger totalMaxIO = new AtomicInteger(0); - - private static boolean loaded = false; - - /** - * This definition needs to match Version.h on the native sources. - *
- * Or else the native module won't be loaded because of version mismatches - */ - private static final int EXPECTED_NATIVE_VERSION = 52; - - /** - * Used to determine the next writing sequence - */ - private final AtomicLong nextWritingSequence = new AtomicLong(0); - - /** - * Used to determine the next writing sequence. - * This is accessed from a single thread (the Poller Thread) - */ - private long nextReadSequence = 0; - - /** - * AIO can't guarantee ordering over callbacks. - *
- * We use this {@link PriorityQueue} to hold values until they are in order - */ - private final PriorityQueue pendingCallbacks = new PriorityQueue(); - - public static void addMax(final int io) - { - AsynchronousFileImpl.totalMaxIO.addAndGet(io); - } - - /** - * For test purposes - */ - public static int getTotalMaxIO() - { - return AsynchronousFileImpl.totalMaxIO.get(); - } - - public static void resetMaxAIO() - { - AsynchronousFileImpl.totalMaxIO.set(0); - } - - public static int openFile(String fileName) - { - return Native.openFile(fileName); - } - - public static void closeFile(int handle) - { - Native.closeFile(handle); - } - - public static void destroyBuffer(ByteBuffer buffer) - { - Native.destroyBuffer(buffer); - } - - private static boolean loadLibrary(final String name) - { - try - { - ActiveMQJournalLogger.LOGGER.trace(name + " being loaded"); - System.loadLibrary(name); - if (Native.getNativeVersion() != AsynchronousFileImpl.EXPECTED_NATIVE_VERSION) - { - ActiveMQJournalLogger.LOGGER.incompatibleNativeLibrary(); - return false; - } - else - { - return true; - } - } - catch (Throwable e) - { - ActiveMQJournalLogger.LOGGER.debug(name + " -> error loading the native library", e); - return false; - } - - } - - static - { - String[] libraries = new String[]{"artemis-native", "artemis-native-64", "artemis-native-32"}; - - for (String library : libraries) - { - if (AsynchronousFileImpl.loadLibrary(library)) - { - AsynchronousFileImpl.loaded = true; - break; - } - else - { - ActiveMQJournalLogger.LOGGER.debug("Library " + library + " not found!"); - } - } - - if (!AsynchronousFileImpl.loaded) - { - ActiveMQJournalLogger.LOGGER.debug("Couldn't locate LibAIO Wrapper"); - } - } - - public static boolean isLoaded() - { - return AsynchronousFileImpl.loaded; - } - - // Attributes ------------------------------------------------------------------------ - - private boolean opened = false; - - private String fileName; - - /** - * Used while inside the callbackDone and callbackError - */ - private final Lock callbackLock = new ReentrantLock(); - - private final ReusableLatch pollerLatch = new ReusableLatch(); - - private volatile Runnable poller; - - private int maxIO; - - private final Lock writeLock = new ReentrantReadWriteLock().writeLock(); - - private final ReusableLatch pendingWrites = new ReusableLatch(); - - private Semaphore maxIOSemaphore; - - private BufferCallback bufferCallback; - - /** - * A callback for IO errors when they happen - */ - private final IOExceptionListener ioExceptionListener; - - /** - * Warning: Beware of the C++ pointer! It will bite you! :-) - */ - private ByteBuffer handler; - - // A context switch on AIO would make it to synchronize the disk before - // switching to the new thread, what would cause - // serious performance problems. Because of that we make all the writes on - // AIO using a single thread. - private final Executor writeExecutor; - - private final Executor pollerExecutor; - - // AsynchronousFile implementation --------------------------------------------------- - - /** - * @param writeExecutor It needs to be a single Thread executor. If null it will use the user thread to execute write operations - * @param pollerExecutor The thread pool that will initialize poller handlers - */ - public AsynchronousFileImpl(final Executor writeExecutor, final Executor pollerExecutor, final IOExceptionListener ioExceptionListener) - { - this.writeExecutor = writeExecutor; - this.pollerExecutor = pollerExecutor; - this.ioExceptionListener = ioExceptionListener; - } - - public AsynchronousFileImpl(final Executor writeExecutor, final Executor pollerExecutor) - { - this(writeExecutor, pollerExecutor, null); - } - - public void open(final String fileName1, final int maxIOArgument) throws ActiveMQException - { - writeLock.lock(); - - try - { - if (opened) - { - throw new IllegalStateException("AsynchronousFile is already opened"); - } - - this.maxIO = maxIOArgument; - maxIOSemaphore = new Semaphore(this.maxIO); - - this.fileName = fileName1; - - try - { - handler = Native.init(AsynchronousFileImpl.class, fileName1, this.maxIO, ActiveMQJournalLogger.LOGGER); - } - catch (ActiveMQException e) - { - ActiveMQException ex = null; - if (e.getType() == ActiveMQExceptionType.NATIVE_ERROR_CANT_INITIALIZE_AIO) - { - ex = new ActiveMQException(e.getType(), - "Can't initialize AIO. Currently AIO in use = " + AsynchronousFileImpl.totalMaxIO.get() + - ", trying to allocate more " + - maxIOArgument, - e); - } - else - { - ex = e; - } - throw ex; - } - opened = true; - AsynchronousFileImpl.addMax(this.maxIO); - nextWritingSequence.set(0); - nextReadSequence = 0; - } - finally - { - writeLock.unlock(); - } - } - - public void close() throws InterruptedException, ActiveMQException - { - checkOpened(); - - writeLock.lock(); - - try - { - - while (!pendingWrites.await(60000)) - { - ActiveMQJournalLogger.LOGGER.couldNotGetLock(fileName); - } - - while (!maxIOSemaphore.tryAcquire(maxIO, 60, TimeUnit.SECONDS)) - { - ActiveMQJournalLogger.LOGGER.couldNotGetLock(fileName); - } - - maxIOSemaphore = null; - if (poller != null) - { - stopPoller(); - } - - if (handler != null) - { - Native.closeInternal(handler); - AsynchronousFileImpl.addMax(-maxIO); - } - opened = false; - handler = null; - } - finally - { - writeLock.unlock(); - } - } - - - public void writeInternal(long positionToWrite, long size, ByteBuffer bytes) throws ActiveMQException - { - try - { - Native.writeInternal(handler, positionToWrite, size, bytes); - } - catch (ActiveMQException e) - { - fireExceptionListener(e.getType().getCode(), e.getMessage()); - throw e; - } - if (bufferCallback != null) - { - bufferCallback.bufferDone(bytes); - } - } - - - public void write(final long position, - final long size, - final ByteBuffer directByteBuffer, - final AIOCallback aioCallback) - { - if (aioCallback == null) - { - throw new NullPointerException("Null Callback"); - } - - checkOpened(); - if (poller == null) - { - startPoller(); - } - - pendingWrites.countUp(); - - if (writeExecutor != null) - { - maxIOSemaphore.acquireUninterruptibly(); - - writeExecutor.execute(new Runnable() - { - public void run() - { - long sequence = nextWritingSequence.getAndIncrement(); - - try - { - Native.write(AsynchronousFileImpl.this, handler, sequence, position, size, directByteBuffer, aioCallback); - } - catch (ActiveMQException e) - { - callbackError(aioCallback, sequence, directByteBuffer, e.getType().getCode(), e.getMessage()); - } - catch (RuntimeException e) - { - callbackError(aioCallback, - sequence, - directByteBuffer, - ActiveMQExceptionType.INTERNAL_ERROR.getCode(), - e.getMessage()); - } - } - }); - } - else - { - maxIOSemaphore.acquireUninterruptibly(); - - long sequence = nextWritingSequence.getAndIncrement(); - - try - { - Native.write(this, handler, sequence, position, size, directByteBuffer, aioCallback); - } - catch (ActiveMQException e) - { - callbackError(aioCallback, sequence, directByteBuffer, e.getType().getCode(), e.getMessage()); - } - catch (RuntimeException e) - { - callbackError(aioCallback, sequence, directByteBuffer, ActiveMQExceptionType.INTERNAL_ERROR.getCode(), e.getMessage()); - } - } - - } - - public void read(final long position, - final long size, - final ByteBuffer directByteBuffer, - final AIOCallback aioPackage) throws ActiveMQException - { - checkOpened(); - if (poller == null) - { - startPoller(); - } - pendingWrites.countUp(); - maxIOSemaphore.acquireUninterruptibly(); - try - { - Native.read(this, handler, position, size, directByteBuffer, aioPackage); - } - catch (ActiveMQException e) - { - // Release only if an exception happened - maxIOSemaphore.release(); - pendingWrites.countDown(); - throw e; - } - catch (RuntimeException e) - { - // Release only if an exception happened - maxIOSemaphore.release(); - pendingWrites.countDown(); - throw e; - } - } - - public long size() throws ActiveMQException - { - checkOpened(); - return Native.size0(handler); - } - - public void fill(final long position, final int blocks, final long size, final byte fillChar) throws ActiveMQException - { - checkOpened(); - try - { - Native.fill(handler, position, blocks, size, fillChar); - } - catch (ActiveMQException e) - { - fireExceptionListener(e.getType().getCode(), e.getMessage()); - throw e; - } - } - - public int getBlockSize() - { - return 512; - } - - /** - * This needs to be synchronized because of - * http://bugs.sun.com/view_bug.do?bug_id=6791815 - * http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2009-January/000386.html - */ - public static synchronized ByteBuffer newBuffer(final int size) - { - if (size % 512 != 0) - { - throw new RuntimeException("Buffer size needs to be aligned to 512"); - } - - return Native.newNativeBuffer(size); - } - - public void setBufferCallback(final BufferCallback callback) - { - bufferCallback = callback; - } - - /** - * Return the JNI handler used on C++ - */ - public ByteBuffer getHandler() - { - return handler; - } - - public static void clearBuffer(final ByteBuffer buffer) - { - Native.resetBuffer(buffer, buffer.limit()); - buffer.position(0); - } - - // Protected ------------------------------------------------------------------------- - - @Override - protected void finalize() - { - if (opened) - { - ActiveMQJournalLogger.LOGGER.fileFinalizedWhileOpen(fileName); - } - } - - // Private --------------------------------------------------------------------------- - - private void callbackDone(final AIOCallback callback, final long sequence, final ByteBuffer buffer) - { - maxIOSemaphore.release(); - - pendingWrites.countDown(); - - callbackLock.lock(); - - try - { - - if (sequence == -1) - { - callback.done(); - } - else - { - if (sequence == nextReadSequence) - { - nextReadSequence++; - callback.done(); - flushCallbacks(); - } - else - { - pendingCallbacks.add(new CallbackHolder(sequence, callback)); - } - } - - // The buffer is not sent on callback for read operations - if (bufferCallback != null && buffer != null) - { - bufferCallback.bufferDone(buffer); - } - } - finally - { - callbackLock.unlock(); - } - } - - private void flushCallbacks() - { - while (!pendingCallbacks.isEmpty() && pendingCallbacks.peek().sequence == nextReadSequence) - { - CallbackHolder holder = pendingCallbacks.poll(); - if (holder.isError()) - { - ErrorCallback error = (ErrorCallback) holder; - holder.callback.onError(error.errorCode, error.message); - } - else - { - holder.callback.done(); - } - nextReadSequence++; - } - } - - // Called by the JNI layer.. just ignore the - // warning - private void callbackError(final AIOCallback callback, - final long sequence, - final ByteBuffer buffer, - final int errorCode, - final String errorMessage) - { - ActiveMQJournalLogger.LOGGER.callbackError(errorMessage); - - fireExceptionListener(errorCode, errorMessage); - - maxIOSemaphore.release(); - - pendingWrites.countDown(); - - callbackLock.lock(); - - try - { - if (sequence == -1) - { - callback.onError(errorCode, errorMessage); - } - else - { - if (sequence == nextReadSequence) - { - nextReadSequence++; - callback.onError(errorCode, errorMessage); - flushCallbacks(); - } - else - { - pendingCallbacks.add(new ErrorCallback(sequence, callback, errorCode, errorMessage)); - } - } - } - finally - { - callbackLock.unlock(); - } - - // The buffer is not sent on callback for read operations - if (bufferCallback != null && buffer != null) - { - bufferCallback.bufferDone(buffer); - } - } - - /** - * This is called by the native layer - * - * @param errorCode - * @param errorMessage - */ - private void fireExceptionListener(final int errorCode, final String errorMessage) - { - ActiveMQJournalLogger.LOGGER.ioError(errorCode, errorMessage); - if (ioExceptionListener != null) - { - ioExceptionListener.onIOException(ActiveMQExceptionType.getType(errorCode).createException(errorMessage), errorMessage); - } - } - - private void pollEvents() - { - if (!opened) - { - return; - } - Native.internalPollEvents(handler); - } - - private void startPoller() - { - writeLock.lock(); - - try - { - - if (poller == null) - { - pollerLatch.countUp(); - poller = new PollerRunnable(); - try - { - pollerExecutor.execute(poller); - } - catch (Exception ex) - { - ActiveMQJournalLogger.LOGGER.errorStartingPoller(ex); - } - } - } - finally - { - writeLock.unlock(); - } - } - - private void checkOpened() - { - if (!opened) - { - throw new RuntimeException("File is not opened"); - } - } - - /** - * @throws ActiveMQException - * @throws InterruptedException - */ - private void stopPoller() throws ActiveMQException, InterruptedException - { - Native.stopPoller(handler); - // We need to make sure we won't call close until Poller is - // completely done, or we might get beautiful GPFs - pollerLatch.await(); - } - - public static FileLock lock(int handle) - { - if (Native.flock(handle)) - { - return new ActiveMQFileLock(handle); - } - else - { - return null; - } - } - - // Native ---------------------------------------------------------------------------- - - - /** - * Explicitly adding a compare to clause that returns 0 for at least the same object. - *
- * If {@link Comparable#compareTo(Object)} does not return 0 -for at least the same object- some - * Collection classes methods will fail (example {@link PriorityQueue#remove(Object)}. If it - * returns 0, then {@link #equals(Object)} must return {@code true} for the exact same cases, - * otherwise we will get compatibility problems between Java5 and Java6. - */ - private static class CallbackHolder implements Comparable - { - final long sequence; - - final AIOCallback callback; - - public boolean isError() - { - return false; - } - - public CallbackHolder(final long sequence, final AIOCallback callback) - { - this.sequence = sequence; - this.callback = callback; - } - - public int compareTo(final CallbackHolder o) - { - // It shouldn't be equals in any case - if (this == o) - return 0; - if (sequence <= o.sequence) - { - return -1; - } - else - { - return 1; - } - } - - /** - * See {@link CallbackHolder}. - */ - @Override - public int hashCode() - { - return super.hashCode(); - } - - /** - * See {@link CallbackHolder}. - */ - @Override - public boolean equals(Object obj) - { - return super.equals(obj); - } - } - - private static final class ErrorCallback extends CallbackHolder - { - final int errorCode; - - final String message; - - @Override - public boolean isError() - { - return true; - } - - public ErrorCallback(final long sequence, final AIOCallback callback, final int errorCode, final String message) - { - super(sequence, callback); - - this.errorCode = errorCode; - - this.message = message; - } - - /** - * See {@link CallbackHolder}. - */ - @Override - public int hashCode() - { - return super.hashCode(); - } - - /** - * See {@link CallbackHolder}. - */ - @Override - public boolean equals(Object obj) - { - return super.equals(obj); - } - } - - private class PollerRunnable implements Runnable - { - PollerRunnable() - { - } - - public void run() - { - try - { - pollEvents(); - } - finally - { - // This gives us extra protection in cases of interruption - // Case the poller thread is interrupted, this will allow us to - // restart the thread when required - poller = null; - pollerLatch.countDown(); - } - } - } - -} diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractSequentialFile.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/AbstractSequentialFile.java similarity index 93% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractSequentialFile.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/AbstractSequentialFile.java index a4eed58038..acc0732732 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractSequentialFile.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/AbstractSequentialFile.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io; import java.io.File; import java.io.IOException; @@ -30,9 +30,9 @@ import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQIOErrorException; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.journal.impl.SimpleWaitIOCallback; +import org.apache.activemq.artemis.core.io.buffer.TimedBuffer; +import org.apache.activemq.artemis.core.io.buffer.TimedBufferObserver; import org.apache.activemq.artemis.journal.ActiveMQJournalBundle; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; @@ -233,7 +233,7 @@ public abstract class AbstractSequentialFile implements SequentialFile } - public void write(final ActiveMQBuffer bytes, final boolean sync, final IOAsyncTask callback) throws IOException + public void write(final ActiveMQBuffer bytes, final boolean sync, final IOCallback callback) throws IOException { if (timedBuffer != null) { @@ -266,7 +266,7 @@ public abstract class AbstractSequentialFile implements SequentialFile } } - public void write(final EncodingSupport bytes, final boolean sync, final IOAsyncTask callback) + public void write(final EncodingSupport bytes, final boolean sync, final IOCallback callback) { if (timedBuffer != null) { @@ -308,18 +308,18 @@ public abstract class AbstractSequentialFile implements SequentialFile return file; } - private static final class DelegateCallback implements IOAsyncTask + private static final class DelegateCallback implements IOCallback { - final List delegates; + final List delegates; - private DelegateCallback(final List delegates) + private DelegateCallback(final List delegates) { this.delegates = delegates; } public void done() { - for (IOAsyncTask callback : delegates) + for (IOCallback callback : delegates) { try { @@ -334,7 +334,7 @@ public abstract class AbstractSequentialFile implements SequentialFile public void onError(final int errorCode, final String errorMessage) { - for (IOAsyncTask callback : delegates) + for (IOCallback callback : delegates) { try { @@ -360,7 +360,7 @@ public abstract class AbstractSequentialFile implements SequentialFile protected class LocalBufferObserver implements TimedBufferObserver { - public void flushBuffer(final ByteBuffer buffer, final boolean requestedSync, final List callbacks) + public void flushBuffer(final ByteBuffer buffer, final boolean requestedSync, final List callbacks) { buffer.flip(); diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractSequentialFileFactory.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/AbstractSequentialFileFactory.java similarity index 92% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractSequentialFileFactory.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/AbstractSequentialFileFactory.java index ec0ab4d5ee..61cd0fdb1e 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractSequentialFileFactory.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/AbstractSequentialFileFactory.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io; import java.io.File; import java.io.FilenameFilter; @@ -30,16 +30,14 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.activemq.artemis.api.core.ActiveMQInterruptedException; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.buffer.TimedBuffer; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; /** * An abstract SequentialFileFactory containing basic functionality for both AIO and NIO SequentialFactories */ -abstract class AbstractSequentialFileFactory implements SequentialFileFactory +public abstract class AbstractSequentialFileFactory implements SequentialFileFactory { // Timeout used to wait executors to shutdown @@ -53,6 +51,8 @@ abstract class AbstractSequentialFileFactory implements SequentialFileFactory protected final long bufferTimeout; + protected final int maxIO; + private final IOCriticalErrorListener critialErrorListener; /** @@ -62,16 +62,17 @@ abstract class AbstractSequentialFileFactory implements SequentialFileFactory * */ protected ExecutorService writeExecutor; - AbstractSequentialFileFactory(final File journalDir, + protected AbstractSequentialFileFactory(final File journalDir, final boolean buffered, final int bufferSize, final int bufferTimeout, + final int maxIO, final boolean logRates, final IOCriticalErrorListener criticalErrorListener) { this.journalDir = journalDir; - if (buffered) + if (buffered && bufferTimeout > 0) { timedBuffer = new TimedBuffer(bufferSize, bufferTimeout, logRates); } @@ -82,6 +83,7 @@ abstract class AbstractSequentialFileFactory implements SequentialFileFactory this.bufferSize = bufferSize; this.bufferTimeout = bufferTimeout; this.critialErrorListener = criticalErrorListener; + this.maxIO = maxIO; } public void stop() @@ -128,7 +130,11 @@ abstract class AbstractSequentialFileFactory implements SequentialFileFactory true, AbstractSequentialFileFactory.getThisClassLoader())); } + } + public int getMaxIO() + { + return maxIO; } @Override diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/DummyCallback.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/DummyCallback.java similarity index 89% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/DummyCallback.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/DummyCallback.java index 9c4c3d64fd..ce21f2aad6 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/DummyCallback.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/DummyCallback.java @@ -14,11 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io; +import org.apache.activemq.artemis.core.journal.impl.SyncIOCompletion; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; -class DummyCallback extends SyncIOCompletion +public class DummyCallback extends SyncIOCompletion { private static final DummyCallback instance = new DummyCallback(); diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/AIOCallback.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOCallback.java similarity index 94% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/AIOCallback.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOCallback.java index 80aa753c71..41470e484f 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/AIOCallback.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOCallback.java @@ -14,12 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.asyncio; +package org.apache.activemq.artemis.core.io; /** * The interface used for AIO Callbacks. */ -public interface AIOCallback +public interface IOCallback { /** * Method for sync notifications. When this callback method is called, there is a guarantee the data is written on the disk. diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCriticalErrorListener.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOCriticalErrorListener.java similarity index 90% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCriticalErrorListener.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOCriticalErrorListener.java index fc0bbf91af..f2da3e8daa 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCriticalErrorListener.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOCriticalErrorListener.java @@ -14,8 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal; +package org.apache.activemq.artemis.core.io; +/** + * TODO Merge this with IOExceptionListener + */ public interface IOCriticalErrorListener { void onIOException(Exception code, String message, SequentialFile file); diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/IOExceptionListener.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOExceptionListener.java similarity index 94% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/IOExceptionListener.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOExceptionListener.java index 0cfe945b4b..5c855e52b0 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/IOExceptionListener.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/IOExceptionListener.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.asyncio; +package org.apache.activemq.artemis.core.io; public interface IOExceptionListener { diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/SequentialFile.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/SequentialFile.java similarity index 73% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/SequentialFile.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/SequentialFile.java index 34e6d024b3..cb9d070f3f 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/SequentialFile.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/SequentialFile.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal; +package org.apache.activemq.artemis.core.io; import java.io.File; import java.io.IOException; @@ -22,19 +22,18 @@ import java.nio.ByteBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQException; -import org.apache.activemq.artemis.core.journal.impl.TimedBuffer; +import org.apache.activemq.artemis.core.journal.EncodingSupport; +import org.apache.activemq.artemis.core.io.buffer.TimedBuffer; public interface SequentialFile { - /* - * Creates the file if it doesn't already exist, then opens it - */ - void open() throws Exception; boolean isOpen(); boolean exists(); + void open() throws Exception; + /** * The maximum number of simultaneous writes accepted * @param maxIO @@ -50,15 +49,15 @@ public interface SequentialFile String getFileName(); - void fill(int position, int size, byte fillCharacter) throws Exception; + void fill(int size) throws Exception; void delete() throws IOException, InterruptedException, ActiveMQException; - void write(ActiveMQBuffer bytes, boolean sync, IOAsyncTask callback) throws Exception; + void write(ActiveMQBuffer bytes, boolean sync, IOCallback callback) throws Exception; void write(ActiveMQBuffer bytes, boolean sync) throws Exception; - void write(EncodingSupport bytes, boolean sync, IOAsyncTask callback) throws Exception; + void write(EncodingSupport bytes, boolean sync, IOCallback callback) throws Exception; void write(EncodingSupport bytes, boolean sync) throws Exception; @@ -68,10 +67,10 @@ public interface SequentialFile * NIO). To be safe, use a buffer from the corresponding * {@link SequentialFileFactory#newBuffer(int)}. */ - void writeDirect(ByteBuffer bytes, boolean sync, IOAsyncTask callback); + void writeDirect(ByteBuffer bytes, boolean sync, IOCallback callback); /** - * Write directly to the file without using any buffer + * Write directly to the file without using intermediate any buffer * @param bytes the ByteBuffer must be compatible with the SequentialFile implementation (AIO or * NIO). To be safe, use a buffer from the corresponding * {@link SequentialFileFactory#newBuffer(int)}. @@ -79,21 +78,11 @@ public interface SequentialFile void writeDirect(ByteBuffer bytes, boolean sync) throws Exception; /** - * Write directly to the file. This is used by compacting and other places where we write a big - * buffer in a single shot. writeInternal should always block until the entire write is sync on - * disk. * @param bytes the ByteBuffer must be compatible with the SequentialFile implementation (AIO or * NIO). To be safe, use a buffer from the corresponding * {@link SequentialFileFactory#newBuffer(int)}. */ - void writeInternal(ByteBuffer bytes) throws Exception; - - /** - * @param bytes the ByteBuffer must be compatible with the SequentialFile implementation (AIO or - * NIO). To be safe, use a buffer from the corresponding - * {@link SequentialFileFactory#newBuffer(int)}. - */ - int read(ByteBuffer bytes, IOAsyncTask callback) throws Exception; + int read(ByteBuffer bytes, IOCallback callback) throws Exception; /** * @param bytes the ByteBuffer must be compatible with the SequentialFile implementation (AIO or @@ -108,8 +97,6 @@ public interface SequentialFile void close() throws Exception; - void waitForClose() throws Exception; - void sync() throws IOException; long size() throws Exception; diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/SequentialFileFactory.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/SequentialFileFactory.java similarity index 95% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/SequentialFileFactory.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/SequentialFileFactory.java index cb47bd9cd3..b9a72caf2e 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/SequentialFileFactory.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/SequentialFileFactory.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal; +package org.apache.activemq.artemis.core.io; import java.io.File; import java.nio.ByteBuffer; @@ -26,7 +26,9 @@ import java.util.List; */ public interface SequentialFileFactory { - SequentialFile createSequentialFile(String fileName, int maxIO); + SequentialFile createSequentialFile(String fileName); + + int getMaxIO(); /** * Lists files that end with the given extension. diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AIOSequentialFile.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/AIOSequentialFile.java similarity index 52% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AIOSequentialFile.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/AIOSequentialFile.java index acef8a5db9..7503681b4a 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AIOSequentialFile.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/AIOSequentialFile.java @@ -14,49 +14,64 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io.aio; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.PriorityQueue; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import org.apache.activemq.artemis.api.core.ActiveMQException; -import org.apache.activemq.artemis.core.asyncio.AsynchronousFile; -import org.apache.activemq.artemis.core.asyncio.BufferCallback; -import org.apache.activemq.artemis.core.asyncio.IOExceptionListener; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.api.core.ActiveMQNativeIOError; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.io.AbstractSequentialFile; +import org.apache.activemq.artemis.core.io.DummyCallback; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.journal.impl.SimpleWaitIOCallback; +import org.apache.activemq.artemis.jlibaio.LibaioFile; +import org.apache.activemq.artemis.utils.ReusableLatch; -public class AIOSequentialFile extends AbstractSequentialFile implements IOExceptionListener +public class AIOSequentialFile extends AbstractSequentialFile { private boolean opened = false; - private final int maxIO; + private LibaioFile aioFile; - private AsynchronousFile aioFile; + private final AIOSequentialFileFactory aioFactory; - private final BufferCallback bufferCallback; + private final ReusableLatch pendingCallbacks = new ReusableLatch(); - /** The pool for Thread pollers */ - private final Executor pollerExecutor; + /** + * Used to determine the next writing sequence + */ + private final AtomicLong nextWritingSequence = new AtomicLong(0); - public AIOSequentialFile(final SequentialFileFactory factory, + /** + * AIO can't guarantee ordering over callbacks. + *
+ * We use this {@link PriorityQueue} to hold values until they are in order + */ + final PriorityQueue pendingCallbackList = new PriorityQueue<>(); + + /** + * Used to determine the next writing sequence. + * This is accessed from a single thread (the Poller Thread) + */ + private long nextReadSequence = 0; + + + public AIOSequentialFile(final AIOSequentialFileFactory factory, final int bufferSize, final long bufferTimeoutMilliseconds, final File directory, final String fileName, - final int maxIO, - final BufferCallback bufferCallback, - final Executor writerExecutor, - final Executor pollerExecutor) + final Executor writerExecutor) { super(directory, fileName, factory, writerExecutor); - this.maxIO = maxIO; - this.bufferCallback = bufferCallback; - this.pollerExecutor = pollerExecutor; + this.aioFactory = factory; } public boolean isOpen() @@ -82,15 +97,12 @@ public class AIOSequentialFile extends AbstractSequentialFile implements IOExcep public SequentialFile cloneFile() { - return new AIOSequentialFile(factory, + return new AIOSequentialFile(aioFactory, -1, -1, getFile().getParentFile(), getFile().getName(), - maxIO, - bufferCallback, - writerExecutor, - pollerExecutor); + writerExecutor); } @Override @@ -103,115 +115,73 @@ public class AIOSequentialFile extends AbstractSequentialFile implements IOExcep super.close(); + if (!pendingCallbacks.await(10, TimeUnit.SECONDS)) + { + factory.onIOError(new IOException("Timeout on close"), "Timeout on close", this); + } + opened = false; timedBuffer = null; aioFile.close(); aioFile = null; - - notifyAll(); } - @Override - public synchronized void waitForClose() throws Exception - { - while (isOpen()) - { - wait(); - } - } - public void fill(final int position, final int size, final byte fillCharacter) throws Exception + public synchronized void fill(final int size) throws Exception { checkOpened(); + aioFile.fill(size); - int fileblockSize = aioFile.getBlockSize(); - - int blockSize = fileblockSize; - - if (size % (100 * 1024 * 1024) == 0) - { - blockSize = 100 * 1024 * 1024; - } - else if (size % (10 * 1024 * 1024) == 0) - { - blockSize = 10 * 1024 * 1024; - } - else if (size % (1024 * 1024) == 0) - { - blockSize = 1024 * 1024; - } - else if (size % (10 * 1024) == 0) - { - blockSize = 10 * 1024; - } - else - { - blockSize = fileblockSize; - } - - int blocks = size / blockSize; - - if (size % blockSize != 0) - { - blocks++; - } - - int filePosition = position; - - if (position % fileblockSize != 0) - { - filePosition = (position / fileblockSize + 1) * fileblockSize; - } - - aioFile.fill(filePosition, blocks, blockSize, fillCharacter); - - fileSize = aioFile.size(); + fileSize = aioFile.getSize(); } public void open() throws Exception { - open(maxIO, true); + open(aioFactory.getMaxIO(), true); } public synchronized void open(final int maxIO, final boolean useExecutor) throws ActiveMQException { opened = true; - aioFile = new AsynchronousFileImpl(useExecutor ? writerExecutor : null, pollerExecutor, this); - try { - aioFile.open(getFile().getAbsolutePath(), maxIO); + aioFile = aioFactory.libaioContext.openFile(getFile(), true); } - catch (ActiveMQException e) + catch (IOException e) { factory.onIOError(e, e.getMessage(), this); - throw e; + throw new ActiveMQNativeIOError(e.getMessage(), e); } position.set(0); - aioFile.setBufferCallback(bufferCallback); - - fileSize = aioFile.size(); + fileSize = aioFile.getSize(); } - public void setBufferCallback(final BufferCallback callback) - { - aioFile.setBufferCallback(callback); - } - - public int read(final ByteBuffer bytes, final IOAsyncTask callback) throws ActiveMQException + public int read(final ByteBuffer bytes, final IOCallback callback) throws ActiveMQException { + checkOpened(); int bytesToRead = bytes.limit(); long positionToRead = position.getAndAdd(bytesToRead); bytes.rewind(); - aioFile.read(positionToRead, bytesToRead, bytes, callback); + try + { + // We don't send the buffer to the callback on read, + // because we want the buffer available. + // Sending it through the callback would make it released + aioFile.read(positionToRead, bytesToRead, bytes, getCallback(callback, null)); + } + catch (IOException e) + { + factory.onIOError(e, e.getMessage(), this); + throw new ActiveMQNativeIOError(e.getMessage(), e); + } return bytesToRead; } @@ -227,39 +197,6 @@ public class AIOSequentialFile extends AbstractSequentialFile implements IOExcep return bytesRead; } - public void sync() - { - throw new UnsupportedOperationException("This method is not supported on AIO"); - } - - public long size() throws Exception - { - if (aioFile == null) - { - return getFile().length(); - } - else - { - return aioFile.size(); - } - } - - @Override - public String toString() - { - return "AIOSequentialFile:" + getFile().getAbsolutePath(); - } - - // Public methods - // ----------------------------------------------------------------------------------------------------- - - @Override - public void onIOException(Exception code, String message) - { - factory.onIOError(code, message, this); - } - - public void writeDirect(final ByteBuffer bytes, final boolean sync) throws Exception { if (sync) @@ -278,24 +215,94 @@ public class AIOSequentialFile extends AbstractSequentialFile implements IOExcep /** * - * @param sync Not used on AIO + * Note: Parameter sync is not used on AIO * */ - public void writeDirect(final ByteBuffer bytes, final boolean sync, final IOAsyncTask callback) + public void writeDirect(final ByteBuffer bytes, final boolean sync, final IOCallback callback) { + checkOpened(); + final int bytesToWrite = factory.calculateBlockSize(bytes.limit()); final long positionToWrite = position.getAndAdd(bytesToWrite); - aioFile.write(positionToWrite, bytesToWrite, bytes, callback); + AIOSequentialFileFactory.AIOSequentialCallback runnableCallback = getCallback(callback, bytes); + runnableCallback.initWrite(positionToWrite, bytesToWrite); + if (writerExecutor != null) + { + writerExecutor.execute(runnableCallback); + } + else + { + runnableCallback.run(); + } } - public void writeInternal(final ByteBuffer bytes) throws ActiveMQException + + + AIOSequentialFileFactory.AIOSequentialCallback getCallback(IOCallback originalCallback, ByteBuffer buffer) { - final int bytesToWrite = factory.calculateBlockSize(bytes.limit()); + AIOSequentialFileFactory.AIOSequentialCallback callback = aioFactory.getCallback(); + callback.init(this.nextWritingSequence.getAndIncrement(), originalCallback, aioFile, this, buffer); + pendingCallbacks.countUp(); + return callback; + } - final long positionToWrite = position.getAndAdd(bytesToWrite); - aioFile.writeInternal(positionToWrite, bytesToWrite, bytes); + void done(AIOSequentialFileFactory.AIOSequentialCallback callback) + { + if (callback.writeSequence == -1) + { + callback.sequentialDone(); + pendingCallbacks.countDown(); + } + + + if (callback.writeSequence == nextReadSequence) + { + nextReadSequence++; + callback.sequentialDone(); + pendingCallbacks.countDown(); + flushCallbacks(); + } + else + { + pendingCallbackList.add(callback); + } + + } + + private void flushCallbacks() + { + while (!pendingCallbackList.isEmpty() && pendingCallbackList.peek().writeSequence == nextReadSequence) + { + AIOSequentialFileFactory.AIOSequentialCallback callback = pendingCallbackList.poll(); + callback.sequentialDone(); + nextReadSequence++; + pendingCallbacks.countDown(); + } + } + + public void sync() + { + throw new UnsupportedOperationException("This method is not supported on AIO"); + } + + public long size() throws Exception + { + if (aioFile == null) + { + return getFile().length(); + } + else + { + return aioFile.getSize(); + } + } + + @Override + public String toString() + { + return "AIOSequentialFile:" + getFile().getAbsolutePath(); } // Protected methods @@ -319,7 +326,7 @@ public class AIOSequentialFile extends AbstractSequentialFile implements IOExcep { if (aioFile == null || !opened) { - throw new IllegalStateException("File not opened"); + throw new NullPointerException("File not opened, file=null"); } } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AIOSequentialFileFactory.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/AIOSequentialFileFactory.java similarity index 52% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AIOSequentialFileFactory.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/AIOSequentialFileFactory.java index 65e6a6fbf4..39dad2ff90 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AIOSequentialFileFactory.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/AIOSequentialFileFactory.java @@ -14,9 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io.aio; import java.io.File; +import java.io.IOException; import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedAction; @@ -24,13 +25,18 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.activemq.artemis.api.core.ActiveMQInterruptedException; -import org.apache.activemq.artemis.core.asyncio.BufferCallback; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.libaio.Native; +import org.apache.activemq.artemis.core.io.AbstractSequentialFileFactory; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.journal.impl.JournalConstants; +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.jlibaio.LibaioFile; +import org.apache.activemq.artemis.jlibaio.SubmitInfo; +import org.apache.activemq.artemis.jlibaio.util.CallbackCache; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; @@ -40,8 +46,16 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor private final ReuseBuffersController buffersControl = new ReuseBuffersController(); + private volatile boolean reuseBuffers = true; + private ExecutorService pollerExecutor; + volatile LibaioContext libaioContext; + + private final CallbackCache callbackPool; + + private final AtomicBoolean running = new AtomicBoolean(false); + // This method exists just to make debug easier. // I could replace log.trace by log.info temporarily while I was debugging // Journal @@ -50,20 +64,22 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor ActiveMQJournalLogger.LOGGER.trace(message); } - public AIOSequentialFileFactory(final File journalDir) + public AIOSequentialFileFactory(final File journalDir, int maxIO) { this(journalDir, JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, JournalConstants.DEFAULT_JOURNAL_BUFFER_TIMEOUT_AIO, + maxIO, false, null); } - public AIOSequentialFileFactory(final File journalDir, final IOCriticalErrorListener listener) + public AIOSequentialFileFactory(final File journalDir, final IOCriticalErrorListener listener, int maxIO) { this(journalDir, JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, JournalConstants.DEFAULT_JOURNAL_BUFFER_TIMEOUT_AIO, + maxIO, false, listener); } @@ -71,31 +87,53 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor public AIOSequentialFileFactory(final File journalDir, final int bufferSize, final int bufferTimeout, + final int maxIO, final boolean logRates) { - this(journalDir, bufferSize, bufferTimeout, logRates, null); + this(journalDir, bufferSize, bufferTimeout, maxIO, logRates, null); } public AIOSequentialFileFactory(final File journalDir, final int bufferSize, final int bufferTimeout, + final int maxIO, final boolean logRates, final IOCriticalErrorListener listener) { - super(journalDir, true, bufferSize, bufferTimeout, logRates, listener); + super(journalDir, true, bufferSize, bufferTimeout, maxIO, logRates, listener); + callbackPool = new CallbackCache<>(maxIO); } - public SequentialFile createSequentialFile(final String fileName, final int maxIO) + public AIOSequentialCallback getCallback() + { + AIOSequentialCallback callback = callbackPool.get(); + if (callback == null) + { + callback = new AIOSequentialCallback(); + } + + return callback; + } + + public void enableBufferReuse() + { + this.reuseBuffers = true; + } + + public void disableBufferReuse() + { + this.reuseBuffers = false; + } + + + public SequentialFile createSequentialFile(final String fileName) { return new AIOSequentialFile(this, bufferSize, bufferTimeout, journalDir, fileName, - maxIO, - buffersControl.callback, - writeExecutor, - pollerExecutor); + writeExecutor); } public boolean isSupportsCallbacks() @@ -105,7 +143,7 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor public static boolean isSupported() { - return AsynchronousFileImpl.isLoaded(); + return LibaioContext.isLoaded(); } public ByteBuffer allocateDirectBuffer(final int size) @@ -118,7 +156,7 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor } // The buffer on AIO has to be a multiple of 512 - ByteBuffer buffer = AsynchronousFileImpl.newBuffer(blocks * 512); + ByteBuffer buffer = LibaioContext.newAlignedBuffer(blocks * 512, 512); buffer.limit(size); @@ -127,7 +165,7 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor public void releaseDirectBuffer(final ByteBuffer buffer) { - Native.destroyBuffer(buffer); + LibaioContext.freeBuffer(buffer); } public ByteBuffer newBuffer(int size) @@ -142,7 +180,8 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor public void clearBuffer(final ByteBuffer directByteBuffer) { - AsynchronousFileImpl.clearBuffer(directByteBuffer); + directByteBuffer.position(0); + libaioContext.memsetBuffer(directByteBuffer); } public int getAlignment() @@ -168,48 +207,63 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFileFactory#releaseBuffer(java.nio.ByteBuffer) + * @see org.apache.activemq.artemis.core.io.SequentialFileFactory#releaseBuffer(java.nio.ByteBuffer) */ @Override public synchronized void releaseBuffer(final ByteBuffer buffer) { - Native.destroyBuffer(buffer); + LibaioContext.freeBuffer(buffer); } @Override public void start() { - super.start(); + if (running.compareAndSet(false, true)) + { + super.start(); - pollerExecutor = Executors.newCachedThreadPool(new ActiveMQThreadFactory("ActiveMQ-AIO-poller-pool" + System.identityHashCode(this), - true, - AIOSequentialFileFactory.getThisClassLoader())); + this.libaioContext = new LibaioContext(maxIO, true); + + this.running.set(true); + + pollerExecutor = Executors.newCachedThreadPool(new ActiveMQThreadFactory("ActiveMQ-AIO-poller-pool" + System.identityHashCode(this), + true, + AIOSequentialFileFactory.getThisClassLoader())); + + pollerExecutor.execute(new PollerRunnable()); + } } @Override public void stop() { - buffersControl.stop(); - - if (pollerExecutor != null) + if (this.running.compareAndSet(true, false)) { - pollerExecutor.shutdown(); + buffersControl.stop(); - try + libaioContext.close(); + libaioContext = null; + + if (pollerExecutor != null) { - if (!pollerExecutor.awaitTermination(AbstractSequentialFileFactory.EXECUTOR_TIMEOUT, TimeUnit.SECONDS)) + pollerExecutor.shutdown(); + + try { - ActiveMQJournalLogger.LOGGER.timeoutOnPollerShutdown(new Exception("trace")); + if (!pollerExecutor.awaitTermination(AbstractSequentialFileFactory.EXECUTOR_TIMEOUT, TimeUnit.SECONDS)) + { + ActiveMQJournalLogger.LOGGER.timeoutOnPollerShutdown(new Exception("trace")); + } + } + catch (InterruptedException e) + { + throw new ActiveMQInterruptedException(e); } } - catch (InterruptedException e) - { - throw new ActiveMQInterruptedException(e); - } - } - super.stop(); + super.stop(); + } } @Override @@ -218,6 +272,135 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor stop(); } + /** + * The same callback is used for Runnable executor. + * This way we can save some memory over the pool. + */ + public class AIOSequentialCallback implements SubmitInfo, Runnable, Comparable + { + IOCallback callback; + boolean error = false; + AIOSequentialFile sequentialFile; + ByteBuffer buffer; + LibaioFile libaioFile; + String errorMessage; + int errorCode = -1; + long writeSequence; + + long position; + int bytes; + + @Override + public String toString() + { + return "AIOSequentialCallback{" + + "error=" + error + + ", errorMessage='" + errorMessage + '\'' + + ", errorCode=" + errorCode + + ", writeSequence=" + writeSequence + + ", position=" + position + + '}'; + } + + public AIOSequentialCallback initWrite(long positionToWrite, int bytesToWrite) + { + this.position = positionToWrite; + this.bytes = bytesToWrite; + return this; + } + + public void run() + { + try + { + libaioFile.write(position, bytes, buffer, this); + } + catch (IOException e) + { + callback.onError(-1, e.getMessage()); + } + } + + public int compareTo(AIOSequentialCallback other) + { + if (this == other || this.writeSequence == other.writeSequence) + { + return 0; + } + else if (other.writeSequence < this.writeSequence) + { + return 1; + } + else + { + return -1; + } + } + + public AIOSequentialCallback init(long writeSequence, IOCallback IOCallback, LibaioFile libaioFile, AIOSequentialFile sequentialFile, ByteBuffer usedBuffer) + { + this.callback = IOCallback; + this.sequentialFile = sequentialFile; + this.error = false; + this.buffer = usedBuffer; + this.libaioFile = libaioFile; + this.writeSequence = writeSequence; + this.errorMessage = null; + return this; + } + + @Override + public void onError(int errno, String message) + { + this.error = true; + this.errorCode = errno; + this.errorMessage = message; + } + + /** + * this is called by libaio. + */ + public void done() + { + this.sequentialFile.done(this); + } + + /** + * This is callbed by the AIOSequentialFile, after determined the callbacks were returned in sequence + */ + public void sequentialDone() + { + + if (error) + { + callback.onError(errorCode, errorMessage); + errorMessage = null; + } + else + { + if (callback != null) + { + callback.done(); + } + + if (buffer != null && reuseBuffers) + { + buffersControl.bufferDone(buffer); + } + + callbackPool.put(AIOSequentialCallback.this); + } + } + } + + private class PollerRunnable implements Runnable + { + public void run() + { + libaioContext.poll(); + } + } + /** * Class that will control buffer-reuse */ @@ -225,17 +408,10 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor { private volatile long bufferReuseLastTime = System.currentTimeMillis(); - /** - * This queue is fed by {@link org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory.ReuseBuffersController.LocalBufferCallback} - * which is called directly by NIO or NIO. On the case of the AIO this is almost called by the native layer as - * soon as the buffer is not being used any more and ready to be reused or GCed - */ private final ConcurrentLinkedQueue reuseBuffersQueue = new ConcurrentLinkedQueue(); private boolean stopped = false; - final BufferCallback callback = new LocalBufferCallback(); - public ByteBuffer newBuffer(final int size) { // if a new buffer wasn't requested in 10 seconds, we clear the queue @@ -258,7 +434,7 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor // buffer. if (size > bufferSize) { - return AsynchronousFileImpl.newBuffer(size); + return LibaioContext.newAlignedBuffer(size, 512); } else { @@ -272,7 +448,7 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor if (buffer == null) { // if empty create a new one. - buffer = AsynchronousFileImpl.newBuffer(bufferSize); + buffer = LibaioContext.newAlignedBuffer(size, 512); buffer.limit(alignedSize); } @@ -306,31 +482,28 @@ public final class AIOSequentialFileFactory extends AbstractSequentialFileFactor } } - private class LocalBufferCallback implements BufferCallback + public void bufferDone(final ByteBuffer buffer) { - public void bufferDone(final ByteBuffer buffer) + synchronized (this) { - synchronized (ReuseBuffersController.this) - { - if (stopped) + if (stopped) + { + releaseBuffer(buffer); + } + else + { + bufferReuseLastTime = System.currentTimeMillis(); + + // If a buffer has any other than the configured bufferSize, the buffer + // will be just sent to GC + if (buffer.capacity() == bufferSize) { - releaseBuffer(buffer); + reuseBuffersQueue.offer(buffer); } else { - bufferReuseLastTime = System.currentTimeMillis(); - - // If a buffer has any other than the configured bufferSize, the buffer - // will be just sent to GC - if (buffer.capacity() == bufferSize) - { - reuseBuffersQueue.offer(buffer); - } - else - { - releaseBuffer(buffer); - } + releaseBuffer(buffer); } } } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/impl/ActiveMQFileLock.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/ActiveMQFileLock.java similarity index 82% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/impl/ActiveMQFileLock.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/ActiveMQFileLock.java index 0af3152343..a184244434 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/impl/ActiveMQFileLock.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/aio/ActiveMQFileLock.java @@ -14,23 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.asyncio.impl; +package org.apache.activemq.artemis.core.io.aio; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; -import org.apache.activemq.artemis.core.libaio.Native; +import org.apache.activemq.artemis.jlibaio.LibaioFile; public class ActiveMQFileLock extends FileLock { - private final int handle; + private final LibaioFile file; - protected ActiveMQFileLock(final int handle) + public ActiveMQFileLock(final LibaioFile handle) { super((FileChannel)null, 0, 0, false); - this.handle = handle; + this.file = handle; } @Override @@ -42,6 +42,6 @@ public class ActiveMQFileLock extends FileLock @Override public void release() throws IOException { - Native.closeFile(handle); + file.close(); } } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TimedBuffer.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/buffer/TimedBuffer.java similarity index 97% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TimedBuffer.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/buffer/TimedBuffer.java index 45d4b6271b..a61569aabb 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TimedBuffer.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/buffer/TimedBuffer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io.buffer; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -28,8 +28,8 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.ActiveMQInterruptedException; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.journal.impl.dataformat.ByteArrayEncoding; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; @@ -57,7 +57,7 @@ public class TimedBuffer private int bufferLimit = 0; - private List callbacks; + private List callbacks; private volatile int timeout; @@ -114,7 +114,7 @@ public class TimedBuffer bufferLimit = 0; - callbacks = new ArrayList(); + callbacks = new ArrayList(); this.timeout = timeout; } @@ -260,12 +260,12 @@ public class TimedBuffer } } - public synchronized void addBytes(final ActiveMQBuffer bytes, final boolean sync, final IOAsyncTask callback) + public synchronized void addBytes(final ActiveMQBuffer bytes, final boolean sync, final IOCallback callback) { addBytes(new ByteArrayEncoding(bytes.toByteBuffer().array()), sync, callback); } - public synchronized void addBytes(final EncodingSupport bytes, final boolean sync, final IOAsyncTask callback) + public synchronized void addBytes(final EncodingSupport bytes, final boolean sync, final IOCallback callback) { if (!started) { @@ -329,7 +329,7 @@ public class TimedBuffer pendingSync = false; // swap the instance as the previous callback list is being used asynchronously - callbacks = new LinkedList(); + callbacks = new LinkedList(); buffer.clear(); diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TimedBufferObserver.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/buffer/TimedBufferObserver.java similarity index 92% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TimedBufferObserver.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/buffer/TimedBufferObserver.java index f219f08fbc..7a9659f4e7 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TimedBufferObserver.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/buffer/TimedBufferObserver.java @@ -14,12 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io.buffer; import java.nio.ByteBuffer; import java.util.List; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; + public interface TimedBufferObserver { @@ -34,7 +35,7 @@ public interface TimedBufferObserver // Public -------------------------------------------------------- - void flushBuffer(ByteBuffer buffer, boolean syncRequested, List callbacks); + void flushBuffer(ByteBuffer buffer, boolean syncRequested, List callbacks); /** Return the number of remaining bytes that still fit on the observer (file) */ int getRemainingBytes(); diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/NIOSequentialFile.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/nio/NIOSequentialFile.java similarity index 91% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/NIOSequentialFile.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/nio/NIOSequentialFile.java index 0dac7f2ed4..d20045ebe2 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/NIOSequentialFile.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/nio/NIOSequentialFile.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io.nio; import java.io.File; import java.io.IOException; @@ -29,9 +29,10 @@ import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; import org.apache.activemq.artemis.api.core.ActiveMQIOErrorException; import org.apache.activemq.artemis.api.core.ActiveMQIllegalStateException; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.io.AbstractSequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.journal.ActiveMQJournalBundle; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; @@ -107,20 +108,16 @@ public final class NIOSequentialFile extends AbstractSequentialFile } } - public void fill(final int position, final int size, final byte fillCharacter) throws IOException + public void fill(final int size) throws IOException { ByteBuffer bb = ByteBuffer.allocate(size); - for (int i = 0; i < size; i++) - { - bb.put(fillCharacter); - } - - bb.flip(); + bb.limit(size); + bb.position(0); try { - channel.position(position); + channel.position(0); channel.write(bb); channel.force(false); channel.position(0); @@ -134,14 +131,6 @@ public final class NIOSequentialFile extends AbstractSequentialFile fileSize = channel.size(); } - public synchronized void waitForClose() throws InterruptedException - { - while (isOpen()) - { - wait(); - } - } - @Override public synchronized void close() throws IOException, InterruptedException, ActiveMQException { @@ -185,7 +174,7 @@ public final class NIOSequentialFile extends AbstractSequentialFile return read(bytes, null); } - public synchronized int read(final ByteBuffer bytes, final IOAsyncTask callback) throws IOException, + public synchronized int read(final ByteBuffer bytes, final IOCallback callback) throws IOException, ActiveMQIllegalStateException { try @@ -278,7 +267,7 @@ public final class NIOSequentialFile extends AbstractSequentialFile return new NIOSequentialFile(factory, directory, getFileName(), maxIO, writerExecutor); } - public void writeDirect(final ByteBuffer bytes, final boolean sync, final IOAsyncTask callback) + public void writeDirect(final ByteBuffer bytes, final boolean sync, final IOCallback callback) { if (callback == null) { @@ -315,7 +304,7 @@ public final class NIOSequentialFile extends AbstractSequentialFile return super.newBuffer(size, limit); } - private void internalWrite(final ByteBuffer bytes, final boolean sync, final IOAsyncTask callback) throws IOException, ActiveMQIOErrorException, InterruptedException + private void internalWrite(final ByteBuffer bytes, final boolean sync, final IOCallback callback) throws IOException, ActiveMQIOErrorException, InterruptedException { if (!isOpen()) { @@ -387,7 +376,7 @@ public final class NIOSequentialFile extends AbstractSequentialFile * @throws IOException * @throws Exception */ - private void doInternalWrite(final ByteBuffer bytes, final boolean sync, final IOAsyncTask callback) throws IOException + private void doInternalWrite(final ByteBuffer bytes, final boolean sync, final IOCallback callback) throws IOException { channel.write(bytes); diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/NIOSequentialFileFactory.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/nio/NIOSequentialFileFactory.java similarity index 82% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/NIOSequentialFileFactory.java rename to artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/nio/NIOSequentialFileFactory.java index e4719280c4..e64e405f3b 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/NIOSequentialFileFactory.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/io/nio/NIOSequentialFileFactory.java @@ -14,45 +14,49 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal.impl; +package org.apache.activemq.artemis.core.io.nio; import java.io.File; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.AbstractSequentialFileFactory; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.journal.impl.JournalConstants; public class NIOSequentialFileFactory extends AbstractSequentialFileFactory { - public NIOSequentialFileFactory(final File journalDir) + public NIOSequentialFileFactory(final File journalDir, final int maxIO) { - this(journalDir, null); + this(journalDir, null, maxIO); } - public NIOSequentialFileFactory(final File journalDir, final IOCriticalErrorListener listener) + public NIOSequentialFileFactory(final File journalDir, final IOCriticalErrorListener listener, final int maxIO) { this(journalDir, false, JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_NIO, JournalConstants.DEFAULT_JOURNAL_BUFFER_TIMEOUT_NIO, + maxIO, false, listener); } - public NIOSequentialFileFactory(final File journalDir, final boolean buffered) + public NIOSequentialFileFactory(final File journalDir, final boolean buffered, final int maxIO) { - this(journalDir, buffered, null); + this(journalDir, buffered, null, maxIO); } public NIOSequentialFileFactory(final File journalDir, final boolean buffered, - final IOCriticalErrorListener listener) + final IOCriticalErrorListener listener, final int maxIO) { this(journalDir, buffered, JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_NIO, JournalConstants.DEFAULT_JOURNAL_BUFFER_TIMEOUT_NIO, + maxIO, false, listener); } @@ -61,29 +65,25 @@ public class NIOSequentialFileFactory extends AbstractSequentialFileFactory final boolean buffered, final int bufferSize, final int bufferTimeout, + final int maxIO, final boolean logRates) { - this(journalDir, buffered, bufferSize, bufferTimeout, logRates, null); + this(journalDir, buffered, bufferSize, bufferTimeout, maxIO, logRates, null); } public NIOSequentialFileFactory(final File journalDir, final boolean buffered, final int bufferSize, final int bufferTimeout, + final int maxIO, final boolean logRates, final IOCriticalErrorListener listener) { - super(journalDir, buffered, bufferSize, bufferTimeout, logRates, listener); + super(journalDir, buffered, bufferSize, bufferTimeout, maxIO, logRates, listener); } - public SequentialFile createSequentialFile(final String fileName, int maxIO) + public SequentialFile createSequentialFile(final String fileName) { - if (maxIO < 1) - { - // A single threaded IO - maxIO = 1; - } - return new NIOSequentialFile(this, journalDir, fileName, maxIO, writeExecutor); } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCompletion.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCompletion.java index b85a845ed5..d0140f17de 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCompletion.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOCompletion.java @@ -16,7 +16,9 @@ */ package org.apache.activemq.artemis.core.journal; -public interface IOCompletion extends IOAsyncTask +import org.apache.activemq.artemis.core.io.IOCallback; + +public interface IOCompletion extends IOCallback { void storeLineUp(); } \ No newline at end of file diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/Journal.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/Journal.java index f3335b0429..6b0beabdf3 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/Journal.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/Journal.java @@ -19,6 +19,7 @@ package org.apache.activemq.artemis.core.journal; import java.util.List; import java.util.Map; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.server.ActiveMQComponent; diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractJournalUpdateTask.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractJournalUpdateTask.java index e21b046076..b36a0c4438 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractJournalUpdateTask.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/AbstractJournalUpdateTask.java @@ -24,8 +24,8 @@ import java.util.Set; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.Pair; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.dataformat.ByteArrayEncoding; import org.apache.activemq.artemis.core.journal.impl.dataformat.JournalAddRecord; import org.apache.activemq.artemis.core.journal.impl.dataformat.JournalInternalRecord; @@ -87,7 +87,7 @@ public abstract class AbstractJournalUpdateTask implements JournalReaderCallback final List> renames) throws Exception { - SequentialFile controlFile = fileFactory.createSequentialFile(AbstractJournalUpdateTask.FILE_COMPACT_CONTROL, 1); + SequentialFile controlFile = fileFactory.createSequentialFile(AbstractJournalUpdateTask.FILE_COMPACT_CONTROL); try { @@ -182,7 +182,7 @@ public abstract class AbstractJournalUpdateTask implements JournalReaderCallback // To Fix the size of the file writingChannel.writerIndex(writingChannel.capacity()); - sequentialFile.writeInternal(writingChannel.toByteBuffer()); + sequentialFile.writeDirect(writingChannel.toByteBuffer(), true); sequentialFile.close(); newDataFiles.add(currentFile); } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/FileWrapperJournal.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/FileWrapperJournal.java index a41e72f12e..5a0f11f532 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/FileWrapperJournal.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/FileWrapperJournal.java @@ -32,7 +32,7 @@ import org.apache.activemq.artemis.core.journal.JournalLoadInformation; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.dataformat.JournalAddRecord; import org.apache.activemq.artemis.core.journal.impl.dataformat.JournalAddRecordTX; diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalBase.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalBase.java index d6a856a856..1ba8f0b7c3 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalBase.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalBase.java @@ -17,6 +17,7 @@ package org.apache.activemq.artemis.core.journal.impl; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; +import org.apache.activemq.artemis.core.io.DummyCallback; import org.apache.activemq.artemis.core.journal.EncodingSupport; import org.apache.activemq.artemis.core.journal.IOCompletion; import org.apache.activemq.artemis.core.journal.Journal; diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalCompactor.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalCompactor.java index 5b0a1b8fb7..1f657a2a6c 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalCompactor.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalCompactor.java @@ -28,8 +28,8 @@ import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.dataformat.ByteArrayEncoding; import org.apache.activemq.artemis.core.journal.impl.dataformat.JournalAddRecord; import org.apache.activemq.artemis.core.journal.impl.dataformat.JournalAddRecordTX; @@ -64,7 +64,7 @@ public class JournalCompactor extends AbstractJournalUpdateTask implements Journ final List newFiles, final List> renameFile) throws Exception { - SequentialFile controlFile = fileFactory.createSequentialFile(AbstractJournalUpdateTask.FILE_COMPACT_CONTROL, 1); + SequentialFile controlFile = fileFactory.createSequentialFile(AbstractJournalUpdateTask.FILE_COMPACT_CONTROL); if (controlFile.exists()) { diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFile.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFile.java index e3b1624b44..dcfc1a2535 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFile.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFile.java @@ -16,7 +16,7 @@ */ package org.apache.activemq.artemis.core.journal.impl; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; public interface JournalFile { diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFileImpl.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFileImpl.java index 4438a9652a..7e96575ff3 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFileImpl.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFileImpl.java @@ -21,7 +21,7 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; public class JournalFileImpl implements JournalFile { diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFilesRepository.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFilesRepository.java index 052dc254a6..268a23d8c3 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFilesRepository.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalFilesRepository.java @@ -31,8 +31,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; /** @@ -662,13 +662,13 @@ public class JournalFilesRepository String tmpFileName = fileName + ".tmp"; - SequentialFile sequentialFile = fileFactory.createSequentialFile(tmpFileName, maxAIO); + SequentialFile sequentialFile = fileFactory.createSequentialFile(tmpFileName); sequentialFile.open(1, false); if (init) { - sequentialFile.fill(0, fileSize, JournalImpl.FILL_CHARACTER); + sequentialFile.fill(fileSize); JournalImpl.initFileHeader(fileFactory, sequentialFile, userVersion, fileID); } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java index 6f411ebf00..068e6975c5 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java @@ -46,15 +46,15 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.Pair; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.journal.IOCompletion; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TestableJournal; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.dataformat.ByteArrayEncoding; @@ -293,7 +293,7 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal final CountDownLatch latch = new CountDownLatch(numIts * 2); - class MyIOAsyncTask implements IOCompletion + class MyAIOCallback implements IOCompletion { public void done() { @@ -310,7 +310,7 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal } } - final MyIOAsyncTask task = new MyIOAsyncTask(); + final MyAIOCallback task = new MyAIOCallback(); final int recordSize = 1024; @@ -373,11 +373,11 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal for (String fileName : fileNames) { - SequentialFile file = fileFactory.createSequentialFile(fileName, filesRepository.getMaxAIO()); + SequentialFile file = fileFactory.createSequentialFile(fileName); if (file.size() >= SIZE_HEADER) { - file.open(1, false); + file.open(); try { @@ -2776,11 +2776,11 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal final boolean completeTransaction, final boolean sync, final JournalTransaction tx, - final IOAsyncTask parameterCallback) throws Exception + final IOCallback parameterCallback) throws Exception { checkJournalIsLoaded(); - final IOAsyncTask callback; + final IOCallback callback; final int size = encoder.getEncodeSize(); @@ -2896,7 +2896,7 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal { for (String dataFile : dataFiles) { - SequentialFile file = fileFactory.createSequentialFile(dataFile, 1); + SequentialFile file = fileFactory.createSequentialFile(dataFile); if (file.exists()) { file.delete(); @@ -2905,7 +2905,7 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal for (String newFile : newFiles) { - SequentialFile file = fileFactory.createSequentialFile(newFile, 1); + SequentialFile file = fileFactory.createSequentialFile(newFile); if (file.exists()) { final String originalName = file.getFileName(); @@ -2916,8 +2916,8 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal for (Pair rename : renames) { - SequentialFile fileTmp = fileFactory.createSequentialFile(rename.getA(), 1); - SequentialFile fileTo = fileFactory.createSequentialFile(rename.getB(), 1); + SequentialFile fileTmp = fileFactory.createSequentialFile(rename.getA()); + SequentialFile fileTo = fileFactory.createSequentialFile(rename.getB()); // We should do the rename only if the tmp file still exist, or else we could // delete a valid file depending on where the crash occurred during the control file delete if (fileTmp.exists()) @@ -2951,7 +2951,7 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal for (String fileToDelete : leftFiles) { ActiveMQJournalLogger.LOGGER.deletingOrphanedFile(fileToDelete); - SequentialFile file = fileFactory.createSequentialFile(fileToDelete, 1); + SequentialFile file = fileFactory.createSequentialFile(fileToDelete); file.delete(); } } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/SyncSpeedTest.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/SyncSpeedTest.java deleted file mode 100644 index 0c982dc917..0000000000 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/SyncSpeedTest.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.activemq.artemis.core.journal.impl; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; - -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.journal.ActiveMQJournalLogger; - -/** - * A SyncSpeedTest - * - * This class just provides some diagnostics on how fast your disk can sync - * Useful when determining performance issues - */ -public class SyncSpeedTest -{ - public static void main(final String[] args) - { - try - { - new SyncSpeedTest().testScaleAIO(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - protected SequentialFileFactory fileFactory; - - public boolean AIO = true; - - protected void setupFactory() - { - if (AIO) - { - fileFactory = new AIOSequentialFileFactory(new File("."), 0, 0, false, null); - } - else - { - fileFactory = new NIOSequentialFileFactory(new File("."), false, 0, 0, false, null); - } - } - - protected SequentialFile createSequentialFile(final String fileName) - { - if (AIO) - { - return new AIOSequentialFile(fileFactory, - 0, - 0, - new File("."), - fileName, - 100000, - null, - null, - Executors.newSingleThreadExecutor()); - } - else - { - return new NIOSequentialFile(fileFactory, new File("."), fileName, 1000, null); - } - } - - public void run2() throws Exception - { - setupFactory(); - - int recordSize = 128 * 1024; - - while (true) - { - System.out.println("** record size is " + recordSize); - - int warmup = 500; - - int its = 500; - - int fileSize = (its + warmup) * recordSize; - - SequentialFile file = createSequentialFile("sync-speed-test.dat"); - - if (file.exists()) - { - file.delete(); - } - - file.open(); - - file.fill(0, fileSize, (byte)'X'); - - if (!AIO) - { - file.sync(); - } - - ByteBuffer bb1 = generateBuffer(recordSize, (byte)'h'); - - long start = 0; - - for (int i = 0; i < its + warmup; i++) - { - if (i == warmup) - { - start = System.currentTimeMillis(); - } - - bb1.rewind(); - - file.writeDirect(bb1, true); - } - - long end = System.currentTimeMillis(); - - double rate = 1000 * (double)its / (end - start); - - double throughput = recordSize * rate; - - System.out.println("Rate of " + rate + " syncs per sec"); - System.out.println("Throughput " + throughput + " bytes per sec"); - System.out.println("*************"); - - recordSize *= 2; - } - } - - public void run() throws Exception - { - int recordSize = 256; - - while (true) - { - System.out.println("** record size is " + recordSize); - - int warmup = 500; - - int its = 500; - - int fileSize = (its + warmup) * recordSize; - - File file = new File("sync-speed-test.dat"); - - if (file.exists()) - { - if (!file.delete()) - { - ActiveMQJournalLogger.LOGGER.errorDeletingFile(file); - } - } - - boolean created = file.createNewFile(); - if (!created) - throw new IOException("could not create file " + file); - - RandomAccessFile rfile = new RandomAccessFile(file, "rw"); - - FileChannel channel = rfile.getChannel(); - - ByteBuffer bb = generateBuffer(fileSize, (byte)'x'); - - write(bb, channel, fileSize); - - channel.force(true); - - channel.position(0); - - ByteBuffer bb1 = generateBuffer(recordSize, (byte)'h'); - - long start = 0; - - for (int i = 0; i < its + warmup; i++) - { - if (i == warmup) - { - start = System.currentTimeMillis(); - } - - bb1.flip(); - channel.write(bb1); - channel.force(false); - } - - long end = System.currentTimeMillis(); - - double rate = 1000 * (double)its / (end - start); - - double throughput = recordSize * rate; - - System.out.println("Rate of " + rate + " syncs per sec"); - System.out.println("Throughput " + throughput + " bytes per sec"); - - recordSize *= 2; - } - } - - public void testScaleAIO() throws Exception - { - setupFactory(); - - final int recordSize = 1024; - - System.out.println("** record size is " + recordSize); - - final int its = 10; - - for (int numThreads = 1; numThreads <= 10; numThreads++) - { - - int fileSize = its * recordSize * numThreads; - - final SequentialFile file = createSequentialFile("sync-speed-test.dat"); - - if (file.exists()) - { - file.delete(); - } - - file.open(); - - file.fill(0, fileSize, (byte)'X'); - - if (!AIO) - { - file.sync(); - } - - final CountDownLatch latch = new CountDownLatch(its * numThreads); - - class MyIOAsyncTask implements IOAsyncTask - { - public void done() - { - latch.countDown(); - } - - public void onError(final int errorCode, final String errorMessage) - { - - } - } - - final MyIOAsyncTask task = new MyIOAsyncTask(); - - class MyRunner implements Runnable - { - private final ByteBuffer bb1; - - MyRunner() - { - bb1 = generateBuffer(recordSize, (byte)'h'); - } - - public void run() - { - for (int i = 0; i < its; i++) - { - bb1.rewind(); - - file.writeDirect(bb1, true, task); - // try - // { - // file.writeDirect(bb1, true); - // } - // catch (Exception e) - // { - // e.printStackTrace(); - // } - } - } - } - - Set threads = new HashSet(); - - for (int i = 0; i < numThreads; i++) - { - MyRunner runner = new MyRunner(); - - Thread t = new Thread(runner); - - threads.add(t); - } - - long start = System.currentTimeMillis(); - - for (Thread t : threads) - { - ActiveMQJournalLogger.LOGGER.startingThread(); - t.start(); - } - - for (Thread t : threads) - { - t.join(); - } - - latch.await(); - - long end = System.currentTimeMillis(); - - double rate = 1000 * (double)its * numThreads / (end - start); - - double throughput = recordSize * rate; - - System.out.println("For " + numThreads + " threads:"); - System.out.println("Rate of " + rate + " records per sec"); - System.out.println("Throughput " + throughput + " bytes per sec"); - System.out.println("*************"); - } - } - - private void write(final ByteBuffer buffer, final FileChannel channel, final int size) throws Exception - { - buffer.flip(); - - channel.write(buffer); - } - - private ByteBuffer generateBuffer(final int size, final byte ch) - { - ByteBuffer bb = ByteBuffer.allocateDirect(size); - - for (int i = 0; i < size; i++) - { - bb.put(ch); - } - - return bb; - } -} \ No newline at end of file diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TransactionCallback.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TransactionCallback.java index 403520252a..140927e007 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TransactionCallback.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/TransactionCallback.java @@ -18,10 +18,10 @@ package org.apache.activemq.artemis.core.journal.impl; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.utils.ReusableLatch; -public class TransactionCallback implements IOAsyncTask +public class TransactionCallback implements IOCallback { private final ReusableLatch countLatch = new ReusableLatch(); @@ -33,7 +33,7 @@ public class TransactionCallback implements IOAsyncTask private int done = 0; - private volatile IOAsyncTask delegateCompletion; + private volatile IOCallback delegateCompletion; public void countUp() { @@ -46,7 +46,7 @@ public class TransactionCallback implements IOAsyncTask countLatch.countDown(); if (++done == up.get() && delegateCompletion != null) { - final IOAsyncTask delegateToCall = delegateCompletion; + final IOCallback delegateToCall = delegateCompletion; // We need to set the delegateCompletion to null first or blocking commits could miss a callback // What would affect mainly tests delegateCompletion = null; @@ -81,7 +81,7 @@ public class TransactionCallback implements IOAsyncTask /** * @return the delegateCompletion */ - public IOAsyncTask getDelegateCompletion() + public IOCallback getDelegateCompletion() { return delegateCompletion; } @@ -89,7 +89,7 @@ public class TransactionCallback implements IOAsyncTask /** * @param delegateCompletion the delegateCompletion to set */ - public void setDelegateCompletion(final IOAsyncTask delegateCompletion) + public void setDelegateCompletion(final IOCallback delegateCompletion) { this.delegateCompletion = delegateCompletion; } diff --git a/artemis-journal/src/test/java/org/apache/activemq/artemis/core/io/aio/CallbackOrderTest.java b/artemis-journal/src/test/java/org/apache/activemq/artemis/core/io/aio/CallbackOrderTest.java new file mode 100644 index 0000000000..82d45024a3 --- /dev/null +++ b/artemis-journal/src/test/java/org/apache/activemq/artemis/core/io/aio/CallbackOrderTest.java @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.core.io.aio; + +import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.activemq.artemis.core.io.IOCallback; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +/** This will emulate callbacks out of order from libaio*/ +public class CallbackOrderTest +{ + + @Rule + public TemporaryFolder temporaryFolder; + + public CallbackOrderTest() + { + File parent = new File("./target"); + parent.mkdirs(); + temporaryFolder = new TemporaryFolder(parent); + } + + /** This method will make sure callbacks will come back in order even when out order from libaio */ + @Test + public void testCallbackOutOfOrder() throws Exception + { + AIOSequentialFileFactory factory = new AIOSequentialFileFactory(temporaryFolder.getRoot(), 100); + AIOSequentialFile file = (AIOSequentialFile)factory.createSequentialFile("test.bin"); + + final AtomicInteger count = new AtomicInteger(0); + + IOCallback callback = new IOCallback() + { + @Override + public void done() + { + count.incrementAndGet(); + } + + @Override + public void onError(int errorCode, String errorMessage) + { + + } + }; + + ArrayList list = new ArrayList<>(); + + // We will repeat the teset a few times, increasing N + // to increase possibility of issues due to reuse of callbacks + for (int n = 1; n < 100; n++) + { + System.out.println("n = " + n); + int N = n; + count.set(0); + list.clear(); + for (int i = 0; i < N; i++) + { + list.add(file.getCallback(callback, null)); + } + + + for (int i = N - 1; i >= 0; i--) + { + list.get(i).done(); + } + + Assert.assertEquals(N, count.get()); + Assert.assertEquals(0, file.pendingCallbackList.size()); + Assert.assertTrue(file.pendingCallbackList.isEmpty()); + } + + factory.stop(); + + } +} diff --git a/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ActiveMQCreatePlugin.java b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ActiveMQCreatePlugin.java index 78154b68e6..bae871eba7 100644 --- a/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ActiveMQCreatePlugin.java +++ b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ActiveMQCreatePlugin.java @@ -250,6 +250,7 @@ public class ActiveMQCreatePlugin extends AbstractMojo add(listCommands, "--failover-on-shutdown"); } + add(listCommands, "--no-sync-test"); add(listCommands, "--verbose"); add(listCommands, instance.getAbsolutePath()); diff --git a/artemis-native/bin/libartemis-native-32.so b/artemis-native/bin/libartemis-native-32.so index 71780694e3..df4b560391 100755 Binary files a/artemis-native/bin/libartemis-native-32.so and b/artemis-native/bin/libartemis-native-32.so differ diff --git a/artemis-native/bin/libartemis-native-64.so b/artemis-native/bin/libartemis-native-64.so index 1c4983c9d3..aec757ab4c 100755 Binary files a/artemis-native/bin/libartemis-native-64.so and b/artemis-native/bin/libartemis-native-64.so differ diff --git a/artemis-native/pom.xml b/artemis-native/pom.xml index abd5f0de79..0206166721 100644 --- a/artemis-native/pom.xml +++ b/artemis-native/pom.xml @@ -32,6 +32,30 @@ artemis-commons ${project.version} + + + org.jboss.logging + jboss-logging-processor + provided + true + + + + org.jboss.logging + jboss-logging + + + org.jboss.logmanager + jboss-logmanager + test + + + + junit + junit + test + + diff --git a/artemis-native/src/main/c/AIOController.cpp b/artemis-native/src/main/c/AIOController.cpp deleted file mode 100644 index a61bf04e27..0000000000 --- a/artemis-native/src/main/c/AIOController.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - - -#include -#include "AIOController.h" -#include "JavaUtilities.h" -#include "JAIODatatypes.h" - -AIOController::AIOController(std::string fileName, int maxIO) : logger(0), fileOutput(fileName, this, maxIO) -{ -} - -void AIOController::log(THREAD_CONTEXT threadContext, short level, const char * message) -{ - jmethodID methodID = 0; - - switch (level) - { - case 0: methodID = loggerError; break; - case 1: methodID = loggerWarn; break; - case 2: methodID = loggerInfo; break; - case 3: methodID = loggerDebug; break; - default: methodID = loggerDebug; break; - } - -#ifdef DEBUG - fprintf (stderr,"Callig log methodID=%ld, message=%s, logger=%ld, threadContext = %ld\n", (long) methodID, message, (long) logger, (long) threadContext); fflush(stderr); -#endif - threadContext->CallVoidMethod(logger,methodID,threadContext->NewStringUTF(message)); -} - - -void AIOController::destroy(THREAD_CONTEXT context) -{ - if (logger != 0) - { - context->DeleteGlobalRef(logger); - } -} - -/* - * level = 0-error, 1-warn, 2-info, 3-debug - */ - - -AIOController::~AIOController() -{ -} diff --git a/artemis-native/src/main/c/AIOController.h b/artemis-native/src/main/c/AIOController.h deleted file mode 100644 index 913565f33f..0000000000 --- a/artemis-native/src/main/c/AIOController.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - - -#ifndef AIOCONTROLLER_H_ -#define AIOCONTROLLER_H_ -#include -#include -#include "JAIODatatypes.h" -#include "AsyncFile.h" - -class AIOController -{ -public: - jmethodID done; - jmethodID error; - - jobject logger; - - jmethodID loggerError; - jmethodID loggerWarn; - jmethodID loggerDebug; - jmethodID loggerInfo; - - /* - * level = 0-error, 1-warn, 2-info, 3-debug - */ - void log(THREAD_CONTEXT threadContext, short level, const char * message); - - AsyncFile fileOutput; - - void destroy(THREAD_CONTEXT context); - - AIOController(std::string fileName, int maxIO); - virtual ~AIOController(); -}; -#endif /*AIOCONTROLLER_H_*/ diff --git a/artemis-native/src/main/c/AIOException.h b/artemis-native/src/main/c/AIOException.h deleted file mode 100644 index 98745a2feb..0000000000 --- a/artemis-native/src/main/c/AIOException.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - - - -#ifndef AIOEXCEPTION_H_ -#define AIOEXCEPTION_H_ - -#include -#include - - -#define NATIVE_ERROR_INTERNAL 200 -#define NATIVE_ERROR_INVALID_BUFFER 201 -#define NATIVE_ERROR_NOT_ALIGNED 202 -#define NATIVE_ERROR_CANT_INITIALIZE_AIO 203 -#define NATIVE_ERROR_CANT_RELEASE_AIO 204 -#define NATIVE_ERROR_CANT_OPEN_CLOSE_FILE 205 -#define NATIVE_ERROR_CANT_ALLOCATE_QUEUE 206 -#define NATIVE_ERROR_PREALLOCATE_FILE 208 -#define NATIVE_ERROR_ALLOCATE_MEMORY 209 -#define NATIVE_ERROR_IO 006 -#define NATIVE_ERROR_AIO_FULL 211 - - -class AIOException : public std::exception -{ -private: - int errorCode; - std::string message; -public: - AIOException(int _errorCode, std::string _message) throw() : errorCode(_errorCode), message(_message) - { - errorCode = _errorCode; - message = _message; - } - - AIOException(int _errorCode, const char * _message) throw () - { - message = std::string(_message); - errorCode = _errorCode; - } - - virtual ~AIOException() throw() - { - - } - - int inline getErrorCode() - { - return errorCode; - } - - const char* what() const throw() - { - return message.data(); - } - -}; - -#endif /*AIOEXCEPTION_H_*/ diff --git a/artemis-native/src/main/c/AsyncFile.cpp b/artemis-native/src/main/c/AsyncFile.cpp deleted file mode 100644 index 2385a0d506..0000000000 --- a/artemis-native/src/main/c/AsyncFile.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "AsyncFile.h" -#include "AIOController.h" -#include "AIOException.h" -#include "pthread.h" -#include "LockClass.h" -#include "CallbackAdapter.h" -#include "LockClass.h" - -//#define DEBUG - -#define WAIT_FOR_SPOT 10000 -#define TRIES_BEFORE_WARN 0 -#define TRIES_BEFORE_ERROR 500 - - -std::string io_error(int rc) -{ - std::stringstream buffer; - - if (rc == -ENOSYS) - buffer << "AIO not in this kernel"; - else - buffer << "Error:= " << strerror((int)-rc); - - return buffer.str(); -} - - -AsyncFile::AsyncFile(std::string & _fileName, AIOController * _controller, int _maxIO) : aioContext(0), events(0), fileHandle(0), controller(_controller), pollerRunning(0) -{ - ::pthread_mutex_init(&fileMutex,0); - ::pthread_mutex_init(&pollerMutex,0); - - maxIO = _maxIO; - fileName = _fileName; - if (io_queue_init(maxIO, &aioContext)) - { - throw AIOException(NATIVE_ERROR_CANT_INITIALIZE_AIO, "Can't initialize aio, out of AIO Handlers"); - } - - fileHandle = ::open(fileName.data(), O_RDWR | O_CREAT | O_DIRECT, 0666); - if (fileHandle < 0) - { - io_queue_release(aioContext); - throw AIOException(NATIVE_ERROR_CANT_OPEN_CLOSE_FILE, "Can't open file"); - } - -#ifdef DEBUG - fprintf (stderr,"File Handle %d", fileHandle); -#endif - - events = (struct io_event *)malloc (maxIO * sizeof (struct io_event)); - - if (events == 0) - { - throw AIOException (NATIVE_ERROR_CANT_ALLOCATE_QUEUE, "Can't allocate ioEvents"); - } - -} - -AsyncFile::~AsyncFile() -{ - if (io_queue_release(aioContext)) - { - throw AIOException(NATIVE_ERROR_CANT_RELEASE_AIO,"Can't release aio"); - } - if (::close(fileHandle)) - { - throw AIOException(NATIVE_ERROR_CANT_OPEN_CLOSE_FILE,"Can't close file"); - } - free(events); - ::pthread_mutex_destroy(&fileMutex); - ::pthread_mutex_destroy(&pollerMutex); -} - -int isException (THREAD_CONTEXT threadContext) -{ - return JNI_ENV(threadContext)->ExceptionOccurred() != 0; -} - -void AsyncFile::pollEvents(THREAD_CONTEXT threadContext) -{ - - LockClass lock(&pollerMutex); - pollerRunning=1; - - - while (pollerRunning) - { - if (isException(threadContext)) - { - return; - } - int result = io_getevents(this->aioContext, 1, maxIO, events, 0); - - -#ifdef DEBUG - fprintf (stderr, "poll, pollerRunning=%d\n", pollerRunning); fflush(stderr); -#endif - - if (result > 0) - { - -#ifdef DEBUG - fprintf (stdout, "Received %d events\n", result); - fflush(stdout); -#endif - } - - for (int i=0; idata == (void *) -1) - { - pollerRunning = 0; -#ifdef DEBUG - controller->log(threadContext, 2, "Received poller request to stop"); -#endif - } - else - { - CallbackAdapter * adapter = (CallbackAdapter *) iocbp->data; - - long result = events[i].res; - if (result < 0) - { - std::string strerror = io_error((int)result); - adapter->onError(threadContext, result, strerror); - } - else - { - adapter->done(threadContext); - } - } - - delete iocbp; - } - } -#ifdef DEBUG - controller->log(threadContext, 2, "Poller finished execution"); -#endif -} - - -void AsyncFile::preAllocate(THREAD_CONTEXT , off_t position, int blocks, size_t size, int fillChar) -{ - - if (size % ALIGNMENT != 0) - { - throw AIOException (NATIVE_ERROR_PREALLOCATE_FILE, "You can only pre allocate files in multiples of 512"); - } - - void * preAllocBuffer = 0; - if (posix_memalign(&preAllocBuffer, 512, size)) - { - throw AIOException(NATIVE_ERROR_ALLOCATE_MEMORY, "Error on posix_memalign"); - } - - memset(preAllocBuffer, fillChar, size); - - - if (::lseek (fileHandle, position, SEEK_SET) < 0) throw AIOException (11, "Error positioning the file"); - - for (int i=0; idata = (void *) adapter; - - int tries = 0; - int result = 0; - - while ((result = ::io_submit(aioContext, 1, &iocb)) == (-EAGAIN)) - { -#ifdef DEBUG - fprintf (stderr, "Retrying block as iocb was full (retry=%d)\n", tries); -#endif - tries ++; - if (tries > TRIES_BEFORE_WARN) - { -#ifdef DEBUG - fprintf (stderr, "Warning level on retries, informing logger (retry=%d)\n", tries); -#endif - controller->log(threadContext, 1, "You should consider expanding AIOLimit if this message appears too many times"); - } - - if (tries > TRIES_BEFORE_ERROR) - { -#ifdef DEBUG - fprintf (stderr, "Error level on retries, throwing exception (retry=%d)\n", tries); -#endif - throw AIOException(NATIVE_ERROR_AIO_FULL, "Too many retries (500) waiting for a valid iocb block, please increase MAX_IO limit"); - } - ::usleep(WAIT_FOR_SPOT); - } - - if (result<0) - { - std::stringstream str; - str<< "Problem on submit block, errorCode=" << result; - throw AIOException (NATIVE_ERROR_IO, str.str()); - } -} - -void AsyncFile::read(THREAD_CONTEXT threadContext, long position, size_t size, void *& buffer, CallbackAdapter *& adapter) -{ - - struct iocb * iocb = new struct iocb(); - ::io_prep_pread(iocb, fileHandle, buffer, size, position); - iocb->data = (void *) adapter; - - int tries = 0; - int result = 0; - - while ((result = ::io_submit(aioContext, 1, &iocb)) == (-EAGAIN)) - { -#ifdef DEBUG - fprintf (stderr, "Retrying block as iocb was full (retry=%d)\n", tries); -#endif - tries ++; - if (tries > TRIES_BEFORE_WARN) - { -#ifdef DEBUG - fprintf (stderr, "Warning level on retries, informing logger (retry=%d)\n", tries); -#endif - controller->log(threadContext, 1, "You should consider expanding AIOLimit if this message appears too many times"); - } - - if (tries > TRIES_BEFORE_ERROR) - { -#ifdef DEBUG - fprintf (stderr, "Error level on retries, throwing exception (retry=%d)\n", tries); -#endif - throw AIOException(NATIVE_ERROR_AIO_FULL, "Too many retries (500) waiting for a valid iocb block, please increase MAX_IO limit"); - } - ::usleep(WAIT_FOR_SPOT); - } - - if (result<0) - { - std::stringstream str; - str<< "Problem on submit block, errorCode=" << result; - throw AIOException (NATIVE_ERROR_IO, str.str()); - } -} - -long AsyncFile::getSize() -{ - struct stat statBuffer; - - if (fstat(fileHandle, &statBuffer) < 0) - { - return -1l; - } - return statBuffer.st_size; -} - - -void AsyncFile::stopPoller(THREAD_CONTEXT threadContext) -{ - pollerRunning = 0; - - - struct iocb * iocb = new struct iocb(); - ::io_prep_pwrite(iocb, fileHandle, 0, 0, 0); - iocb->data = (void *) -1; - - int result = 0; - - while ((result = ::io_submit(aioContext, 1, &iocb)) == (-EAGAIN)) - { - fprintf(stderr, "Couldn't send request to stop poller, trying again"); - controller->log(threadContext, 1, "Couldn't send request to stop poller, trying again"); - ::usleep(WAIT_FOR_SPOT); - } - - // Waiting the Poller to finish (by giving up the lock) - LockClass lock(&pollerMutex); -} - diff --git a/artemis-native/src/main/c/AsyncFile.h b/artemis-native/src/main/c/AsyncFile.h deleted file mode 100644 index 71281c9f08..0000000000 --- a/artemis-native/src/main/c/AsyncFile.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef FILEOUTPUT_H_ -#define FILEOUTPUT_H_ - -#include -#include -#include -#include -#include "JAIODatatypes.h" -#include "AIOException.h" - -class AIOController; - -class CallbackAdapter; - -/** Author: Clebert Suconic at Redhat dot com*/ -class AsyncFile -{ -private: - io_context_t aioContext; - struct io_event *events; - int fileHandle; - std::string fileName; - - pthread_mutex_t fileMutex; - pthread_mutex_t pollerMutex; - - AIOController * controller; - - bool pollerRunning; - - int maxIO; - -public: - AsyncFile(std::string & _fileName, AIOController * controller, int maxIO); - virtual ~AsyncFile(); - - void write(THREAD_CONTEXT threadContext, long position, size_t size, void *& buffer, CallbackAdapter *& adapter); - - /** Write directly to the file without using libaio queue */ - void writeInternal(THREAD_CONTEXT threadContext, long position, size_t size, void *& buffer); - - void read(THREAD_CONTEXT threadContext, long position, size_t size, void *& buffer, CallbackAdapter *& adapter); - - int getHandle() - { - return fileHandle; - } - - long getSize(); - - inline void * newBuffer(int size) - { - void * buffer = 0; - if (::posix_memalign(&buffer, 512, size)) - { - throw AIOException(NATIVE_ERROR_ALLOCATE_MEMORY, "Error on posix_memalign"); - } - return buffer; - - } - - inline void destroyBuffer(void * buffer) - { - ::free(buffer); - } - - - // Finishes the polling thread (if any) and return - void stopPoller(THREAD_CONTEXT threadContext); - void preAllocate(THREAD_CONTEXT threadContext, off_t position, int blocks, size_t size, int fillChar); - - void pollEvents(THREAD_CONTEXT threadContext); - -}; - -#endif /*FILEOUTPUT_H_*/ diff --git a/artemis-native/src/main/c/CMakeLists.txt b/artemis-native/src/main/c/CMakeLists.txt index 0a45fd6870..beef8da8ae 100644 --- a/artemis-native/src/main/c/CMakeLists.txt +++ b/artemis-native/src/main/c/CMakeLists.txt @@ -30,35 +30,21 @@ endif() # you may want to remove this next line for debugging # -O3 would make inline debug hard +#ADD_DEFINITIONS("-O3 -Wall -z execstack") ADD_DEFINITIONS("-O3 -Wall") -#ADD_DEFINITIONS("-fdump-tree-all -Wall -pg -g -mstack-protector-guard=guard") +#ADD_DEFINITIONS("-fdump-tree-all -Wall -pg -g") find_library(LIBAIO NAMES aio) INCLUDE_DIRECTORIES(. ${JNI_INCLUDE_DIRS}) ADD_CUSTOM_COMMAND( - OUTPUT org_apache_activemq_artemis_core_libaio_Native.h - COMMAND javah -cp ../java/ org.apache.activemq.artemis.core.libaio.Native - DEPENDS ../java/org/apache/activemq/artemis/core/libaio/Native.java + OUTPUT org_apache_activemq_artemis_jlibaio_LibaioContext.h + COMMAND javah -cp ../java/ org.apache.activemq.artemis.jlibaio.LibaioContext + DEPENDS ../java/org/apache/activemq/artemis/jlibaio/LibaioContext.java ) -ADD_LIBRARY(artemis-native SHARED - AIOController.cpp - AIOController.h - AIOException.h - AsyncFile.cpp - AsyncFile.h - CallbackAdapter.h - JAIODatatypes.h - JavaUtilities.cpp - JavaUtilities.h - JNI_AsynchronousFileImpl.cpp - JNICallbackAdapter.cpp - JNICallbackAdapter.h - LockClass.h - Version.h - org_apache_activemq_artemis_core_libaio_Native.h) +ADD_LIBRARY(artemis-native SHARED org_apache_activemq_artemis_jlibaio_LibaioContext.c org_apache_activemq_artemis_jlibaio_LibaioContext.h exception_helper.h) target_link_libraries(artemis-native aio) diff --git a/artemis-native/src/main/c/CallbackAdapter.h b/artemis-native/src/main/c/CallbackAdapter.h deleted file mode 100644 index e8b67dadad..0000000000 --- a/artemis-native/src/main/c/CallbackAdapter.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef BUFFERADAPTER_H_ -#define BUFFERADAPTER_H_ - -#include - -#include "JAIODatatypes.h" - -class CallbackAdapter -{ -private: - -public: - CallbackAdapter() - { - - } - virtual ~CallbackAdapter() - { - - } - - virtual void done(THREAD_CONTEXT ) = 0; - virtual void onError(THREAD_CONTEXT , long , std::string )=0; -}; -#endif /*BUFFERADAPTER_H_*/ diff --git a/artemis-native/src/main/c/JAIODatatypes.h b/artemis-native/src/main/c/JAIODatatypes.h deleted file mode 100644 index b611c2ba1e..0000000000 --- a/artemis-native/src/main/c/JAIODatatypes.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef JAIODATATYPES_H_ -#define JAIODATATYPES_H_ - -#include - -#define THREAD_CONTEXT JNIEnv *& -#define JNI_ENV(pointer) pointer -#define ALIGNMENT 512 - - -#endif /*JAIODATATYPES_H_*/ diff --git a/artemis-native/src/main/c/JNICallbackAdapter.cpp b/artemis-native/src/main/c/JNICallbackAdapter.cpp deleted file mode 100644 index 0f4cef4c10..0000000000 --- a/artemis-native/src/main/c/JNICallbackAdapter.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#include -#include "JNICallbackAdapter.h" -#include -#include "JavaUtilities.h" - -jobject nullObj = NULL; - -JNICallbackAdapter::JNICallbackAdapter(AIOController * _controller, jlong _sequence, jobject _callback, jobject _fileController, jobject _bufferReference, short _isRead) : CallbackAdapter() -{ - controller = _controller; - - sequence = _sequence; - - callback = _callback; - - fileController = _fileController; - - bufferReference = _bufferReference; - - isRead = _isRead; - -} - -JNICallbackAdapter::~JNICallbackAdapter() -{ -} - -void JNICallbackAdapter::done(THREAD_CONTEXT threadContext) -{ - JNI_ENV(threadContext)->CallVoidMethod(fileController, controller->done, callback, sequence, isRead ? nullObj : bufferReference); - - release(threadContext); -} - -void JNICallbackAdapter::onError(THREAD_CONTEXT threadContext, long errorCode, std::string error) -{ - controller->log(threadContext, 0, "Libaio event generated errors, callback object was informed about it"); - - jstring strError = JNI_ENV(threadContext)->NewStringUTF(error.data()); - - JNI_ENV(threadContext)->CallVoidMethod(fileController, controller->error, callback, sequence, isRead ? nullObj : bufferReference, (jint)errorCode, strError); - - release(threadContext); -} - diff --git a/artemis-native/src/main/c/JNICallbackAdapter.h b/artemis-native/src/main/c/JNICallbackAdapter.h deleted file mode 100644 index 5d326209c0..0000000000 --- a/artemis-native/src/main/c/JNICallbackAdapter.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef JNIBUFFERADAPTER_H_ -#define JNIBUFFERADAPTER_H_ - -#include - -#include "CallbackAdapter.h" -#include "AIOController.h" -#include "JAIODatatypes.h" - - -class JNICallbackAdapter : public CallbackAdapter -{ -private: - - AIOController * controller; - - jobject callback; - - jobject fileController; - - jobject bufferReference; - - jlong sequence; - - // Is this a read operation - short isRead; - - void release(THREAD_CONTEXT threadContext) - { - JNI_ENV(threadContext)->DeleteGlobalRef(callback); - JNI_ENV(threadContext)->DeleteGlobalRef(fileController); - JNI_ENV(threadContext)->DeleteGlobalRef(bufferReference); - delete this; - return; - } - - -public: - // _ob must be a global Reference (use createGloblReferente before calling the constructor) - JNICallbackAdapter(AIOController * _controller, jlong sequence, jobject _callback, jobject _fileController, jobject _bufferReference, short _isRead); - virtual ~JNICallbackAdapter(); - - void done(THREAD_CONTEXT threadContext); - - void onError(THREAD_CONTEXT , long , std::string ); - - -}; -#endif /*JNIBUFFERADAPTER_H_*/ diff --git a/artemis-native/src/main/c/JNI_AsynchronousFileImpl.cpp b/artemis-native/src/main/c/JNI_AsynchronousFileImpl.cpp deleted file mode 100644 index 0334a7c0a2..0000000000 --- a/artemis-native/src/main/c/JNI_AsynchronousFileImpl.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "org_apache_activemq_artemis_core_libaio_Native.h" - - -#include "JavaUtilities.h" -#include "AIOController.h" -#include "JNICallbackAdapter.h" -#include "AIOException.h" -#include "Version.h" - - -// This value is set here globally, to avoid passing stuff on stack between java and the native layer on every sleep call -struct timespec nanoTime; - -inline AIOController * getController(JNIEnv *env, jobject & controllerAddress) -{ - return (AIOController *) env->GetDirectBufferAddress(controllerAddress); -} - -/* Inaccessible static: log */ -/* Inaccessible static: totalMaxIO */ -/* Inaccessible static: loaded */ -/* Inaccessible static: EXPECTED_NATIVE_VERSION */ -/* - * Class: org.apache.activemq.artemis_core_asyncio_impl_AsynchronousFileImpl - * Method: openFile - * Signature: (Ljava/lang/String;)I - */ -JNIEXPORT jint JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_openFile - (JNIEnv * env , jclass , jstring jstrFileName) -{ - std::string fileName = convertJavaString(env, jstrFileName); - - return open(fileName.data(), O_RDWR | O_CREAT, 0666); -} - -/* - * Class: org.apache.activemq.artemis_core_asyncio_impl_AsynchronousFileImpl - * Method: closeFile - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_closeFile - (JNIEnv * , jclass , jint handle) -{ - close(handle); -} - -/* - * Class: org.apache.activemq.artemis_core_asyncio_impl_AsynchronousFileImpl - * Method: flock - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_flock - (JNIEnv * , jclass , jint handle) -{ - return flock(handle, LOCK_EX | LOCK_NB) == 0; -} - - - -/* - * Class: org_jboss_jaio_libaioimpl_LibAIOController - * Method: init - * Signature: (Ljava/lang/String;Ljava/lang/Class;)J - */ -JNIEXPORT jobject JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_init - (JNIEnv * env, jclass, jclass controllerClazz, jstring jstrFileName, jint maxIO, jobject logger) -{ - AIOController * controller = 0; - try - { - std::string fileName = convertJavaString(env, jstrFileName); - - controller = new AIOController(fileName, (int) maxIO); - controller->done = env->GetMethodID(controllerClazz,"callbackDone","(Lorg/apache/activemq/artemis/core/asyncio/AIOCallback;JLjava/nio/ByteBuffer;)V"); - if (!controller->done) - { - throwException (env, -1, "can't get callbackDone method"); - return 0; - } - - controller->error = env->GetMethodID(controllerClazz, "callbackError", "(Lorg/apache/activemq/artemis/core/asyncio/AIOCallback;JLjava/nio/ByteBuffer;ILjava/lang/String;)V"); - if (!controller->done) - { - throwException (env, -1, "can't get callbackError method"); - return 0; - } - - jclass loggerClass = env->GetObjectClass(logger); - - if (!(controller->loggerDebug = env->GetMethodID(loggerClass, "debug", "(Ljava/lang/Object;)V"))) return 0; - if (!(controller->loggerWarn = env->GetMethodID(loggerClass, "warn", "(Ljava/lang/Object;)V"))) return 0; - if (!(controller->loggerInfo = env->GetMethodID(loggerClass, "info", "(Ljava/lang/Object;)V"))) return 0; - if (!(controller->loggerError = env->GetMethodID(loggerClass, "error", "(Ljava/lang/Object;)V"))) return 0; - - controller->logger = env->NewGlobalRef(logger); - - return env->NewDirectByteBuffer(controller, 0); - } - catch (AIOException& e){ - if (controller != 0) - { - delete controller; - } - throwException(env, e.getErrorCode(), e.what()); - return 0; - } -} - -/** -* objThis here is passed as a parameter at the java layer. It used to be a JNI this and now it's a java static method - where the intended reference is now passed as an argument -*/ -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_read - (JNIEnv *env, jclass, jobject objThis, jobject controllerAddress, jlong position, jlong size, jobject jbuffer, jobject callback) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - void * buffer = env->GetDirectBufferAddress(jbuffer); - - if (buffer == 0) - { - throwException(env, NATIVE_ERROR_INVALID_BUFFER, "Invalid Buffer used, libaio requires NativeBuffer instead of Java ByteBuffer"); - return; - } - - if (((long)buffer) % 512) - { - throwException(env, NATIVE_ERROR_NOT_ALIGNED, "Buffer not aligned for use with DMA"); - return; - } - - CallbackAdapter * adapter = new JNICallbackAdapter(controller, -1, env->NewGlobalRef(callback), env->NewGlobalRef(objThis), env->NewGlobalRef(jbuffer), true); - - controller->fileOutput.read(env, position, (size_t)size, buffer, adapter); - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - - -// Fast memset on buffer -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_resetBuffer - (JNIEnv *env, jclass, jobject jbuffer, jint size) -{ - void * buffer = env->GetDirectBufferAddress(jbuffer); - - if (buffer == 0) - { - throwException(env, NATIVE_ERROR_INVALID_BUFFER, "Invalid Buffer used, libaio requires NativeBuffer instead of Java ByteBuffer"); - return; - } - - memset(buffer, 0, (size_t)size); - -} - -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_destroyBuffer - (JNIEnv * env, jclass, jobject jbuffer) -{ - if (jbuffer == 0) - { - throwException(env, NATIVE_ERROR_INVALID_BUFFER, "Null Buffer"); - return; - } - void * buffer = env->GetDirectBufferAddress(jbuffer); - free(buffer); -} - -JNIEXPORT jobject JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_newNativeBuffer - (JNIEnv * env, jclass, jlong size) -{ - try - { - - if (size % ALIGNMENT) - { - throwException(env, NATIVE_ERROR_INVALID_BUFFER, "Buffer size needs to be aligned to 512"); - return 0; - } - - - // This will allocate a buffer, aligned by 512. - // Buffers created here need to be manually destroyed by destroyBuffer, or this would leak on the process heap away of Java's GC managed memory - void * buffer = 0; - if (::posix_memalign(&buffer, 512, size)) - { - throwException(env, NATIVE_ERROR_INTERNAL, "Error on posix_memalign"); - return 0; - } - - memset(buffer, 0, (size_t)size); - - jobject jbuffer = env->NewDirectByteBuffer(buffer, size); - return jbuffer; - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - return 0; - } -} - -/** -* objThis here is passed as a parameter at the java layer. It used to be a JNI this and now it's a java static method - where the intended reference is now passed as an argument -*/ -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_write - (JNIEnv *env, jclass, jobject objThis, jobject controllerAddress, jlong sequence, jlong position, jlong size, jobject jbuffer, jobject callback) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - void * buffer = env->GetDirectBufferAddress(jbuffer); - - if (buffer == 0) - { - throwException(env, NATIVE_ERROR_INVALID_BUFFER, "Invalid Buffer used, libaio requires NativeBuffer instead of Java ByteBuffer"); - return; - } - - - CallbackAdapter * adapter = new JNICallbackAdapter(controller, sequence, env->NewGlobalRef(callback), env->NewGlobalRef(objThis), env->NewGlobalRef(jbuffer), false); - - controller->fileOutput.write(env, position, (size_t)size, buffer, adapter); - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_writeInternal - (JNIEnv * env, jclass, jobject controllerAddress, jlong positionToWrite, jlong size, jobject jbuffer) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - void * buffer = env->GetDirectBufferAddress(jbuffer); - - if (buffer == 0) - { - throwException(env, NATIVE_ERROR_INVALID_BUFFER, "Invalid Buffer used, libaio requires NativeBuffer instead of Java ByteBuffer"); - return; - } - - controller->fileOutput.writeInternal(env, positionToWrite, (size_t)size, buffer); - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - - -JNIEXPORT void Java_org_apache_activemq_artemis_core_libaio_Native_internalPollEvents - (JNIEnv *env, jclass, jobject controllerAddress) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - controller->fileOutput.pollEvents(env); - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_stopPoller - (JNIEnv *env, jclass, jobject controllerAddress) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - controller->fileOutput.stopPoller(env); - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_closeInternal - (JNIEnv *env, jclass, jobject controllerAddress) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - controller->destroy(env); - delete controller; - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - - -JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_fill - (JNIEnv * env, jclass, jobject controllerAddress, jlong position, jint blocks, jlong size, jbyte fillChar) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - - controller->fileOutput.preAllocate(env, position, blocks, size, fillChar); - - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - } -} - - - -/** It does nothing... just return true to make sure it has all the binary dependencies */ -JNIEXPORT jint JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_getNativeVersion - (JNIEnv *, jclass) - -{ - return _VERSION_NATIVE_AIO; -} - - -JNIEXPORT jlong JNICALL Java_org_apache_activemq_artemis_core_libaio_Native_size0 - (JNIEnv * env, jclass, jobject controllerAddress) -{ - try - { - AIOController * controller = getController(env, controllerAddress); - - long size = controller->fileOutput.getSize(); - if (size < 0) - { - throwException(env, NATIVE_ERROR_INTERNAL, "InternalError on Native Layer: method size failed"); - return -1l; - } - return size; - } - catch (AIOException& e) - { - throwException(env, e.getErrorCode(), e.what()); - return -1l; - } - -} diff --git a/artemis-native/src/main/c/JavaUtilities.cpp b/artemis-native/src/main/c/JavaUtilities.cpp deleted file mode 100644 index 10d609924a..0000000000 --- a/artemis-native/src/main/c/JavaUtilities.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#include -#include -#include -#include "JavaUtilities.h" - - -void throwRuntimeException(JNIEnv * env, const char * message) -{ - jclass exceptionClass = env->FindClass("java/lang/RuntimeException"); - env->ThrowNew(exceptionClass,message); - -} - -void throwException(JNIEnv * env, const int code, const char * message) -{ - jclass exceptionClass = env->FindClass("org/apache/activemq/artemis/api/core/ActiveMQException"); - if (exceptionClass==NULL) - { - std::cerr << "Couldn't throw exception message:= " << message << "\n"; - throwRuntimeException (env, "Can't find Exception class"); - return; - } - - jmethodID constructor = env->GetMethodID(exceptionClass, "", "(ILjava/lang/String;)V"); - if (constructor == NULL) - { - std::cerr << "Couldn't find the constructor ***"; - throwRuntimeException (env, "Can't find Constructor for Exception"); - return; - } - - jstring strError = env->NewStringUTF(message); - jthrowable ex = (jthrowable)env->NewObject(exceptionClass, constructor, code, strError); - env->Throw(ex); - -} - -std::string convertJavaString(JNIEnv * env, jstring& jstr) -{ - const char * valueStr = env->GetStringUTFChars(jstr, NULL); - std::string data(valueStr); - env->ReleaseStringUTFChars(jstr, valueStr); - return data; -} - diff --git a/artemis-native/src/main/c/JavaUtilities.h b/artemis-native/src/main/c/JavaUtilities.h deleted file mode 100644 index 53ba870bad..0000000000 --- a/artemis-native/src/main/c/JavaUtilities.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef JAVAUTILITIES_H_ -#define JAVAUTILITIES_H_ -#include -#include - -void throwException(JNIEnv * env, const int code, const char * message); -std::string convertJavaString(JNIEnv * env, jstring& jstr); - -#endif /*JAVAUTILITIES_H_*/ diff --git a/artemis-native/src/main/c/LockClass.h b/artemis-native/src/main/c/LockClass.h deleted file mode 100644 index 52599192ee..0000000000 --- a/artemis-native/src/main/c/LockClass.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef LOCKCLASS_H_ -#define LOCKCLASS_H_ - -#include - -class LockClass -{ -protected: - pthread_mutex_t* _m; -public: - inline LockClass(pthread_mutex_t* m) : _m(m) - { - ::pthread_mutex_lock(_m); - } - inline ~LockClass() - { - ::pthread_mutex_unlock(_m); - } -}; - - -#endif /*LOCKCLASS_H_*/ diff --git a/artemis-native/src/main/c/Version.h b/artemis-native/src/main/c/Version.h deleted file mode 100644 index 5b521b3aed..0000000000 --- a/artemis-native/src/main/c/Version.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -#ifndef _VERSION_NATIVE_AIO - -// This definition needs to match org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl.EXPECTED_NATIVE_VERSION -// Or else the native module won't be loaded because of version mismatches -#define _VERSION_NATIVE_AIO 52 -#endif - diff --git a/artemis-native/src/main/c/exception_helper.h b/artemis-native/src/main/c/exception_helper.h new file mode 100644 index 0000000000..d8c77078f5 --- /dev/null +++ b/artemis-native/src/main/c/exception_helper.h @@ -0,0 +1,23 @@ +/* + * Copyright 2015 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +void throwRuntimeException(JNIEnv* env, char* message); +void throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber); +void throwIOException(JNIEnv* env, char* message); +void throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber); +void throwClosedChannelException(JNIEnv* env); +void throwOutOfMemoryError(JNIEnv* env); +char* exceptionMessage(char* msg, int error); diff --git a/artemis-native/src/main/c/org_apache_activemq_artemis_jlibaio_LibaioContext.c b/artemis-native/src/main/c/org_apache_activemq_artemis_jlibaio_LibaioContext.c new file mode 100644 index 0000000000..b6fcdd3e68 --- /dev/null +++ b/artemis-native/src/main/c/org_apache_activemq_artemis_jlibaio_LibaioContext.c @@ -0,0 +1,710 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +#ifndef _GNU_SOURCE +// libaio, O_DIRECT and other things won't be available without this define +#define _GNU_SOURCE +#endif + +//#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "org_apache_activemq_artemis_jlibaio_LibaioContext.h" +#include "exception_helper.h" + +struct io_control { + io_context_t ioContext; + struct io_event * events; + + jobject thisObject; + + // This is used to make sure we don't return IOCB while something else is using them + // this is to guarantee the submits could be done concurrently with polling + pthread_mutex_t iocbLock; + + pthread_mutex_t pollLock; + + // a resuable pool of iocb + struct iocb ** iocb; + int queueSize; + int iocbPut; + int iocbGet; + int used; +}; + +jclass submitClass = NULL; +jmethodID errorMethod = NULL; +jmethodID doneMethod = NULL; +jmethodID libaioContextDone = NULL; + +jclass libaioContextClass = NULL; +jclass runtimeExceptionClass = NULL; +jclass ioExceptionClass = NULL; + +// util methods +void throwRuntimeException(JNIEnv* env, char* message) { + (*env)->ThrowNew(env, runtimeExceptionClass, message); +} + +void throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) { + char* allocatedMessage = exceptionMessage(message, errorNumber); + (*env)->ThrowNew(env, runtimeExceptionClass, allocatedMessage); + free(allocatedMessage); +} + +void throwIOException(JNIEnv* env, char* message) { + (*env)->ThrowNew(env, ioExceptionClass, message); +} + +void throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) { + char* allocatedMessage = exceptionMessage(message, errorNumber); + (*env)->ThrowNew(env, ioExceptionClass, allocatedMessage); + free(allocatedMessage); +} + +void throwOutOfMemoryError(JNIEnv* env) { + jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); + (*env)->ThrowNew(env, exceptionClass, ""); +} + +/** Notice: every usage of exceptionMessage needs to release the allocated memory for the sequence of char */ +char* exceptionMessage(char* msg, int error) { + if (error < 0) { + // some functions return negative values + // and it's hard to keep track of when to send -error and when not + // this will just take care when things are forgotten + // what would generate a proper error + error = error * -1; + } + //strerror is returning a constant, so no need to free anything coming from strerror + char* err = strerror(error); + char* result = malloc(strlen(msg) + strlen(err) + 1); + strcpy(result, msg); + strcat(result, err); + return result; +} + +jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } else { + jclass localRuntimeExceptionClass = (*env)->FindClass(env, "java/lang/RuntimeException"); + if (localRuntimeExceptionClass == NULL) { + // pending exception... + return JNI_ERR; + } + runtimeExceptionClass = (jclass) (*env)->NewGlobalRef(env, localRuntimeExceptionClass); + if (runtimeExceptionClass == NULL) { + // out-of-memory! + throwOutOfMemoryError(env); + return JNI_ERR; + } + + jclass localIoExceptionClass = (*env)->FindClass(env, "java/io/IOException"); + if (localIoExceptionClass == NULL) { + // pending exception... + return JNI_ERR; + } + ioExceptionClass = (jclass) (*env)->NewGlobalRef(env, localIoExceptionClass); + if (ioExceptionClass == NULL) { + // out-of-memory! + throwOutOfMemoryError(env); + return JNI_ERR; + } + + submitClass = (*env)->FindClass(env, "org/apache/activemq/artemis/jlibaio/SubmitInfo"); + if (submitClass == NULL) { + return JNI_ERR; + } + + submitClass = (jclass)(*env)->NewGlobalRef(env, (jobject)submitClass); + + errorMethod = (*env)->GetMethodID(env, submitClass, "onError", "(ILjava/lang/String;)V"); + if (errorMethod == NULL) { + return JNI_ERR; + } + errorMethod = (jmethodID)(*env)->NewGlobalRef(env, (jobject)(errorMethod)); + + doneMethod = (*env)->GetMethodID(env, submitClass, "done", "()V"); + if (doneMethod == NULL) { + return JNI_ERR; + } + doneMethod = (jmethodID)(*env)->NewGlobalRef(env, (jobject)(doneMethod)); + + libaioContextClass = (*env)->FindClass(env, "org/apache/activemq/artemis/jlibaio/LibaioContext"); + if (libaioContextClass == NULL) { + return JNI_ERR; + } + libaioContextClass = (jclass)(*env)->NewGlobalRef(env, (jobject)libaioContextClass); + + libaioContextDone = (*env)->GetMethodID(env, libaioContextClass, "done", "(Lorg/apache/activemq/artemis/jlibaio/SubmitInfo;)V"); + if (libaioContextDone == NULL) { + return JNI_ERR; + } + libaioContextDone = (jmethodID)(*env)->NewGlobalRef(env, (jobject)libaioContextDone); + + return JNI_VERSION_1_6; + } +} + +void JNI_OnUnload(JavaVM* vm, void* reserved) { + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) { + // Something is wrong but nothing we can do about this :( + return; + } else { + // delete global references so the GC can collect them + if (runtimeExceptionClass != NULL) { + (*env)->DeleteGlobalRef(env, runtimeExceptionClass); + } + if (ioExceptionClass != NULL) { + (*env)->DeleteGlobalRef(env, ioExceptionClass); + } + + // Deleting global refs so their classes can be GCed + if (errorMethod != NULL) { + (*env)->DeleteGlobalRef(env, (jobject)errorMethod); + } + + if (doneMethod != NULL) { + (*env)->DeleteGlobalRef(env, (jobject)doneMethod); + } + + if (submitClass != NULL) { + (*env)->DeleteGlobalRef(env, (jobject)submitClass); + } + + if (libaioContextClass != NULL) { + (*env)->DeleteGlobalRef(env, (jobject)libaioContextClass); + } + + if (libaioContextDone != NULL) { + (*env)->DeleteGlobalRef(env, (jobject)libaioContextDone); + } + } +} + +static inline struct io_control * getIOControl(JNIEnv* env, jobject pointer) { + struct io_control * ioControl = (struct io_control *) (*env)->GetDirectBufferAddress(env, pointer); + if (ioControl == NULL) { + throwRuntimeException(env, "Controller not initialized"); + } + return ioControl; +} + +/** + * remove an iocb from the pool of IOCBs. Returns null if full + */ +static inline struct iocb * getIOCB(struct io_control * control) { + struct iocb * iocb = 0; + + pthread_mutex_lock(&(control->iocbLock)); + + #ifdef DEBUG + fprintf (stdout, "getIOCB::used=%d, queueSize=%d, get=%d, put=%d\n", control->used, control->queueSize, control->iocbGet, control->iocbPut); + #endif + + if (control->used < control->queueSize) { + control->used++; + iocb = control->iocb[control->iocbGet++]; + + if (control->iocbGet >= control->queueSize) { + control->iocbGet = 0; + } + } + + pthread_mutex_unlock(&(control->iocbLock)); + return iocb; +} + +/** + * Put an iocb back on the pool of IOCBs + */ +static inline void putIOCB(struct io_control * control, struct iocb * iocbBack) { + pthread_mutex_lock(&(control->iocbLock)); + + #ifdef DEBUG + fprintf (stdout, "putIOCB::used=%d, queueSize=%d, get=%d, put=%d\n", control->used, control->queueSize, control->iocbGet, control->iocbPut); + #endif + + control->used--; + control->iocb[control->iocbPut++] = iocbBack; + if (control->iocbPut >= control->queueSize) { + control->iocbPut = 0; + } + pthread_mutex_unlock(&(control->iocbLock)); +} + +static inline void * getBuffer(JNIEnv* env, jobject pointer) { + return (*env)->GetDirectBufferAddress(env, pointer); +} + +JNIEXPORT jboolean JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_lock + (JNIEnv * env, jclass clazz, jint handle) { + return flock(handle, LOCK_EX | LOCK_NB) == 0; +} + +/** + * Everything that is allocated here will be freed at deleteContext when the class is unloaded. + */ +JNIEXPORT jobject JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_newContext(JNIEnv* env, jobject thisObject, jint queueSize) { + io_context_t libaioContext; + int i = 0; + + #ifdef DEBUG + fprintf (stdout, "Initializing context\n"); + #endif + + int res = io_queue_init(queueSize, &libaioContext); + if (res) { + // Error, so need to release whatever was done before + free(libaioContext); + + throwRuntimeExceptionErrorNo(env, "Cannot initialize queue:", res); + return NULL; + } + + struct iocb ** iocb = (struct iocb **)malloc((sizeof(struct iocb *) * (size_t)queueSize)); + if (iocb == NULL) { + throwOutOfMemoryError(env); + return NULL; + } + + for (i = 0; i < queueSize; i++) { + iocb[i] = (struct iocb *)malloc(sizeof(struct iocb)); + if (iocb[i] == NULL) { + // it's unlikely this would happen at this point + // for that reason I'm not cleaning up individual IOCBs here + // we could increase support here with a cleanup of any previously allocated iocb + // But I'm afraid of adding not needed complexity here + throwOutOfMemoryError(env); + return NULL; + } + } + + struct io_control * theControl = (struct io_control *) malloc(sizeof(struct io_control)); + if (theControl == NULL) { + throwOutOfMemoryError(env); + return NULL; + } + + res = pthread_mutex_init(&(theControl->iocbLock), 0); + if (res) { + free(theControl); + free(libaioContext); + throwRuntimeExceptionErrorNo(env, "Can't initialize mutext:", res); + return NULL; + } + + res = pthread_mutex_init(&(theControl->pollLock), 0); + if (res) { + free(theControl); + free(libaioContext); + throwRuntimeExceptionErrorNo(env, "Can't initialize mutext:", res); + return NULL; + } + + struct io_event * events = (struct io_event *)malloc(sizeof(struct io_event) * (size_t)queueSize); + + theControl->ioContext = libaioContext; + theControl->events = events; + theControl->iocb = iocb; + theControl->queueSize = queueSize; + theControl->iocbPut = 0; + theControl->iocbGet = 0; + theControl->used = 0; + theControl->thisObject = (*env)->NewGlobalRef(env, thisObject); + + return (*env)->NewDirectByteBuffer(env, theControl, sizeof(struct io_control)); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_deleteContext(JNIEnv* env, jclass clazz, jobject contextPointer) { + int i; + struct io_control * theControl = getIOControl(env, contextPointer); + if (theControl == NULL) { + return; + } + + io_queue_release(theControl->ioContext); + + // to make sure the poll has finished + pthread_mutex_lock(&(theControl->pollLock)); + pthread_mutex_unlock(&(theControl->pollLock)); + + pthread_mutex_destroy(&(theControl->pollLock)); + pthread_mutex_destroy(&(theControl->iocbLock)); + + // Releasing each individual iocb + for (i = 0; i < theControl->queueSize; i++) { + free(theControl->iocb[i]); + } + + (*env)->DeleteGlobalRef(env, theControl->thisObject); + + free(theControl->iocb); + free(theControl->events); + free(theControl); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_close(JNIEnv* env, jclass clazz, jint fd) { + if (close(fd) < 0) { + throwIOExceptionErrorNo(env, "Error closing file:", errno); + } +} + +JNIEXPORT int JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_open(JNIEnv* env, jclass clazz, + jstring path, jboolean direct) { + const char* f_path = (*env)->GetStringUTFChars(env, path, 0); + + int res; + if (direct) { + res = open(f_path, O_RDWR | O_CREAT | O_DIRECT, 0666); + } else { + res = open(f_path, O_RDWR | O_CREAT, 0666); + } + + (*env)->ReleaseStringUTFChars(env, path, f_path); + + if (res < 0) { + throwIOExceptionErrorNo(env, "Cannot open file:", errno); + } + + return res; +} + +static inline void submit(JNIEnv * env, struct io_control * theControl, struct iocb * iocb) { + int result = io_submit(theControl->ioContext, 1, &iocb); + + if (result < 0) { + // Putting the Global Ref and IOCB back in case of a failure + (*env)->DeleteGlobalRef(env, (jobject)iocb->data); + putIOCB(theControl, iocb); + + throwIOExceptionErrorNo(env, "Error while submitting IO: ", -result); + } + + return; +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_submitWrite + (JNIEnv * env, jclass clazz, jint fileHandle, jobject contextPointer, jlong position, jint size, jobject bufferWrite, jobject callback) { + struct io_control * theControl = getIOControl(env, contextPointer); + if (theControl == NULL) { + return; + } + + #ifdef DEBUG + fprintf (stdout, "submitWrite position %ld, size %d\n", position, size); + #endif + + struct iocb * iocb = getIOCB(theControl); + + if (iocb == NULL) { + throwIOException(env, "Not enough space in libaio queue"); + return; + } + + io_prep_pwrite(iocb, fileHandle, getBuffer(env, bufferWrite), (size_t)size, position); + + // The GlobalRef will be deleted when poll is called. this is done so + // the vm wouldn't crash if the Callback passed by the user is GCed between submission + // and callback. + // also as the real intention is to hold the reference until the life cycle is complete + iocb->data = (void *) (*env)->NewGlobalRef(env, callback); + + return submit(env, theControl, iocb); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_submitRead + (JNIEnv * env, jclass clazz, jint fileHandle, jobject contextPointer, jlong position, jint size, jobject bufferRead, jobject callback) { + struct io_control * theControl = getIOControl(env, contextPointer); + if (theControl == NULL) { + return; + } + + struct iocb * iocb = getIOCB(theControl); + + if (iocb == NULL) { + throwIOException(env, "Not enough space in libaio queue"); + return; + } + + io_prep_pread(iocb, fileHandle, getBuffer(env, bufferRead), (size_t)size, position); + + // The GlobalRef will be deleted when poll is called. this is done so + // the vm wouldn't crash if the Callback passed by the user is GCed between submission + // and callback. + // also as the real intention is to hold the reference until the life cycle is complete + iocb->data = (void *) (*env)->NewGlobalRef(env, callback); + + return submit(env, theControl, iocb); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_blockedPoll + (JNIEnv * env, jobject thisObject, jobject contextPointer) { + + #ifdef DEBUG + fprintf (stdout, "Running blockedPoll"); + #endif + + int i; + struct io_control * theControl = getIOControl(env, contextPointer); + if (theControl == NULL) { + return; + } + int max = theControl->queueSize; + pthread_mutex_lock(&(theControl->pollLock)); + + for (;;) { + + int result = io_getevents(theControl->ioContext, 1, max, theControl->events, 0); + + if (result < 0) + { + #ifdef DEBUG + fprintf (stdout, "finished blockedPoll rutine with result=%d\n", result); + #endif + break; + } + #ifdef DEBUG + fprintf (stdout, "blockedPoll returned %d events\n", result); + #endif + + for (i = 0; i < result; i++) + { + #ifdef DEBUG + fprintf (stdout, "blockedPoll treading event %d\n", i); + #endif + struct io_event * event = &(theControl->events[i]); + struct iocb * iocbp = event->obj; + int eventResult = (int)event->res; + + #ifdef DEBUG + fprintf (stdout, "Poll res: %d totalRes=%d\n", eventResult, result); + #endif + + if (eventResult < 0) { + #ifdef DEBUG + fprintf (stdout, "Error: %s\n", strerror(-eventResult)); + #endif + + jstring jstrError = (*env)->NewStringUTF(env, strerror(-eventResult)); + + if (iocbp->data != NULL) { + (*env)->CallVoidMethod(env, (jobject)(iocbp->data), errorMethod, (jint)(-eventResult), jstrError); + } + } + + jobject obj = (jobject)iocbp->data; + putIOCB(theControl, iocbp); + + if (obj != NULL) { + (*env)->CallVoidMethod(env, theControl->thisObject, libaioContextDone,obj); + // We delete the globalRef after the completion of the callback + (*env)->DeleteGlobalRef(env, obj); + } + + } + } + + pthread_mutex_unlock(&(theControl->pollLock)); + +} + +JNIEXPORT jint JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_poll + (JNIEnv * env, jobject obj, jobject contextPointer, jobjectArray callbacks, jint min, jint max) { + int i = 0; + struct io_control * theControl = getIOControl(env, contextPointer); + if (theControl == NULL) { + return 0; + } + + + int result = io_getevents(theControl->ioContext, min, max, theControl->events, 0); + int retVal = result; + + for (i = 0; i < result; i++) { + struct io_event * event = &(theControl->events[i]); + struct iocb * iocbp = event->obj; + int eventResult = (int)event->res; + + #ifdef DEBUG + fprintf (stdout, "Poll res: %d totalRes=%d\n", eventResult, result); + #endif + + if (eventResult < 0) { + #ifdef DEBUG + fprintf (stdout, "Error: %s\n", strerror(-eventResult)); + #endif + + jstring jstrError = (*env)->NewStringUTF(env, strerror(-eventResult)); + + (*env)->CallVoidMethod(env, (jobject)(iocbp->data), errorMethod, (jint)(-eventResult), jstrError); + } + + (*env)->SetObjectArrayElement(env, callbacks, i, (jobject)iocbp->data); + + if (iocbp->data != NULL) { + // We delete the globalRef after the completion of the callback + (*env)->DeleteGlobalRef(env, (jobject)iocbp->data); + } + + putIOCB(theControl, iocbp); + } + + return retVal; +} + +JNIEXPORT jobject JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_newAlignedBuffer +(JNIEnv * env, jclass clazz, jint size, jint alignment) { + if (size % alignment != 0) { + throwRuntimeException(env, "Buffer size needs to be aligned to passed argument"); + return NULL; + } + + // This will allocate a buffer, aligned by alignment. + // Buffers created here need to be manually destroyed by destroyBuffer, or this would leak on the process heap away of Java's GC managed memory + // NOTE: this buffer will contain non initialized data, you must fill it up properly + void * buffer; + int result = posix_memalign(&buffer, (size_t)alignment, (size_t)size); + + if (result) { + throwRuntimeExceptionErrorNo(env, "Can't allocate posix buffer:", result); + return NULL; + } + + memset(buffer, 0, (size_t)size); + + return (*env)->NewDirectByteBuffer(env, buffer, size); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_freeBuffer + (JNIEnv * env, jclass clazz, jobject jbuffer) { + if (jbuffer == NULL) + { + throwRuntimeException(env, "Null pointer"); + return; + } + void * buffer = (*env)->GetDirectBufferAddress(env, jbuffer); + free(buffer); +} + + +/** It does nothing... just return true to make sure it has all the binary dependencies */ +JNIEXPORT jint JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_getNativeVersion + (JNIEnv * env, jclass clazz) + +{ + return org_apache_activemq_artemis_jlibaio_LibaioContext_EXPECTED_NATIVE_VERSION; +} + +JNIEXPORT jlong JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_getSize + (JNIEnv * env, jclass clazz, jint fd) +{ + struct stat statBuffer; + + if (fstat(fd, &statBuffer) < 0) + { + throwIOExceptionErrorNo(env, "Cannot determine file size:", errno); + return -1l; + } + return statBuffer.st_size; +} + +JNIEXPORT jint JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_getBlockSizeFD + (JNIEnv * env, jclass clazz, jint fd) +{ + struct stat statBuffer; + + if (fstat(fd, &statBuffer) < 0) + { + throwIOExceptionErrorNo(env, "Cannot determine file size:", errno); + return -1l; + } + return statBuffer.st_blksize; +} + +JNIEXPORT jint JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_getBlockSize + (JNIEnv * env, jclass clazz, jstring path) +{ + const char* f_path = (*env)->GetStringUTFChars(env, path, 0); + struct stat statBuffer; + + if (stat(f_path, &statBuffer) < 0) + { + throwIOExceptionErrorNo(env, "Cannot determine file size:", errno); + return -1l; + } + + (*env)->ReleaseStringUTFChars(env, path, f_path); + + return statBuffer.st_blksize; +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_fallocate + (JNIEnv * env, jclass clazz, jint fd, jlong size) +{ + if (fallocate(fd, 0, 0, (off_t) size) < 0) + { + throwIOExceptionErrorNo(env, "Could not preallocate file", errno); + } + fsync(fd); + lseek (fd, 0, SEEK_SET); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_fill + (JNIEnv * env, jclass clazz, jint fd, jlong size) +{ + void * preAllocBuffer = 0; + if (posix_memalign(&preAllocBuffer, 512, size) != 0) + { + throwOutOfMemoryError(env); + return; + } + memset(preAllocBuffer, 0, size); + lseek (fd, 0, SEEK_SET); + write(fd, preAllocBuffer, size); + lseek (fd, 0, SEEK_SET); + free (preAllocBuffer); +} + +JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_memsetBuffer + (JNIEnv *env, jclass clazz, jobject jbuffer, jint size) +{ + #ifdef DEBUG + fprintf (stdout, "Mem setting buffer with %d bytes\n", size); + #endif + void * buffer = (*env)->GetDirectBufferAddress(env, jbuffer); + + if (buffer == 0) + { + throwRuntimeException(env, "Invalid Buffer used, libaio requires NativeBuffer instead of Java ByteBuffer"); + return; + } + + memset(buffer, 0, (size_t)size); +} diff --git a/artemis-native/src/main/java/org/apache/activemq/artemis/core/libaio/Native.java b/artemis-native/src/main/java/org/apache/activemq/artemis/core/libaio/Native.java deleted file mode 100644 index 51f5da7f83..0000000000 --- a/artemis-native/src/main/java/org/apache/activemq/artemis/core/libaio/Native.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.activemq.artemis.core.libaio; - -import java.nio.ByteBuffer; - -import org.apache.activemq.artemis.api.core.ActiveMQException; - -public class Native -{ - // Functions used for locking files ..... - public static native int openFile(String fileName); - - public static native void closeFile(int handle); - - public static native boolean flock(int handle); - // Functions used for locking files ^^^^^^^^ - - public static native void resetBuffer(ByteBuffer directByteBuffer, int size); - - public static native void destroyBuffer(ByteBuffer buffer); - - public static native ByteBuffer newNativeBuffer(long size); - - public static native void newInit(Class someClass); - - public static native ByteBuffer init(Class controllerClass, String fileName, int maxIO, Object logger) throws ActiveMQException; - - public static native long size0(ByteBuffer handle); - - public static native void write(Object thisObject, ByteBuffer handle, - long sequence, - long position, - long size, - ByteBuffer buffer, - Object aioPackageCallback) throws ActiveMQException; - - /** a direct write to the file without the use of libaio's submit. */ - public static native void writeInternal(ByteBuffer handle, long positionToWrite, long size, ByteBuffer bytes) throws ActiveMQException; - - /** - *This is using org.apache.activemq.artemis.core.asyncio.AIOCallback - */ - public static native void read(Object thisObject, ByteBuffer handle, long position, long size, ByteBuffer buffer, Object aioPackageCallback) throws ActiveMQException; - - public static native void fill(ByteBuffer handle, long position, int blocks, long size, byte fillChar) throws ActiveMQException; - - public static native void closeInternal(ByteBuffer handler); - - public static native void stopPoller(ByteBuffer handler); - - /** A native method that does nothing, and just validate if the ELF dependencies are loaded and on the correct platform as this binary format */ - public static native int getNativeVersion(); - - /** Poll asynchronous events from internal queues */ - public static native void internalPollEvents(ByteBuffer handler); - - // Inner classes --------------------------------------------------------------------- - -} diff --git a/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/LibaioContext.java b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/LibaioContext.java new file mode 100644 index 0000000000..8b45f54465 --- /dev/null +++ b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/LibaioContext.java @@ -0,0 +1,446 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.jlibaio; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import static io.netty.util.internal.ObjectUtil.checkNotNull; + +/** + * This class is used as an aggregator for the {@link LibaioFile}. + *
+ * It holds native data, and it will share a libaio queue that can be used by multiple files. + *
+ * You need to use the poll methods to read the result of write and read submissions. + *
+ * You also need to use the special buffer created by {@link LibaioFile} as you need special alignments + * when dealing with O_DIRECT files. + *
+ * A Single controller can server multiple files. There's no need to create one controller per file. + *
+ * Interesting reading for this. + */ +public class LibaioContext implements Closeable +{ + + private static final AtomicLong totalMaxIO = new AtomicLong(0); + + /** + * This definition needs to match Version.h on the native sources. + *
+ * Or else the native module won't be loaded because of version mismatches + */ + private static final int EXPECTED_NATIVE_VERSION = 1; + + private static boolean loaded = false; + + public static boolean isLoaded() + { + return loaded; + } + + private static boolean loadLibrary(final String name) + { + try + { + System.loadLibrary(name); + if (getNativeVersion() != EXPECTED_NATIVE_VERSION) + { + NativeLogger.LOGGER.incompatibleNativeLibrary(); + return false; + } + else + { + return true; + } + } + catch (Throwable e) + { + NativeLogger.LOGGER.debug(name + " -> error loading the native library", e); + return false; + } + + } + + static + { + String[] libraries = new String[]{"artemis-native-64", "artemis-native-32"}; + + for (String library : libraries) + { + if (loadLibrary(library)) + { + loaded = true; + break; + } + else + { + NativeLogger.LOGGER.debug("Library " + library + " not found!"); + } + } + + if (!loaded) + { + NativeLogger.LOGGER.debug("Couldn't locate LibAIO Wrapper"); + } + } + + /** + * This is used to validate leaks on tests. + * @return the number of allocated aio, to be used on test checks. + */ + public static long getTotalMaxIO() + { + return totalMaxIO.get(); + } + + /** + * It will reset all the positions on the buffer to 0, using memset. + * @param buffer a native buffer. +s */ + public void memsetBuffer(ByteBuffer buffer) + { + memsetBuffer(buffer, buffer.limit()); + } + + /** + * This is used on tests validating for leaks. + */ + public static void resetMaxAIO() + { + totalMaxIO.set(0); + } + + /** + * the native ioContext including the structure created. + */ + private final ByteBuffer ioContext; + + private final AtomicBoolean closed = new AtomicBoolean(false); + + final Semaphore ioSpace; + + final int queueSize; + + /** + * The queue size here will use resources defined on the kernel parameter + * fs.aio-max-nr . + * + * @param queueSize the size to be initialize on libaio + * io_queue_init which can't be higher than /proc/sys/fs/aio-max-nr. + * @param useSemaphore should block on a semaphore avoiding using more submits than what's available. + */ + public LibaioContext(int queueSize, boolean useSemaphore) + { + try + { + this.ioContext = newContext(queueSize); + } + catch (Exception e) + { + throw e; + } + this.queueSize = queueSize; + totalMaxIO.addAndGet(queueSize); + if (useSemaphore) + { + this.ioSpace = new Semaphore(queueSize); + } + else + { + this.ioSpace = null; + } + } + + + /** + * Documented at {@link LibaioFile#write(long, int, java.nio.ByteBuffer, SubmitInfo)} + * @param fd the file descriptor + * @param position the write position + * @param size number of bytes to use + * @param bufferWrite the native buffer + * @param callback a callback + * @throws IOException in case of error + */ + public void submitWrite(int fd,long position, int size, + ByteBuffer bufferWrite, Callback callback) throws IOException + { + try + { + if (ioSpace != null) + { + ioSpace.acquire(); + } + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + throw new IOException(e.getMessage(), e); + } + submitWrite(fd, this.ioContext, position, size, bufferWrite, callback); + } + + public void submitRead(int fd, long position, int size, ByteBuffer bufferWrite, + Callback callback) throws IOException + { + try + { + if (ioSpace != null) + { + ioSpace.acquire(); + } + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + throw new IOException(e.getMessage(), e); + } + submitRead(fd, this.ioContext, position, size, bufferWrite, callback); + } + + + /** + * This is used to close the libaio queues and cleanup the native data used. + *
+ * It is unsafe to close the controller while you have pending writes or files open as + * this could cause core dumps or VM crashes. + */ + @Override + public void close() + { + if (!closed.getAndSet(true)) + { + totalMaxIO.addAndGet(-queueSize); + + if (ioContext != null) + { + deleteContext(ioContext); + } + } + } + + @Override + protected void finalize() throws Throwable + { + super.finalize(); + close(); + } + + /** + * It will open a file. If you set the direct flag = false then you won't need to use the special buffer. + * Notice: This will create an empty file if the file doesn't already exist. + * + * @param file the file to be open. + * @param direct will set ODIRECT. + * @return It will return a LibaioFile instance. + * @throws IOException in case of error. + */ + public LibaioFile openFile(File file, boolean direct) throws IOException + { + return openFile(file.getPath(), direct); + } + + /** + * It will open a file. If you set the direct flag = false then you won't need to use the special buffer. + * Notice: This will create an empty file if the file doesn't already exist. + * + * @param file the file to be open. + * @param direct should use O_DIRECT when opening the file. + * @return a new open file. + * @throws IOException in case of error. + */ + public LibaioFile openFile(String file, boolean direct) throws IOException + { + checkNotNull(file, "path"); + checkNotNull(ioContext, "IOContext"); + + // note: the native layer will throw an IOException in case of errors + int res = LibaioContext.open(file, direct); + + return new LibaioFile<>(res, this); + } + + /** + * It will open a file disassociated with any sort of factory. + * This is useful when you won't use reading / writing through libaio like locking files. + * @param file a file name + * @param direct will use O_DIRECT + * @return a new file + * @throws IOException in case of error. + */ + public static LibaioFile openControlFile(String file, boolean direct) throws IOException + { + checkNotNull(file, "path"); + + // note: the native layer will throw an IOException in case of errors + int res = LibaioContext.open(file, direct); + + return new LibaioFile<>(res, null); + } + + /** + * It will poll the libaio queue for results. It should block until min is reached + * Results are placed on the callback. + *
+ * This shouldn't be called concurrently. You should provide your own synchronization if you need more than one + * Thread polling for any reason. + *
+ * Notice that the native layer will invoke {@link SubmitInfo#onError(int, String)} in case of failures, + * but it won't call done method for you. + * + * @param callbacks area to receive the callbacks passed on submission.The size of this callback has to + * be greater than the parameter max. + * @param min the minimum number of elements to receive. It will block until this is achieved. + * @param max The maximum number of elements to receive. + * @return Number of callbacks returned. + * @see LibaioFile#write(long, int, java.nio.ByteBuffer, SubmitInfo) + * @see LibaioFile#read(long, int, java.nio.ByteBuffer, SubmitInfo) + */ + public int poll(Callback[] callbacks, int min, int max) + { + int released = poll(ioContext, callbacks, min, max); + if (ioSpace != null) + { + if (released > 0) + { + ioSpace.release(released); + } + } + return released; + } + + /** + * It will start polling and will keep doing until the context is closed. + * This will call callbacks on {@link SubmitInfo#onError(int, String)} and + * {@link SubmitInfo#done()}. + * In case of error, both {@link SubmitInfo#onError(int, String)} and + * {@link SubmitInfo#done()} are called. + */ + public void poll() + { + blockedPoll(ioContext); + } + + /** Called from the native layer */ + private void done(SubmitInfo info) + { + if (ioSpace != null) + { + ioSpace.release(); + } + info.done(); + } + + /** + * This is the queue for libaio, initialized with queueSize. + */ + private native ByteBuffer newContext(int queueSize); + + /** + * Internal method to be used when closing the controller. + */ + private native void deleteContext(ByteBuffer buffer); + + /** + * it will return a file descriptor. + * + * @param path the file name. + * @param direct translates as O_DIRECT On open + * @return a fd from open C call. + */ + public static native int open(String path, boolean direct); + + static native void close(int fd); + + /** + */ + + /** + * Buffers for O_DIRECT need to use posix_memalign. + *
+ * Documented at {@link LibaioFile#newBuffer(int)}. + * + * @param size needs to be % alignment + * @param alignment the alignment used at the dispositive + * @return a new native buffer used with posix_memalign + */ + public static native ByteBuffer newAlignedBuffer(int size, int alignment); + + /** + * This will call posix free to release the inner buffer allocated at {@link #newAlignedBuffer(int, int)}. + * @param buffer a native buffer allocated with {@link #newAlignedBuffer(int, int)}. + */ + public static native void freeBuffer(ByteBuffer buffer); + + /** + * Documented at {@link LibaioFile#write(long, int, java.nio.ByteBuffer, SubmitInfo)}. + */ + native void submitWrite(int fd, + ByteBuffer libaioContext, + long position, int size, ByteBuffer bufferWrite, + Callback callback) throws IOException; + + /** + * Documented at {@link LibaioFile#read(long, int, java.nio.ByteBuffer, SubmitInfo)}. + */ + native void submitRead(int fd, + ByteBuffer libaioContext, + long position, int size, ByteBuffer bufferWrite, + Callback callback) throws IOException; + + /** + * Note: this shouldn't be done concurrently. + * This method will block until the min condition is satisfied on the poll. + *

+ * The callbacks will include the original callback sent at submit (read or write). + */ + native int poll(ByteBuffer libaioContext, Callback[] callbacks, int min, int max); + + /** + * This method will block as long as the context is open. + */ + native void blockedPoll(ByteBuffer libaioContext); + + static native int getNativeVersion(); + + public static native boolean lock(int fd); + + public static native void memsetBuffer(ByteBuffer buffer, int size); + + static native long getSize(int fd); + + static native int getBlockSizeFD(int fd); + + public static int getBlockSize(File path) + { + return getBlockSize(path.getAbsolutePath()); + } + + public static native int getBlockSize(String path); + + static native void fallocate(int fd, long size); + + static native void fill(int fd, long size); + + static native void writeInternal(int fd, long position, long size, ByteBuffer bufferWrite) throws IOException; +} diff --git a/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/LibaioFile.java b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/LibaioFile.java new file mode 100644 index 0000000000..bf88d65356 --- /dev/null +++ b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/LibaioFile.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.jlibaio; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * This is an extension to use libaio. + */ +public final class LibaioFile +{ + protected boolean open; + /** + * This represents a structure allocated on the native + * this is a io_context_t + */ + final LibaioContext ctx; + + private int fd; + + LibaioFile(int fd, LibaioContext ctx) + { + this.ctx = ctx; + this.fd = fd; + } + + public int getBlockSize() + { + return 512; + // FIXME + //return LibaioContext.getBlockSizeFD(fd); + } + + public boolean lock() + { + return LibaioContext.lock(fd); + } + + /** + * {@inheritDoc} + */ + public void close() throws IOException + { + open = false; + LibaioContext.close(fd); + } + + /** + * @return The size of the file. + */ + public long getSize() + { + return LibaioContext.getSize(fd); + } + + /** + * It will submit a write to the queue. The callback sent here will be received on the + * {@link LibaioContext#poll(SubmitInfo[], int, int)} + * In case of the libaio queue is full (e.g. returning E_AGAIN) this method will return false. + *
+ * Notice: this won't hold a global reference on buffer, callback should hold a reference towards bufferWrite. + * And don't free the buffer until the callback was called as this could crash the VM. + * + * @param position The position on the file to write. Notice this has to be a multiple of 512. + * @param size The size of the buffer to use while writing. + * @param buffer if you are using O_DIRECT the buffer here needs to be allocated by {@link #newBuffer(int)}. + * @param callback A callback to be returned on the poll method. + * @throws java.io.IOException in case of error + */ + public void write(long position, int size, ByteBuffer buffer, Callback callback) throws IOException + { + ctx.submitWrite(fd, position, size, buffer, callback); + } + + /** + * It will submit a read to the queue. The callback sent here will be received on the + * {@link LibaioContext#poll(SubmitInfo[], int, int)}. + * In case of the libaio queue is full (e.g. returning E_AGAIN) this method will return false. + *
+ * Notice: this won't hold a global reference on buffer, callback should hold a reference towards bufferWrite. + * And don't free the buffer until the callback was called as this could crash the VM. + * * + * + * @param position The position on the file to read. Notice this has to be a multiple of 512. + * @param size The size of the buffer to use while reading. + * @param buffer if you are using O_DIRECT the buffer here needs to be allocated by {@link #newBuffer(int)}. + * @param callback A callback to be returned on the poll method. + * @throws java.io.IOException in case of error + * @see LibaioContext#poll(SubmitInfo[], int, int) + */ + public void read(long position, int size, ByteBuffer buffer, Callback callback) throws IOException + { + ctx.submitRead(fd, position, size, buffer, callback); + } + + /** + * It will allocate a buffer to be used on libaio operations. + * Buffers here are allocated with posix_memalign. + *
+ * You need to explicitly free the buffer created from here using the + * {@link LibaioContext#freeBuffer(java.nio.ByteBuffer)}. + * + * @param size the size of the buffer. + * @return the buffer allocated. + */ + public ByteBuffer newBuffer(int size) + { + return LibaioContext.newAlignedBuffer(size, 512); + } + + /** + * It will preallocate the file with a given size. + * @param size number of bytes to be filled on the file + */ + public void fill(long size) + { + try + { + LibaioContext.fill(fd, size); + } + catch (OutOfMemoryError e) + { + NativeLogger.LOGGER.debug("Didn't have enough memory to allocate " + size + " bytes in memory, using simple fallocate"); + LibaioContext.fallocate(fd, size); + } + } + + /** + * It will use fallocate to initialize a file. + * @param size number of bytes to be filled on the file + */ + public void fallocate(long size) + { + LibaioContext.fallocate(fd, size); + } + +} diff --git a/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/NativeLogger.java b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/NativeLogger.java new file mode 100644 index 0000000000..449c1685ce --- /dev/null +++ b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/NativeLogger.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.jlibaio; + +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; +import org.jboss.logging.annotations.MessageLogger; + +/** + * Logger Code 14 + * + * each message id must be 6 digits long starting with 14, the 3rd digit donates the level so + * + * INF0 1 + * WARN 2 + * DEBUG 3 + * ERROR 4 + * TRACE 5 + * FATAL 6 + * + * so an INFO message would be 1000 to 6000 + */ +@MessageLogger(projectCode = "jlibaio") +public interface NativeLogger extends BasicLogger +{ + /** + * The journal logger. + */ + NativeLogger LOGGER = Logger.getMessageLogger(NativeLogger.class, NativeLogger.class.getPackage().getName()); + + + @LogMessage(level = Logger.Level.WARN) + @Message(id = 1001, value = "You have a native library with a different version than expected", format = Message.Format.MESSAGE_FORMAT) + void incompatibleNativeLibrary(); +} diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/BufferCallback.java b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/SubmitInfo.java similarity index 77% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/BufferCallback.java rename to artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/SubmitInfo.java index e7b0ca54ea..47feea86d2 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/asyncio/BufferCallback.java +++ b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/SubmitInfo.java @@ -14,14 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.asyncio; -import java.nio.ByteBuffer; +package org.apache.activemq.artemis.jlibaio; -/** - * Used to receive a notification on completed buffers used by the AIO layer. - */ -public interface BufferCallback +public interface SubmitInfo { - void bufferDone(ByteBuffer buffer); + void onError(int errno, String message); + + void done(); } diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOAsyncTask.java b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/package-info.java similarity index 70% rename from artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOAsyncTask.java rename to artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/package-info.java index 09c80ca17d..341fa1ced7 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/IOAsyncTask.java +++ b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/package-info.java @@ -14,14 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.activemq.artemis.core.journal; - -import org.apache.activemq.artemis.core.asyncio.AIOCallback; /** - * This class is just a direct extension of AIOCallback. - * Just to avoid the direct dependency of org.apache.activemq.artemis.core.asynciio.AIOCallback from the journal. + * This packages handles Linux libaio at a low level. + *
+ * Buffers needs to be specially allocated by {@link org.apache.activemq.artemis.jlibaio.LibaioContext#newAlignedBuffer(int, int)} + * as they need to be aligned to 512 or 4096 when using Direct files. */ -public interface IOAsyncTask extends AIOCallback -{ -} +package org.apache.activemq.artemis.jlibaio; diff --git a/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/util/CallbackCache.java b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/util/CallbackCache.java new file mode 100644 index 0000000000..ec2a630587 --- /dev/null +++ b/artemis-native/src/main/java/org/apache/activemq/artemis/jlibaio/util/CallbackCache.java @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.jlibaio.util; + + +import org.apache.activemq.artemis.jlibaio.SubmitInfo; + +/** + * this is an utility class where you can reuse Callbackk objects for your LibaioContext usage. + */ +public class CallbackCache +{ + private final SubmitInfo[] pool; + + private int put = 0; + private int get = 0; + private int available = 0; + private final int size; + + private final Object lock = new Object(); + + public CallbackCache(int size) + { + this.pool = new SubmitInfo[size]; + this.size = size; + } + + public Callback get() + { + synchronized (lock) + { + if (available <= 0) + { + return null; + } + else + { + Callback retValue = (Callback)pool[get]; + pool[get] = null; + if (retValue == null) + { + throw new NullPointerException("You should initialize the pool before using it"); + } + if (retValue != null) + { + available--; + get++; + if (get >= size) + { + get = 0; + } + } + return retValue; + } + } + } + + public CallbackCache put(Callback callback) + { + if (callback == null) + { + return null; + } + synchronized (lock) + { + if (available < size) + { + available++; + pool[put++] = callback; + if (put >= size) + { + put = 0; + } + } + } + return this; + } +} diff --git a/artemis-native/src/test/java/org/apache/activemq/artemis/jlibaio/test/CallbackCachelTest.java b/artemis-native/src/test/java/org/apache/activemq/artemis/jlibaio/test/CallbackCachelTest.java new file mode 100644 index 0000000000..f62f8e2457 --- /dev/null +++ b/artemis-native/src/test/java/org/apache/activemq/artemis/jlibaio/test/CallbackCachelTest.java @@ -0,0 +1,112 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.jlibaio.test; + +import java.util.HashSet; + +import org.apache.activemq.artemis.jlibaio.util.CallbackCache; +import org.apache.activemq.artemis.jlibaio.SubmitInfo; +import org.junit.Assert; +import org.junit.Test; + +public class CallbackCachelTest +{ + @Test + public void testPartiallyInitialized() + { + CallbackCache pool = new CallbackCache(100); + + + for (int i = 0; i < 50; i++) + { + pool.put(new MyPool(i)); + } + + MyPool value = pool.get(); + + Assert.assertNotNull(value); + + pool.put(value); + + + // add and remove immediately + for (int i = 0; i < 777; i++) + { + pool.put(pool.get()); + } + + + HashSet hashValues = new HashSet<>(); + + + MyPool getValue; + while ((getValue = pool.get()) != null) + { + hashValues.add(getValue); + } + + + Assert.assertEquals(50, hashValues.size()); + } + + static class MyPool implements SubmitInfo + { + public final int i; + + MyPool(int i) + { + this.i = i; + } + + + public int getI() + { + return i; + } + + @Override + public void onError(int errno, String message) + { + } + + @Override + public void done() + { + + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MyPool myPool = (MyPool) o; + + if (i != myPool.i) return false; + + return true; + } + + @Override + public int hashCode() + { + return i; + } + } +} diff --git a/artemis-native/src/test/java/org/apache/activemq/artemis/jlibaio/test/LibaioTest.java b/artemis-native/src/test/java/org/apache/activemq/artemis/jlibaio/test/LibaioTest.java new file mode 100644 index 0000000000..e46caf36d0 --- /dev/null +++ b/artemis-native/src/test/java/org/apache/activemq/artemis/jlibaio/test/LibaioTest.java @@ -0,0 +1,859 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.activemq.artemis.jlibaio.test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.jlibaio.LibaioFile; +import org.apache.activemq.artemis.jlibaio.SubmitInfo; +import org.junit.After; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +/** + * This test is using a different package from {@link LibaioFile} + * as I need to validate public methods on the API + */ +public class LibaioTest +{ + + @BeforeClass + public static void testAIO() + { + Assume.assumeTrue(LibaioContext.isLoaded()); + } + + /** This is just an arbitrary number for a number of elements you need to pass to the libaio init method + * Some of the tests are using half of this number, so if anyone decide to change this please use an even number. + */ + private static final int LIBAIO_QUEUE_SIZE = 50; + + @Rule + public TemporaryFolder temporaryFolder; + + public LibaioContext control; + + @Before + public void setUpFactory() + { + control = new LibaioContext<>(LIBAIO_QUEUE_SIZE, true); + } + + @After + public void deleteFactory() + { + control.close(); + validateLibaio(); + } + + public void validateLibaio() + { + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); + } + + public LibaioTest() + { + /* + * I didn't use /tmp for three reasons + * - Most systems now will use tmpfs which is not compatible with O_DIRECT + * - This would fill up /tmp in case of failures. + * - target is cleaned up every time you do a mvn clean, so it's safer + */ + File parent = new File("./target"); + parent.mkdirs(); + temporaryFolder = new TemporaryFolder(parent); + } + + @Test + public void testOpen() throws Exception + { + LibaioFile fileDescriptor = control.openFile(temporaryFolder.newFile("test.bin"), true); + fileDescriptor.close(); + } + + @Test + public void testInitAndFallocate() throws Exception + { + LibaioFile fileDescriptor = control.openFile(temporaryFolder.newFile("test.bin"), true); + fileDescriptor.fallocate(1024 * 1024); + + ByteBuffer buffer = fileDescriptor.newBuffer(1024 * 1024); + fileDescriptor.read(0, 1024 * 1024, buffer, new TestInfo()); + + TestInfo[] callbacks = new TestInfo[1]; + control.poll(callbacks, 1, 1); + + fileDescriptor.close(); + + + buffer.position(0); + + LibaioFile fileDescriptor2 = control.openFile(temporaryFolder.newFile("test2.bin"), true); + fileDescriptor2.fill(1024 * 1024); + fileDescriptor2.read(0, 1024 * 1024, buffer, new TestInfo()); + + control.poll(callbacks, 1, 1); + for (int i = 0; i < 1024 * 1024; i++) + { + Assert.assertEquals(0, buffer.get()); + } + + LibaioContext.freeBuffer(buffer); + } + + @Test + public void testSubmitWriteOnTwoFiles() throws Exception + { + + File file1 = temporaryFolder.newFile("test.bin"); + File file2 = temporaryFolder.newFile("test2.bin"); + + fillupFile(file1, LIBAIO_QUEUE_SIZE / 2); + fillupFile(file2, LIBAIO_QUEUE_SIZE / 2); + + LibaioFile[] fileDescriptor = new LibaioFile[]{control.openFile(file1, true), + control.openFile(file2, true)}; + + Assert.assertEquals((LIBAIO_QUEUE_SIZE / 2) * 512, fileDescriptor[0].getSize()); + Assert.assertEquals((LIBAIO_QUEUE_SIZE / 2) * 512, fileDescriptor[1].getSize()); + Assert.assertEquals(fileDescriptor[0].getBlockSize(), fileDescriptor[1].getBlockSize()); + Assert.assertEquals(LibaioContext.getBlockSize(temporaryFolder.getRoot()), LibaioContext.getBlockSize(file1)); + Assert.assertEquals(LibaioContext.getBlockSize(file1), LibaioContext.getBlockSize(file2)); + System.out.println("blockSize = " + fileDescriptor[0].getBlockSize()); + System.out.println("blockSize /tmp= " + LibaioContext.getBlockSize("/tmp")); + + ByteBuffer buffer = LibaioContext.newAlignedBuffer(512, 512); + + try + { + for (int i = 0; i < 512; i++) + { + buffer.put((byte) 'a'); + } + + TestInfo callback = new TestInfo(); + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + + for (int i = 0; i < LIBAIO_QUEUE_SIZE / 2; i++) + { + for (LibaioFile file : fileDescriptor) + { + file.write(i * 512, 512, buffer, callback); + } + } + + Assert.assertEquals(LIBAIO_QUEUE_SIZE, control.poll(callbacks, LIBAIO_QUEUE_SIZE, LIBAIO_QUEUE_SIZE)); + + for (Object returnedCallback : callbacks) + { + Assert.assertSame(returnedCallback, callback); + } + + for (LibaioFile file : fileDescriptor) + { + ByteBuffer bigbuffer = LibaioContext.newAlignedBuffer(512 * 25, 512); + file.read(0, 512 * 25, bigbuffer, callback); + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + for (Object returnedCallback : callbacks) + { + Assert.assertSame(returnedCallback, callback); + } + + for (int i = 0; i < 512 * 25; i++) + { + Assert.assertEquals((byte) 'a', bigbuffer.get()); + } + + LibaioContext.freeBuffer(bigbuffer); + + file.close(); + } + } + finally + { + LibaioContext.freeBuffer(buffer); + } + } + + @Test + public void testSubmitWriteAndRead() throws Exception + { + TestInfo callback = new TestInfo(); + + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + + LibaioFile fileDescriptor = control.openFile(temporaryFolder.newFile("test.bin"), true); + + // ByteBuffer buffer = ByteBuffer.allocateDirect(512); + ByteBuffer buffer = LibaioContext.newAlignedBuffer(512, 512); + + try + { + for (int i = 0; i < 512; i++) + { + buffer.put((byte) 'a'); + } + + buffer.rewind(); + + fileDescriptor.write(0, 512, buffer, callback); + + int retValue = control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE); + Assert.assertEquals(1, retValue); + + Assert.assertSame(callback, callbacks[0]); + + LibaioContext.freeBuffer(buffer); + + buffer = LibaioContext.newAlignedBuffer(512, 512); + + for (int i = 0; i < 512; i++) + { + buffer.put((byte) 'B'); + } + + fileDescriptor.write(0, 512, buffer, null); + + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + buffer.rewind(); + + fileDescriptor.read(0, 512, buffer, null); + + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + for (int i = 0; i < 512; i++) + { + Assert.assertEquals('B', buffer.get()); + } + } + finally + { + LibaioContext.freeBuffer(buffer); + fileDescriptor.close(); + } + } + + @Test + /** + * This file is making use of libaio without O_DIRECT + * We won't need special buffers on this case. + */ + public void testSubmitWriteAndReadRegularBuffers() throws Exception + { + TestInfo callback = new TestInfo(); + + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + + File file = temporaryFolder.newFile("test.bin"); + + fillupFile(file, LIBAIO_QUEUE_SIZE); + + LibaioFile fileDescriptor = control.openFile(file, false); + + final int BUFFER_SIZE = 50; + + ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); + + try + { + for (int i = 0; i < BUFFER_SIZE; i++) + { + buffer.put((byte) 'a'); + } + + buffer.rewind(); + + fileDescriptor.write(0, BUFFER_SIZE, buffer, callback); + + int retValue = control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE); + System.out.println("Return from poll::" + retValue); + Assert.assertEquals(1, retValue); + + Assert.assertSame(callback, callbacks[0]); + + buffer.rewind(); + + for (int i = 0; i < BUFFER_SIZE; i++) + { + buffer.put((byte) 'B'); + } + + fileDescriptor.write(0, BUFFER_SIZE, buffer, null); + + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + buffer.rewind(); + + fileDescriptor.read(0, 50, buffer, null); + + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + for (int i = 0; i < BUFFER_SIZE; i++) + { + Assert.assertEquals('B', buffer.get()); + } + } + finally + { + fileDescriptor.close(); + } + } + + @Test + public void testSubmitRead() throws Exception + { + + TestInfo callback = new TestInfo(); + + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + + File file = temporaryFolder.newFile("test.bin"); + + fillupFile(file, LIBAIO_QUEUE_SIZE); + + LibaioFile fileDescriptor = control.openFile(file, true); + + ByteBuffer buffer = LibaioContext.newAlignedBuffer(512, 512); + + final int BUFFER_SIZE = 512; + try + { + for (int i = 0; i < BUFFER_SIZE; i++) + { + buffer.put((byte) '@'); + } + + fileDescriptor.write(0, BUFFER_SIZE, buffer, callback); + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + Assert.assertSame(callback, callbacks[0]); + + buffer.rewind(); + + fileDescriptor.read(0, BUFFER_SIZE, buffer, callback); + + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + Assert.assertSame(callback, callbacks[0]); + + for (int i = 0; i < BUFFER_SIZE; i++) + { + Assert.assertEquals('@', buffer.get()); + } + } + finally + { + LibaioContext.freeBuffer(buffer); + fileDescriptor.close(); + } + } + + @Test + public void testInvalidWrite() throws Exception + { + + TestInfo callback = new TestInfo(); + + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + + File file = temporaryFolder.newFile("test.bin"); + + fillupFile(file, LIBAIO_QUEUE_SIZE); + + LibaioFile fileDescriptor = control.openFile(file, true); + + try + { + ByteBuffer buffer = ByteBuffer.allocateDirect(300); + for (int i = 0; i < 300; i++) + { + buffer.put((byte) 'z'); + } + + fileDescriptor.write(0, 300, buffer, callback); + + Assert.assertEquals(1, control.poll(callbacks, 1, LIBAIO_QUEUE_SIZE)); + + Assert.assertTrue(callbacks[0].isError()); + + // Error condition + Assert.assertSame(callbacks[0], callback); + + System.out.println("Error:" + callbacks[0]); + + buffer = fileDescriptor.newBuffer(512); + for (int i = 0; i < 512; i++) + { + buffer.put((byte) 'z'); + } + + callback = new TestInfo(); + + fileDescriptor.write(0, 512, buffer, callback); + + Assert.assertEquals(1, control.poll(callbacks, 1, 1)); + + Assert.assertSame(callback, callbacks[0]); + + fileDescriptor.write(5, 512, buffer, callback); + + Assert.assertEquals(1, control.poll(callbacks, 1, 1)); + + Assert.assertTrue(callbacks[0].isError()); + + callbacks = null; + callback = null; + + TestInfo.checkLeaks(); + } + finally + { + fileDescriptor.close(); + } + } + + @Test + public void testLeaks() throws Exception + { + File file = temporaryFolder.newFile("test.bin"); + + fillupFile(file, LIBAIO_QUEUE_SIZE * 2); + + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + + LibaioFile fileDescriptor = control.openFile(file, true); + + ByteBuffer bufferWrite = LibaioContext.newAlignedBuffer(512, 512); + + try + { + for (int i = 0; i < 512; i++) + { + bufferWrite.put((byte) 'B'); + } + + for (int j = 0; j < LIBAIO_QUEUE_SIZE * 2; j++) + { + for (int i = 0; i < LIBAIO_QUEUE_SIZE; i++) + { + TestInfo countClass = new TestInfo(); + fileDescriptor.write(i * 512, 512, bufferWrite, countClass); + } + + Assert.assertEquals(LIBAIO_QUEUE_SIZE, control.poll(callbacks, LIBAIO_QUEUE_SIZE, LIBAIO_QUEUE_SIZE)); + + for (int i = 0; i < LIBAIO_QUEUE_SIZE; i++) + { + Assert.assertNotNull(callbacks[i]); + callbacks[i] = null; + } + } + + TestInfo.checkLeaks(); + } + finally + { + LibaioContext.freeBuffer(bufferWrite); + } + } + + @Test + public void testLock() throws Exception + { + File file = temporaryFolder.newFile("test.bin"); + + LibaioFile fileDescriptor = control.openFile(file, true); + fileDescriptor.lock(); + + fileDescriptor.close(); + } + + @Test + public void testAlloc() throws Exception + { + File file = temporaryFolder.newFile("test.bin"); + + LibaioFile fileDescriptor = control.openFile(file, true); + fileDescriptor.fill(10 * 1024 * 1024); + + fileDescriptor.close(); + } + + @Test + public void testReleaseNullBuffer() throws Exception + { + boolean failed = false; + try + { + LibaioContext.freeBuffer(null); + } + catch (Exception expected) + { + failed = true; + } + + Assert.assertTrue("Exception happened!", failed); + + } + + @Test + public void testMemset() throws Exception + { + + ByteBuffer buffer = LibaioContext.newAlignedBuffer(512 * 8, 512); + + for (int i = 0; i < buffer.capacity(); i++) + { + buffer.put((byte) 'z'); + } + + buffer.position(0); + + for (int i = 0; i < buffer.capacity(); i++) + { + Assert.assertEquals((byte) 'z', buffer.get()); + } + + control.memsetBuffer(buffer); + + buffer.position(0); + + for (int i = 0; i < buffer.capacity(); i++) + { + Assert.assertEquals((byte) 0, buffer.get()); + } + + LibaioContext.freeBuffer(buffer); + + } + + @Test + public void testIOExceptionConditions() throws Exception + { + boolean exceptionThrown = false; + + control.close(); + control = new LibaioContext<>(LIBAIO_QUEUE_SIZE, false); + try + { + // There is no space for a queue this huge, the native layer should throw the exception + LibaioContext newController = new LibaioContext(Integer.MAX_VALUE, false); + } + catch (RuntimeException e) + { + exceptionThrown = true; + } + + Assert.assertTrue(exceptionThrown); + exceptionThrown = false; + + try + { + // this should throw an exception, we shouldn't be able to open a directory! + control.openFile(temporaryFolder.getRoot(), true); + } + catch (IOException expected) + { + exceptionThrown = true; + } + + Assert.assertTrue(exceptionThrown); + + exceptionThrown = false; + + LibaioFile fileDescriptor = control.openFile(temporaryFolder.newFile(), true); + fileDescriptor.close(); + try + { + fileDescriptor.close(); + } + catch (IOException expected) + { + exceptionThrown = true; + } + + Assert.assertTrue(exceptionThrown); + + fileDescriptor = control.openFile(temporaryFolder.newFile(), true); + + ByteBuffer buffer = fileDescriptor.newBuffer(512); + + try + { + for (int i = 0; i < 512; i++) + { + buffer.put((byte) 'a'); + } + + for (int i = 0; i < LIBAIO_QUEUE_SIZE; i++) + { + fileDescriptor.write(i * 512, 512, buffer, new TestInfo()); + } + + boolean ex = false; + try + { + fileDescriptor.write(0, 512, buffer, new TestInfo()); + } + catch (Exception e) + { + ex = true; + } + + Assert.assertTrue(ex); + + TestInfo[] callbacks = new TestInfo[LIBAIO_QUEUE_SIZE]; + Assert.assertEquals(LIBAIO_QUEUE_SIZE, control.poll(callbacks, LIBAIO_QUEUE_SIZE, LIBAIO_QUEUE_SIZE)); + + // it should be possible to write now after queue space being released + fileDescriptor.write(0, 512, buffer, new TestInfo()); + Assert.assertEquals(1, control.poll(callbacks, 1, 100)); + + TestInfo errorCallback = new TestInfo(); + // odd positions will have failures through O_DIRECT + fileDescriptor.read(3, 512, buffer, errorCallback); + Assert.assertEquals(1, control.poll(callbacks, 1, 50)); + Assert.assertTrue(callbacks[0].isError()); + Assert.assertSame(errorCallback, (callbacks[0])); + + // to help GC and the checkLeaks + callbacks = null; + errorCallback = null; + + TestInfo.checkLeaks(); + + exceptionThrown = false; + try + { + LibaioContext.newAlignedBuffer(300, 512); + } + catch (RuntimeException e) + { + exceptionThrown = true; + } + + Assert.assertTrue(exceptionThrown); + + exceptionThrown = false; + try + { + LibaioContext.newAlignedBuffer(-512, 512); + } + catch (RuntimeException e) + { + exceptionThrown = true; + } + + Assert.assertTrue(exceptionThrown); + } + finally + { + LibaioContext.freeBuffer(buffer); + } + } + + @Test + public void testBlockedCallback() throws Exception + { + final LibaioContext blockedContext = new LibaioContext(500, true); + Thread t = new Thread() + { + public void run() + { + blockedContext.poll(); + } + }; + + t.start(); + + + int NUMBER_OF_BLOCKS = 5000; + + final CountDownLatch latch = new CountDownLatch(NUMBER_OF_BLOCKS); + + File file = temporaryFolder.newFile("sub-file.txt"); + LibaioFile aioFile = blockedContext.openFile(file, true); + aioFile.fill(NUMBER_OF_BLOCKS * 512); + + final AtomicInteger errors = new AtomicInteger(0); + + class MyCallback implements SubmitInfo + { + @Override + public void onError(int errno, String message) + { + errors.incrementAndGet(); + } + + @Override + public void done() + { + latch.countDown(); + } + } + + MyCallback callback = new MyCallback(); + + ByteBuffer buffer = LibaioContext.newAlignedBuffer(512, 512); + + + for (int i = 0; i < 512; i++) + { + buffer.put((byte)'a'); + } + + long start = System.currentTimeMillis(); + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + aioFile.write(i * 512, 512, buffer, callback); + } + + long end = System.currentTimeMillis(); + + latch.await(); + + + System.out.println("time = " + (end - start) + " writes/second=" + NUMBER_OF_BLOCKS * 1000L / (end - start)); +// +// MultiThreadAsynchronousFileTest.debug((sync ? "Sync result:" : "Async result:") + " Records/Second = " + +// MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS * +// MultiThreadAsynchronousFileTest.NUMBER_OF_LINES * +// 1000 / +// (endTime - startTime) + +// " total time = " + +// (endTime - startTime) + +// " total number of records = " + +// MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS * +// MultiThreadAsynchronousFileTest.NUMBER_OF_LINES); + + Thread.sleep(100); + + blockedContext.close(); + t.join(); + } + + private void fillupFile(File file, int blocks) throws IOException + { + FileOutputStream fileOutputStream = new FileOutputStream(file); + byte[] bufferWrite = new byte[512]; + for (int i = 0; i < 512; i++) + { + bufferWrite[i] = (byte) 0; + } + + for (int i = 0; i < blocks; i++) + { + fileOutputStream.write(bufferWrite); + } + + fileOutputStream.close(); + } + + + static class TestInfo implements SubmitInfo + { + static AtomicInteger count = new AtomicInteger(); + + @Override + protected void finalize() throws Throwable + { + super.finalize(); + count.decrementAndGet(); + } + + public static void checkLeaks() throws InterruptedException + { + for (int i = 0; count.get() != 0 && i < 50; i++) + { + WeakReference reference = new WeakReference(new Object()); + while (reference.get() != null) + { + System.gc(); + Thread.sleep(100); + } + } + Assert.assertEquals(0, count.get()); + } + + boolean error = false; + String errorMessage; + int errno; + + public TestInfo() + { + count.incrementAndGet(); + } + + @Override + public void onError(int errno, String message) + { + this.errno = errno; + this.errorMessage = message; + this.error = true; + } + + @Override + public void done() + { + } + + public int getErrno() + { + return errno; + } + + public void setErrno(int errno) + { + this.errno = errno; + } + + public boolean isError() + { + return error; + } + + public void setError(boolean error) + { + this.error = error; + } + + public String getErrorMessage() + { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) + { + this.errorMessage = errorMessage; + } + } +} diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java index 71610b46d2..f74d6d793a 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java @@ -20,6 +20,7 @@ package org.apache.activemq.artemis.core.protocol.proton.plug; import java.util.concurrent.Executor; import io.netty.buffer.ByteBuf; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.qpid.proton.amqp.Binary; import org.apache.qpid.proton.amqp.transport.AmqpError; import org.apache.qpid.proton.amqp.transport.ErrorCondition; @@ -30,7 +31,6 @@ import org.apache.qpid.proton.jms.EncodedMessage; import org.apache.qpid.proton.message.ProtonJMessage; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.client.ActiveMQClient; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.protocol.proton.ProtonProtocolManager; import org.apache.activemq.artemis.core.server.QueueQueryResult; import org.apache.activemq.artemis.core.server.ServerConsumer; @@ -275,7 +275,7 @@ public class ProtonSessionIntegrationCallback implements AMQPSessionCallback, Se serverSession.send(message, false); - manager.getServer().getStorageManager().afterCompleteOperations(new IOAsyncTask() + manager.getServer().getStorageManager().afterCompleteOperations(new IOCallback() { @Override public void done() diff --git a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java index aa3f9e00d2..45260d57a2 100644 --- a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java +++ b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTPublishManager.java @@ -22,7 +22,7 @@ import io.netty.buffer.EmptyByteBuf; import io.netty.handler.codec.mqtt.MqttMessageType; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.server.ServerConsumer; import org.apache.activemq.artemis.core.server.ServerMessage; import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl; @@ -183,7 +183,7 @@ public class MQTTPublishManager private void createMessageAck(final int messageId, final int qos) { - session.getServer().getStorageManager().afterCompleteOperations(new IOAsyncTask() + session.getServer().getStorageManager().afterCompleteOperations(new IOCallback() { @Override public void done() diff --git a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java index d2459856cc..fcdff057a4 100644 --- a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java +++ b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java @@ -36,6 +36,7 @@ import org.apache.activemq.artemis.api.core.BaseInterceptor; import org.apache.activemq.artemis.api.core.Interceptor; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.management.CoreNotificationType; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQConsumer; import org.apache.activemq.artemis.core.server.management.ManagementService; @@ -62,7 +63,6 @@ import org.apache.activemq.command.TransactionId; import org.apache.activemq.command.TransactionInfo; import org.apache.activemq.command.WireFormatInfo; import org.apache.activemq.command.XATransactionId; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQConnectionContext; import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQPersistenceAdapter; import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQProducerBrokerExchange; @@ -261,7 +261,7 @@ public class OpenWireProtocolManager implements ProtocolManager, No public void sendReply(final OpenWireConnection connection, final Command command) { - server.getStorageManager().afterCompleteOperations(new IOAsyncTask() + server.getStorageManager().afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java index a4e8ea565c..b3d926ccab 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java @@ -33,7 +33,7 @@ import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.client.ActiveMQClient; import org.apache.activemq.artemis.api.core.management.CoreNotificationType; import org.apache.activemq.artemis.api.core.management.ManagementHelper; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.postoffice.BindingType; import org.apache.activemq.artemis.core.remoting.impl.netty.NettyServerConnection; import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants; @@ -357,7 +357,7 @@ class StompProtocolManager implements ProtocolManager, No public void sendReply(final StompConnection connection, final StompFrame frame) { - server.getStorageManager().afterCompleteOperations(new IOAsyncTask() + server.getStorageManager().afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java index 8efeabbdf4..c1b767a66a 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java @@ -41,7 +41,7 @@ import org.apache.activemq.artemis.core.config.ha.SharedStoreMasterPolicyConfigu import org.apache.activemq.artemis.core.config.ha.SharedStoreSlavePolicyConfiguration; import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; import org.apache.activemq.artemis.core.config.impl.Validators; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalConstants; import org.apache.activemq.artemis.core.security.Role; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingManager.java index ee3bb8687a..8e06cdecf7 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingManager.java @@ -26,7 +26,7 @@ import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeLis *

  *
  * +--------------+      1  +----------------+       N +--------------+       N +--------+       1 +-------------------+
- * | {@link org.apache.activemq.artemis.core.postoffice.PostOffice} |-------> |{@link PagingManager}|-------> |{@link PagingStore} | ------> | {@link org.apache.activemq.artemis.core.paging.impl.Page}  | ------> | {@link org.apache.activemq.artemis.core.journal.SequentialFile} |
+ * | {@link org.apache.activemq.artemis.core.postoffice.PostOffice} |-------> |{@link PagingManager}|-------> |{@link PagingStore} | ------> | {@link org.apache.activemq.artemis.core.paging.impl.Page}  | ------> | {@link SequentialFile} |
  * +--------------+         +----------------+         +--------------+         +--------+         +-------------------+
  *                                                              |                  1 ^
  *                                                              |                    |
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStore.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStore.java
index 3b74e45aca..b0129e79bd 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStore.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStore.java
@@ -158,7 +158,7 @@ public interface PagingStore extends ActiveMQComponent
    /**
     * Sends the pages with given IDs to the {@link ReplicationManager}.
     * 

- * Sending is done here to avoid exposing the internal {@link org.apache.activemq.artemis.core.journal.SequentialFile}s. + * Sending is done here to avoid exposing the internal {@link SequentialFile}s. * * @param replicator * @param pageIds diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStoreFactory.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStoreFactory.java index f83966dc4a..08180342f6 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStoreFactory.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/PagingStoreFactory.java @@ -19,7 +19,7 @@ package org.apache.activemq.artemis.core.paging; import java.util.List; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.settings.HierarchicalRepository; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/cursor/impl/PageSubscriptionImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/cursor/impl/PageSubscriptionImpl.java index 39324dad02..e98da75183 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/cursor/impl/PageSubscriptionImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/cursor/impl/PageSubscriptionImpl.java @@ -32,8 +32,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.filter.Filter; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagingStore; @@ -521,7 +521,7 @@ final class PageSubscriptionImpl implements PageSubscription store.storeCursorAcknowledge(cursorId, position); } - store.afterCompleteOperations(new IOAsyncTask() + store.afterCompleteOperations(new IOCallback() { volatile String error = ""; @@ -541,7 +541,7 @@ final class PageSubscriptionImpl implements PageSubscription @Override public String toString() { - return IOAsyncTask.class.getSimpleName() + "(" + PageSubscriptionImpl.class.getSimpleName() + ") " + error; + return IOCallback.class.getSimpleName() + "(" + PageSubscriptionImpl.class.getSimpleName() + ") " + error; } }); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/Page.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/Page.java index 24d60df67d..ae41bb0b1f 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/Page.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/Page.java @@ -25,8 +25,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.cursor.LivePageCache; import org.apache.activemq.artemis.core.paging.cursor.PageSubscriptionCounter; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryNIO.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryNIO.java index 3a12b96047..63681f2f61 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryNIO.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreFactoryNIO.java @@ -29,9 +29,9 @@ import java.util.List; import java.util.concurrent.ScheduledExecutorService; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.PagingManager; import org.apache.activemq.artemis.core.paging.PagingStore; import org.apache.activemq.artemis.core.paging.PagingStoreFactory; @@ -208,6 +208,6 @@ public class PagingStoreFactoryNIO implements PagingStoreFactory private SequentialFileFactory newFileFactory(final String directoryName) { - return new NIOSequentialFileFactory(new File(directory, directoryName), false, critialErrorListener); + return new NIOSequentialFileFactory(new File(directory, directoryName), false, critialErrorListener, 1); } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreImpl.java index 3b0a139fb7..6b67f3e863 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/paging/impl/PagingStoreImpl.java @@ -37,8 +37,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagingManager; @@ -576,7 +576,7 @@ public class PagingStoreImpl implements PagingStore public boolean checkPageFileExists(final int pageNumber) { String fileName = createFileName(pageNumber); - SequentialFile file = fileFactory.createSequentialFile(fileName, 1); + SequentialFile file = fileFactory.createSequentialFile(fileName); return file.exists(); } @@ -589,7 +589,7 @@ public class PagingStoreImpl implements PagingStore fileFactory = storeFactory.newFileFactory(getStoreName()); } - SequentialFile file = fileFactory.createSequentialFile(fileName, 1000); + SequentialFile file = fileFactory.createSequentialFile(fileName); Page page = new Page(storeName, storageManager, fileFactory, file, pageNumber); @@ -1227,7 +1227,7 @@ public class PagingStoreImpl implements PagingStore { for (Integer id : pageIds) { - SequentialFile sFile = fileFactory.createSequentialFile(createFileName(id), 1); + SequentialFile sFile = fileFactory.createSequentialFile(createFileName(id)); if (!sFile.exists()) { continue; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/OperationContext.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/OperationContext.java index 2e1dd7329d..d13f311b28 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/OperationContext.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/OperationContext.java @@ -16,7 +16,7 @@ */ package org.apache.activemq.artemis.core.persistence; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.IOCompletion; /** @@ -28,7 +28,7 @@ public interface OperationContext extends IOCompletion { /** Execute the task when all IO operations are complete, * Or execute it immediately if nothing is pending. */ - void executeOnCompletion(IOAsyncTask runnable); + void executeOnCompletion(IOCallback runnable); void replicationLineUp(); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/StorageManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/StorageManager.java index 5196cccef9..7cf811249e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/StorageManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/StorageManager.java @@ -25,10 +25,10 @@ import java.util.concurrent.Executor; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.message.impl.MessageInternal; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; @@ -99,7 +99,7 @@ public interface StorageManager extends IDGenerator, ActiveMQComponent void pageWrite(PagedMessage message, int pageNumber); - void afterCompleteOperations(IOAsyncTask run); + void afterCompleteOperations(IOCallback run); /** * Block until the operations are done. diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/DescribeJournal.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/DescribeJournal.java index 3c251642e8..210877c9d5 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/DescribeJournal.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/DescribeJournal.java @@ -31,12 +31,12 @@ import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; import org.apache.activemq.artemis.core.journal.EncodingSupport; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.core.journal.impl.JournalReaderCallback; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.cursor.impl.PageSubscriptionCounterImpl; import org.apache.activemq.artemis.core.paging.impl.PageTransactionInfoImpl; import org.apache.activemq.artemis.core.persistence.impl.journal.BatchingIDGenerator.IDCounterEncoding; @@ -109,7 +109,7 @@ public final class DescribeJournal public static void describeBindingsJournal(final File bindingsDir) throws Exception { - SequentialFileFactory bindingsFF = new NIOSequentialFileFactory(bindingsDir, null); + SequentialFileFactory bindingsFF = new NIOSequentialFileFactory(bindingsDir, null, 1); JournalImpl bindings = new JournalImpl(1024 * 1024, 2, -1, 0, bindingsFF, "activemq-bindings", "bindings", 1); describeJournal(bindingsFF, bindings, bindingsDir); @@ -118,7 +118,7 @@ public final class DescribeJournal public static DescribeJournal describeMessagesJournal(final File messagesDir) throws Exception { - SequentialFileFactory messagesFF = new NIOSequentialFileFactory(messagesDir, null); + SequentialFileFactory messagesFF = new NIOSequentialFileFactory(messagesDir, null, 1); // Will use only default values. The load function should adapt to anything different ConfigurationImpl defaultValues = new ConfigurationImpl(); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JournalStorageManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JournalStorageManager.java index 5104b6861c..33a1cbecd0 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JournalStorageManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/JournalStorageManager.java @@ -53,22 +53,22 @@ import org.apache.activemq.artemis.api.core.ActiveMQInternalErrorException; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.filter.Filter; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.message.impl.MessageInternal; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; @@ -236,7 +236,9 @@ public class JournalStorageManager implements StorageManager } - SequentialFileFactory bindingsFF = new NIOSequentialFileFactory(config.getBindingsLocation(), criticalErrorListener); + SequentialFileFactory bindingsFF = new NIOSequentialFileFactory(config.getBindingsLocation(), + criticalErrorListener, + config.getJournalMaxIO_NIO()); Journal localBindings = new JournalImpl(1024 * 1024, 2, @@ -261,6 +263,7 @@ public class JournalStorageManager implements StorageManager journalFF = new AIOSequentialFileFactory(config.getJournalLocation(), config.getJournalBufferSize_AIO(), config.getJournalBufferTimeout_AIO(), + config.getJournalMaxIO_AIO(), config.isLogJournalWriteRate(), criticalErrorListener); } @@ -271,6 +274,7 @@ public class JournalStorageManager implements StorageManager true, config.getJournalBufferSize_NIO(), config.getJournalBufferTimeout_NIO(), + config.getJournalMaxIO_NIO(), config.isLogJournalWriteRate(), criticalErrorListener); } @@ -296,7 +300,8 @@ public class JournalStorageManager implements StorageManager largeMessagesDirectory = config.getLargeMessagesDirectory(); - largeMessagesFactory = new NIOSequentialFileFactory(config.getLargeMessagesLocation(), false, criticalErrorListener); + largeMessagesFactory = new NIOSequentialFileFactory(config.getLargeMessagesLocation(), false, criticalErrorListener, + 1); perfBlastPages = config.getJournalPerfBlastPages(); @@ -572,7 +577,7 @@ public class JournalStorageManager implements StorageManager String fileName = entry.getValue().getA(); final long id = entry.getKey(); long size = entry.getValue().getB(); - SequentialFile seqFile = largeMessagesFactory.createSequentialFile(fileName, 1); + SequentialFile seqFile = largeMessagesFactory.createSequentialFile(fileName); if (!seqFile.exists()) continue; replicator.syncLargeMessageFile(seqFile, size, id); @@ -608,7 +613,7 @@ public class JournalStorageManager implements StorageManager if (!largeMessagesToDelete.contains(id)) { idList.add(id); - SequentialFile seqFile = largeMessagesFactory.createSequentialFile(filename, 1); + SequentialFile seqFile = largeMessagesFactory.createSequentialFile(filename); long size = seqFile.size(); largeMessages.put(id, new Pair(filename, size)); } @@ -747,7 +752,7 @@ public class JournalStorageManager implements StorageManager return new OperationContextImpl(executor1); } - public void afterCompleteOperations(final IOAsyncTask run) + public void afterCompleteOperations(final IOCallback run) { getContext().executeOnCompletion(run); } @@ -2498,7 +2503,7 @@ public class JournalStorageManager implements StorageManager public SequentialFile createFileForLargeMessage(final long messageID, LargeMessageExtension extension) { - return largeMessagesFactory.createSequentialFile(messageID + extension.getExtension(), -1); + return largeMessagesFactory.createSequentialFile(messageID + extension.getExtension()); } @@ -2788,7 +2793,7 @@ public class JournalStorageManager implements StorageManager List tmpFiles = largeMessagesFactory.listFiles("tmp"); for (String tmpFile : tmpFiles) { - SequentialFile file = largeMessagesFactory.createSequentialFile(tmpFile, -1); + SequentialFile file = largeMessagesFactory.createSequentialFile(tmpFile); file.delete(); } } @@ -2830,7 +2835,7 @@ public class JournalStorageManager implements StorageManager return DummyOperationContext.instance; } - public void executeOnCompletion(final IOAsyncTask runnable) + public void executeOnCompletion(final IOCallback runnable) { // There are no executeOnCompletion calls while using the DummyOperationContext // However we keep the code here for correctness diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageImpl.java index dc09160b38..c4aa058cfe 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageImpl.java @@ -24,7 +24,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; import org.apache.activemq.artemis.api.core.ActiveMQInternalErrorException; import org.apache.activemq.artemis.api.core.Message; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.message.BodyEncoder; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; import org.apache.activemq.artemis.core.server.LargeServerMessage; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageInSync.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageInSync.java index 76a86535e7..b034660424 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageInSync.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/LargeServerMessageInSync.java @@ -20,7 +20,7 @@ import java.nio.ByteBuffer; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.Message; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.persistence.StorageManager.LargeMessageExtension; import org.apache.activemq.artemis.core.replication.ReplicatedLargeMessage; @@ -62,7 +62,7 @@ public final class LargeServerMessageInSync implements ReplicatedLargeMessage buffer.rewind(); int bytesRead = appendFile.read(buffer); if (bytesRead > 0) - mainSeqFile.writeInternal(buffer); + mainSeqFile.writeDirect(buffer, false); if (bytesRead < buffer.capacity()) { break; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/OperationContextImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/OperationContextImpl.java index 32eca2645f..a8e8e2a96b 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/OperationContextImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/journal/OperationContextImpl.java @@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.impl.SimpleWaitIOCallback; import org.apache.activemq.artemis.core.persistence.OperationContext; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; @@ -134,7 +134,7 @@ public class OperationContextImpl implements OperationContext checkTasks(); } - public void executeOnCompletion(final IOAsyncTask completion) + public void executeOnCompletion(final IOCallback completion) { if (errorCode != -1) { @@ -219,7 +219,7 @@ public class OperationContextImpl implements OperationContext /** * @param task */ - private void execute(final IOAsyncTask task) + private void execute(final IOCallback task) { executorsPending.incrementAndGet(); try @@ -243,7 +243,7 @@ public class OperationContextImpl implements OperationContext } catch (Throwable e) { - ActiveMQServerLogger.LOGGER.errorExecutingIOAsyncTask(e); + ActiveMQServerLogger.LOGGER.errorExecutingAIOCallback(e); executorsPending.decrementAndGet(); task.onError(ActiveMQExceptionType.INTERNAL_ERROR.getCode(), "It wasn't possible to complete IO operation - " + e.getMessage()); @@ -296,9 +296,9 @@ public class OperationContextImpl implements OperationContext final int replicationLined; final int pageLined; - final IOAsyncTask task; + final IOCallback task; - TaskHolder(final IOAsyncTask task) + TaskHolder(final IOCallback task) { storeLined = storeLineUp.intValue(); replicationLined = replicationLineUp.intValue(); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageLargeServerMessage.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageLargeServerMessage.java index 303e2571a2..25cd0fc593 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageLargeServerMessage.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageLargeServerMessage.java @@ -17,7 +17,7 @@ package org.apache.activemq.artemis.core.persistence.impl.nullpm; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.server.LargeServerMessage; import org.apache.activemq.artemis.core.server.ServerMessage; import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageManager.java index ade2173796..d6336d299a 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/impl/nullpm/NullStorageManager.java @@ -27,10 +27,10 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.message.impl.MessageInternal; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; @@ -112,7 +112,7 @@ public class NullStorageManager implements StorageManager } @Override - public void executeOnCompletion(final IOAsyncTask runnable) + public void executeOnCompletion(final IOCallback runnable) { runnable.done(); } @@ -359,7 +359,7 @@ public class NullStorageManager implements StorageManager } @Override - public void afterCompleteOperations(final IOAsyncTask run) + public void afterCompleteOperations(final IOCallback run) { run.done(); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java index 12bf669038..71a2458ae7 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/PostOfficeImpl.java @@ -41,8 +41,8 @@ import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.management.CoreNotificationType; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.api.core.management.NotificationType; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.filter.Filter; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.message.impl.MessageImpl; import org.apache.activemq.artemis.core.paging.PagingManager; import org.apache.activemq.artemis.core.paging.PagingStore; @@ -1179,7 +1179,7 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding { // This will use the same thread if there are no pending operations // avoiding a context switch on this case - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { @@ -1249,7 +1249,7 @@ public class PostOfficeImpl implements PostOffice, NotificationListener, Binding queues.addAll(durableQueues); queues.addAll(nonDurableQueues); - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(int errorCode, String errorMessage) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/ServerSessionPacketHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/ServerSessionPacketHandler.java index 109d4fd551..a39950edea 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/ServerSessionPacketHandler.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/protocol/core/ServerSessionPacketHandler.java @@ -58,8 +58,8 @@ import javax.transaction.xa.Xid; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; import org.apache.activemq.artemis.api.core.ActiveMQInternalErrorException; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.exception.ActiveMQXAException; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl; import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.CreateQueueMessage; @@ -614,7 +614,7 @@ public class ServerSessionPacketHandler implements ChannelHandler final boolean flush, final boolean closeChannel) { - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicatedJournal.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicatedJournal.java index 2723198d5d..d96dbe187e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicatedJournal.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicatedJournal.java @@ -26,7 +26,7 @@ import org.apache.activemq.artemis.core.journal.JournalLoadInformation; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.dataformat.ByteArrayEncoding; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationEndpoint.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationEndpoint.java index ec16825b86..afb1e77f97 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationEndpoint.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationEndpoint.java @@ -34,11 +34,11 @@ import java.util.concurrent.TimeUnit; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.config.Configuration; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.Journal.JournalState; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.journal.impl.FileWrapperJournal; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.paging.PagedMessage; @@ -546,7 +546,7 @@ public final class ReplicationEndpoint implements ChannelHandler, ActiveMQCompon if (!channel1.isOpen()) { - channel1.open(1, false); + channel1.open(); } channel1.writeDirect(ByteBuffer.wrap(data), true); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationManager.java index a2f39c967f..905d7a57d3 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/replication/ReplicationManager.java @@ -33,7 +33,7 @@ import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.client.SessionFailureListener; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.persistence.OperationContext; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java index b136990600..11e6f6198c 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java @@ -43,10 +43,10 @@ import io.netty.channel.Channel; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.client.impl.ServerLocatorInternal; import org.apache.activemq.artemis.core.config.Configuration; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.paging.cursor.PagePosition; import org.apache.activemq.artemis.core.paging.cursor.PageSubscription; @@ -522,8 +522,8 @@ public interface ActiveMQServerLogger extends BasicLogger void lareMessageErrorCopying(@Cause Exception e, LargeServerMessage largeServerMessage); @LogMessage(level = Logger.Level.WARN) - @Message(id = 222054, value = "Error on executing IOAsyncTask", format = Message.Format.MESSAGE_FORMAT) - void errorExecutingIOAsyncTask(@Cause Throwable t); + @Message(id = 222054, value = "Error on executing IOCallback", format = Message.Format.MESSAGE_FORMAT) + void errorExecutingAIOCallback(@Cause Throwable t); @LogMessage(level = Logger.Level.WARN) @Message(id = 222055, value = "Error on deleting duplicate cache", format = Message.Format.MESSAGE_FORMAT) @@ -1200,7 +1200,7 @@ public interface ActiveMQServerLogger extends BasicLogger @LogMessage(level = Logger.Level.ERROR) @Message(id = 224007, value = "page subscription = {0} error={1}", format = Message.Format.MESSAGE_FORMAT) - void pageSubscriptionError(IOAsyncTask ioAsyncTask, String error); + void pageSubscriptionError(IOCallback IOCallback, String error); @LogMessage(level = Logger.Level.ERROR) @Message(id = 224008, value = "Failed to store id", format = Message.Format.MESSAGE_FORMAT) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/LargeServerMessage.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/LargeServerMessage.java index 57120ffa9d..e22a172dc9 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/LargeServerMessage.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/LargeServerMessage.java @@ -17,7 +17,7 @@ package org.apache.activemq.artemis.core.server; import org.apache.activemq.artemis.api.core.ActiveMQException; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.replication.ReplicatedLargeMessage; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/cluster/impl/Redistributor.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/cluster/impl/Redistributor.java index 3c0ba4167e..106158cb10 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/cluster/impl/Redistributor.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/cluster/impl/Redistributor.java @@ -22,8 +22,8 @@ import java.util.concurrent.Executor; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.Pair; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.filter.Filter; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.postoffice.PostOffice; import org.apache.activemq.artemis.core.server.Consumer; @@ -247,7 +247,7 @@ public class Redistributor implements Consumer tx.commit(); - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/AIOFileLockNodeManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/AIOFileLockNodeManager.java index 7adee2e28b..2d0f3c0d0e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/AIOFileLockNodeManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/AIOFileLockNodeManager.java @@ -17,10 +17,11 @@ package org.apache.activemq.artemis.core.server.impl; import java.io.File; -import java.io.IOException; import java.nio.channels.FileLock; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; +import org.apache.activemq.artemis.core.io.aio.ActiveMQFileLock; +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.jlibaio.LibaioFile; /** * This is using the ActiveMQ Artemis Libaio Native to perform calls to flock on a Linux system. At the @@ -56,19 +57,15 @@ public final class AIOFileLockNodeManager extends FileLockNodeManager { File file = newFileForRegionLock(lockPos); - int handle = AsynchronousFileImpl.openFile(file.getAbsolutePath()); + LibaioFile fileControl = LibaioContext.openControlFile(file.getAbsolutePath(), false); - if (handle < 0) + if (!fileControl.lock()) { - throw new IOException("couldn't open file " + file.getAbsolutePath()); + fileControl.close(); + return null; } - FileLock lock = AsynchronousFileImpl.lock(handle); - - if (lock == null) - { - AsynchronousFileImpl.closeFile(handle); - } + FileLock lock = new ActiveMQFileLock(fileControl); return lock; @@ -83,21 +80,13 @@ public final class AIOFileLockNodeManager extends FileLockNodeManager while (!interrupted) { - int handle = AsynchronousFileImpl.openFile(file.getAbsolutePath()); - - if (handle < 0) - { - throw new IOException("couldn't open file " + file.getAbsolutePath()); - } - - FileLock lockFile = AsynchronousFileImpl.lock(handle); + FileLock lockFile = tryLock(liveLockPos); if (lockFile != null) { return lockFile; } else { - AsynchronousFileImpl.closeFile(handle); try { Thread.sleep(500); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java index 0dc85de41b..9d7e95baed 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java @@ -19,7 +19,6 @@ package org.apache.activemq.artemis.core.server.impl; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl; import org.apache.activemq.artemis.core.config.BridgeConfiguration; import org.apache.activemq.artemis.core.config.Configuration; @@ -29,11 +28,10 @@ import org.apache.activemq.artemis.core.config.DivertConfiguration; import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; import org.apache.activemq.artemis.core.filter.Filter; import org.apache.activemq.artemis.core.filter.impl.FilterImpl; -import org.apache.activemq.artemis.core.journal.IOCriticalErrorListener; +import org.apache.activemq.artemis.core.io.IOCriticalErrorListener; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.SyncSpeedTest; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.management.impl.ActiveMQServerControlImpl; import org.apache.activemq.artemis.core.paging.PagingManager; import org.apache.activemq.artemis.core.paging.cursor.PageSubscription; @@ -96,6 +94,7 @@ import org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings; import org.apache.activemq.artemis.core.transaction.ResourceManager; import org.apache.activemq.artemis.core.transaction.impl.ResourceManagerImpl; import org.apache.activemq.artemis.core.version.Version; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.spi.core.protocol.SessionCallback; @@ -359,7 +358,7 @@ public class ActiveMQServerImpl implements ActiveMQServer { manager = new InVMNodeManager(replicatingBackup); } - else if (configuration.getJournalType() == JournalType.ASYNCIO && AsynchronousFileImpl.isLoaded()) + else if (configuration.getJournalType() == JournalType.ASYNCIO && LibaioContext.isLoaded()) { manager = new AIOFileLockNodeManager(directory, replicatingBackup, configuration.getJournalLockAcquisitionTimeout()); } @@ -401,13 +400,6 @@ public class ActiveMQServerImpl implements ActiveMQServer ActiveMQServerLogger.LOGGER.serverStarting((haPolicy.isBackup() ? "backup" : "live"), configuration); - if (configuration.isRunSyncSpeedTest()) - { - SyncSpeedTest test = new SyncSpeedTest(); - - test.run(); - } - final boolean wasLive = !haPolicy.isBackup(); if (!haPolicy.isBackup()) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/QueueImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/QueueImpl.java index 29a45090e9..92cdbf9e3d 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/QueueImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/QueueImpl.java @@ -45,8 +45,8 @@ import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.management.CoreNotificationType; import org.apache.activemq.artemis.api.core.management.ManagementHelper; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.filter.Filter; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.message.impl.MessageImpl; import org.apache.activemq.artemis.core.paging.cursor.PageSubscription; import org.apache.activemq.artemis.core.paging.cursor.PagedReference; @@ -2524,7 +2524,7 @@ public class QueueImpl implements Queue acknowledge(tx, ref); - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java index 98b6bb7022..49a39261bb 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java @@ -39,11 +39,11 @@ import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.management.CoreNotificationType; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.api.core.management.ResourceNames; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.client.impl.ClientMessageImpl; import org.apache.activemq.artemis.core.exception.ActiveMQXAException; import org.apache.activemq.artemis.core.filter.Filter; import org.apache.activemq.artemis.core.filter.impl.FilterImpl; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.message.impl.MessageInternal; import org.apache.activemq.artemis.core.paging.PagingStore; import org.apache.activemq.artemis.core.persistence.OperationContext; @@ -1395,7 +1395,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener public void close(final boolean failed) { if (closed) return; - context.executeOnCompletion(new IOAsyncTask() + context.executeOnCompletion(new IOCallback() { public void onError(int errorCode, String errorMessage) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java index 42aab20303..357ce6f607 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/transaction/impl/TransactionImpl.java @@ -23,7 +23,7 @@ import java.util.Date; import java.util.List; import org.apache.activemq.artemis.api.core.ActiveMQException; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; import org.apache.activemq.artemis.core.server.Queue; @@ -197,7 +197,7 @@ public class TransactionImpl implements Transaction // We use the Callback even for non persistence // If we are using non-persistence with replication, the replication manager will have // to execute this runnable in the correct order - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) @@ -266,7 +266,7 @@ public class TransactionImpl implements Transaction // to execute this runnable in the correct order // This also will only use a different thread if there are any IO pending. // If the IO finished early by the time we got here, we won't need an executor - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) @@ -323,7 +323,7 @@ public class TransactionImpl implements Transaction // We use the Callback even for non persistence // If we are using non-persistence with replication, the replication manager will have // to execute this runnable in the correct order - storageManager.afterCompleteOperations(new IOAsyncTask() + storageManager.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java index 26e9bb529f..4142f1f46a 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java @@ -67,7 +67,6 @@ import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ServerLocator; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl; import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal; import org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl; @@ -78,11 +77,11 @@ import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.core.journal.impl.JournalReaderCallback; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.PagingStore; import org.apache.activemq.artemis.core.persistence.impl.journal.OperationContextImpl; import org.apache.activemq.artemis.core.postoffice.Binding; @@ -117,6 +116,7 @@ import org.apache.activemq.artemis.core.server.impl.SharedNothingBackupActivatio import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.core.transaction.impl.XidImpl; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManagerImpl; import org.apache.activemq.artemis.utils.OrderedExecutorFactory; @@ -574,7 +574,7 @@ public abstract class ActiveMQTestBase extends Assert public static JournalType getDefaultJournalType() { - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { return JournalType.ASYNCIO; } @@ -1894,7 +1894,7 @@ public abstract class ActiveMQTestBase extends Assert JournalImpl messagesJournal = null; try { - SequentialFileFactory messagesFF = new NIOSequentialFileFactory(new File(getJournalDir()), null); + SequentialFileFactory messagesFF = new NIOSequentialFileFactory(new File(getJournalDir()), null, 1); messagesJournal = new JournalImpl(config.getJournalFileSize(), config.getJournalMinFiles(), @@ -1940,7 +1940,7 @@ public abstract class ActiveMQTestBase extends Assert protected HashMap countJournal(Configuration config) throws Exception { final HashMap recordsType = new HashMap(); - SequentialFileFactory messagesFF = new NIOSequentialFileFactory(config.getJournalLocation(), null); + SequentialFileFactory messagesFF = new NIOSequentialFileFactory(config.getJournalLocation(), null, 1); JournalImpl messagesJournal = new JournalImpl(config.getJournalFileSize(), config.getJournalMinFiles(), @@ -1988,7 +1988,7 @@ public abstract class ActiveMQTestBase extends Assert if (messageJournal) { - ff = new NIOSequentialFileFactory(config.getJournalLocation(), null); + ff = new NIOSequentialFileFactory(config.getJournalLocation(), null, 1); journal = new JournalImpl(config.getJournalFileSize(), config.getJournalMinFiles(), 0, @@ -2000,7 +2000,7 @@ public abstract class ActiveMQTestBase extends Assert } else { - ff = new NIOSequentialFileFactory(config.getBindingsLocation(), null); + ff = new NIOSequentialFileFactory(config.getBindingsLocation(), null, 1); journal = new JournalImpl(1024 * 1024, 2, config.getJournalCompactMinFiles(), @@ -2403,31 +2403,31 @@ public abstract class ActiveMQTestBase extends Assert long timeout = System.currentTimeMillis() + 15000; - while (AsynchronousFileImpl.getTotalMaxIO() != 0 && System.currentTimeMillis() > timeout) - { - try - { - Thread.sleep(100); - } - catch (Exception ignored) - { - } - } - - int invmSize = InVMRegistry.instance.size(); - if (invmSize > 0) - { - InVMRegistry.instance.clear(); - log.info(threadDump("Thread dump")); - fail("invm registry still had acceptors registered"); - } - - final int totalMaxIO = AsynchronousFileImpl.getTotalMaxIO(); - if (totalMaxIO != 0) - { - AsynchronousFileImpl.resetMaxAIO(); - Assert.fail("test did not close all its files " + totalMaxIO); - } +// while (AsynchronousFileImpl.getTotalMaxIO() != 0 && System.currentTimeMillis() > timeout) +// { +// try +// { +// Thread.sleep(100); +// } +// catch (Exception ignored) +// { +// } +// } +// +// int invmSize = InVMRegistry.instance.size(); +// if (invmSize > 0) +// { +// InVMRegistry.instance.clear(); +// log.info(threadDump("Thread dump")); +// fail("invm registry still had acceptors registered"); +// } +// +// final int totalMaxIO = AsynchronousFileImpl.getTotalMaxIO(); +// if (totalMaxIO != 0) +// { +// AsynchronousFileImpl.resetMaxAIO(); +// Assert.fail("test did not close all its files " + totalMaxIO); +// } } private void cleanupPools() diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ColocatedActiveMQServer.java b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ColocatedActiveMQServer.java index 4f9dd48833..845c9da3b5 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ColocatedActiveMQServer.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ColocatedActiveMQServer.java @@ -17,18 +17,17 @@ package org.apache.activemq.artemis.tests.util; import javax.management.MBeanServer; - import java.io.File; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.impl.FileConfiguration; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.JournalType; import org.apache.activemq.artemis.core.server.NodeManager; import org.apache.activemq.artemis.core.server.impl.AIOFileLockNodeManager; -import org.apache.activemq.artemis.core.server.impl.FileLockNodeManager; import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl; +import org.apache.activemq.artemis.core.server.impl.FileLockNodeManager; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager; @@ -69,7 +68,7 @@ public class ColocatedActiveMQServer extends ActiveMQServerImpl if (replicatingBackup) { NodeManager manager; - if (getConfiguration().getJournalType() == JournalType.ASYNCIO && AsynchronousFileImpl.isLoaded()) + if (getConfiguration().getJournalType() == JournalType.ASYNCIO && LibaioContext.isLoaded()) { return new AIOFileLockNodeManager(directory, replicatingBackup, getConfiguration().getJournalLockAcquisitionTimeout()); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java index a6bce80e46..4332fbda7a 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/HangConsumerTest.java @@ -37,9 +37,9 @@ import org.apache.activemq.artemis.api.core.client.ServerLocator; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.filter.Filter; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.cursor.PageSubscription; import org.apache.activemq.artemis.core.persistence.OperationContext; import org.apache.activemq.artemis.core.persistence.StorageManager; @@ -480,7 +480,7 @@ public class HangConsumerTest extends ActiveMQTestBase server.stop(); - SequentialFileFactory messagesFF = new NIOSequentialFileFactory(server.getConfiguration().getBindingsLocation(), null); + SequentialFileFactory messagesFF = new NIOSequentialFileFactory(server.getConfiguration().getBindingsLocation(), null, 1); JournalImpl messagesJournal = new JournalImpl(1024 * 1024, 2, diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/JournalCrashTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/JournalCrashTest.java index e71189fa99..cbc2904dc0 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/JournalCrashTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/JournalCrashTest.java @@ -33,7 +33,7 @@ import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; @@ -221,7 +221,7 @@ public class JournalCrashTest extends ActiveMQTestBase */ private void printJournal() throws Exception { - NIOSequentialFileFactory factory = new NIOSequentialFileFactory(new File(getJournalDir())); + NIOSequentialFileFactory factory = new NIOSequentialFileFactory(new File(getJournalDir()), 100); JournalImpl journal = new JournalImpl(ActiveMQDefaultConfiguration.getDefaultJournalFileSize(), 2, 0, diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LibaioDependencyCheckTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LibaioDependencyCheckTest.java index 4e6191e38d..9044b286a4 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LibaioDependencyCheckTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/LibaioDependencyCheckTest.java @@ -16,9 +16,9 @@ */ package org.apache.activemq.artemis.tests.integration.client; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.junit.Test; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; /** @@ -45,7 +45,7 @@ public class LibaioDependencyCheckTest extends ActiveMQTestBase { if (System.getProperties().get("os.name").equals("Linux")) { - assertTrue("Libaio is not available on this platform", AsynchronousFileImpl.isLoaded()); + assertTrue("Libaio is not available on this platform", LibaioContext.isLoaded()); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/PagingTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/PagingTest.java index 9d0d4d7ad6..b87063935e 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/PagingTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/PagingTest.java @@ -46,15 +46,15 @@ import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.MessageHandler; import org.apache.activemq.artemis.api.core.client.ServerLocator; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.client.impl.ClientConsumerInternal; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.DivertConfiguration; import org.apache.activemq.artemis.core.filter.Filter; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagingManager; import org.apache.activemq.artemis.core.paging.PagingStore; @@ -1734,7 +1734,7 @@ public class PagingTest extends ActiveMQTestBase 2, 0, 0, - new NIOSequentialFileFactory(server.getConfiguration().getJournalLocation()), + new NIOSequentialFileFactory(server.getConfiguration().getJournalLocation(), 1), "activemq-data", "amq", 1); @@ -6454,7 +6454,7 @@ public class PagingTest extends ActiveMQTestBase pageDone.countDown(); } - public void executeOnCompletion(IOAsyncTask runnable) + public void executeOnCompletion(IOCallback runnable) { } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/RedeliveryConsumerTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/RedeliveryConsumerTest.java index 460c4df6cd..dea83e66ba 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/RedeliveryConsumerTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/RedeliveryConsumerTest.java @@ -32,7 +32,7 @@ import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.persistence.impl.journal.JournalRecordIds; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger; @@ -297,7 +297,7 @@ public class RedeliveryConsumerTest extends ActiveMQTestBase 2, 0, 0, - new NIOSequentialFileFactory(server.getConfiguration().getJournalLocation()), + new NIOSequentialFileFactory(server.getConfiguration().getJournalLocation(), 1), "activemq-data", "amq", 1); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/bridge/BridgeTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/bridge/BridgeTest.java index ede895ff0a..151e2b4d5a 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/bridge/BridgeTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/bridge/BridgeTest.java @@ -45,9 +45,9 @@ import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.CoreQueueConfiguration; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.persistence.impl.journal.DescribeJournal; import org.apache.activemq.artemis.core.persistence.impl.journal.JournalRecordIds; import org.apache.activemq.artemis.core.postoffice.DuplicateIDCache; @@ -1923,7 +1923,7 @@ public class BridgeTest extends ActiveMQTestBase protected Map loadQueues(ActiveMQServer serverToInvestigate) throws Exception { SequentialFileFactory messagesFF = new NIOSequentialFileFactory(serverToInvestigate.getConfiguration() - .getJournalLocation()); + .getJournalLocation(), 1); JournalImpl messagesJournal = new JournalImpl(serverToInvestigate.getConfiguration().getJournalFileSize(), serverToInvestigate.getConfiguration().getJournalMinFiles(), diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOImportExportTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOImportExportTest.java index 2dc0d38399..e49e50b6b6 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOImportExportTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOImportExportTest.java @@ -16,8 +16,8 @@ */ package org.apache.activemq.artemis.tests.integration.journal; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.junit.BeforeClass; public class AIOImportExportTest extends NIOImportExportTest @@ -31,6 +31,6 @@ public class AIOImportExportTest extends NIOImportExportTest @Override protected SequentialFileFactory getFileFactory() throws Exception { - return new AIOSequentialFileFactory(getTestDirfile()); + return new AIOSequentialFileFactory(getTestDirfile(), 10); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalCompactTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalCompactTest.java index 39972e7088..f1ce78534a 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalCompactTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalCompactTest.java @@ -19,8 +19,8 @@ package org.apache.activemq.artemis.tests.integration.journal; import java.io.File; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalConstants; import org.junit.BeforeClass; @@ -43,7 +43,7 @@ public class AIOJournalCompactTest extends NIOJournalCompactTest return new AIOSequentialFileFactory(getTestDirfile(), JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, - 100000, + 100000, 10, false); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalImplTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalImplTest.java index acbaac4edb..59f6b95887 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalImplTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOJournalImplTest.java @@ -17,10 +17,10 @@ package org.apache.activemq.artemis.tests.integration.journal; import java.io.File; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalConstants; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestUnit; import org.junit.Assert; import org.junit.Before; @@ -48,7 +48,7 @@ public class AIOJournalImplTest extends JournalImplTestUnit public void setUp() throws Exception { super.setUp(); - if (!AsynchronousFileImpl.isLoaded()) + if (!LibaioContext.isLoaded()) { Assert.fail(String.format("libAIO is not loaded on %s %s %s", System.getProperty("os.name"), @@ -67,7 +67,7 @@ public class AIOJournalImplTest extends JournalImplTestUnit file.mkdir(); return new AIOSequentialFileFactory(getTestDirfile(), - JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, 1000000, + JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, 1000000, 10, false); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOSequentialFileFactoryTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOSequentialFileFactoryTest.java index 072c820ccc..acc65b1c72 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOSequentialFileFactoryTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/AIOSequentialFileFactoryTest.java @@ -19,9 +19,9 @@ import java.io.File; import java.nio.ByteBuffer; import org.apache.activemq.artemis.tests.unit.core.journal.impl.SequentialFileFactoryTestBase; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -38,13 +38,13 @@ public class AIOSequentialFileFactoryTest extends SequentialFileFactoryTestBase @Override protected SequentialFileFactory createFactory(String folder) { - return new AIOSequentialFileFactory(new File(folder)); + return new AIOSequentialFileFactory(new File(folder), 10); } @Test public void testBuffer() throws Exception { - SequentialFile file = factory.createSequentialFile("filtetmp.log", 10); + SequentialFile file = factory.createSequentialFile("filtetmp.log"); file.open(); ByteBuffer buff = factory.newBuffer(10); Assert.assertEquals(512, buff.limit()); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOBufferedJournalCompactTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOBufferedJournalCompactTest.java index 1a69dab929..c4b1accf3b 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOBufferedJournalCompactTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOBufferedJournalCompactTest.java @@ -19,8 +19,8 @@ package org.apache.activemq.artemis.tests.integration.journal; import java.io.File; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; public class NIOBufferedJournalCompactTest extends NIOJournalCompactTest { @@ -34,7 +34,7 @@ public class NIOBufferedJournalCompactTest extends NIOJournalCompactTest file.mkdir(); - return new NIOSequentialFileFactory(getTestDirfile(), true); + return new NIOSequentialFileFactory(getTestDirfile(), true, 1); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOImportExportTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOImportExportTest.java index d581644ed9..e50143aac7 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOImportExportTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOImportExportTest.java @@ -17,8 +17,8 @@ package org.apache.activemq.artemis.tests.integration.journal; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.SimpleEncoding; import org.junit.Test; @@ -32,7 +32,7 @@ public class NIOImportExportTest extends JournalImplTestBase @Override protected SequentialFileFactory getFileFactory() throws Exception { - return new NIOSequentialFileFactory(getTestDirfile(), true); + return new NIOSequentialFileFactory(getTestDirfile(), true, 1); } // Constants ----------------------------------------------------- diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalCompactTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalCompactTest.java index 3e42498874..c3148bb86d 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalCompactTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalCompactTest.java @@ -31,18 +31,18 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.activemq.artemis.api.core.Pair; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.config.Configuration; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.AbstractJournalUpdateTask; import org.apache.activemq.artemis.core.journal.impl.JournalCompactor; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.JournalFileImpl; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.persistence.impl.journal.JournalStorageManager; import org.apache.activemq.artemis.core.persistence.impl.journal.OperationContextImpl; import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl; @@ -72,7 +72,7 @@ public class NIOJournalCompactTest extends JournalImplTestBase for (int i = 0; i < 5; i++) { - SequentialFile file = fileFactory.createSequentialFile("file-" + i + ".tst", 1); + SequentialFile file = fileFactory.createSequentialFile("file-" + i + ".tst"); dataFiles.add(new JournalFileImpl(file, 0, JournalImpl.FORMAT_VERSION)); } @@ -80,7 +80,7 @@ public class NIOJournalCompactTest extends JournalImplTestBase for (int i = 0; i < 3; i++) { - SequentialFile file = fileFactory.createSequentialFile("file-" + i + ".tst.new", 1); + SequentialFile file = fileFactory.createSequentialFile("file-" + i + ".tst.new"); newFiles.add(new JournalFileImpl(file, 0, JournalImpl.FORMAT_VERSION)); } @@ -1825,7 +1825,7 @@ public class NIOJournalCompactTest extends JournalImplTestBase storage.commit(tx); - ctx.executeOnCompletion(new IOAsyncTask() + ctx.executeOnCompletion(new IOCallback() { public void onError(int errorCode, String errorMessage) { @@ -1939,7 +1939,7 @@ public class NIOJournalCompactTest extends JournalImplTestBase @Override protected SequentialFileFactory getFileFactory() throws Exception { - return new NIOSequentialFileFactory(getTestDirfile()); + return new NIOSequentialFileFactory(getTestDirfile(), 1); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalImplTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalImplTest.java index ad7671f643..b4ff1470bf 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalImplTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOJournalImplTest.java @@ -21,8 +21,8 @@ import java.io.File; import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger; import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestUnit; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; public class NIOJournalImplTest extends JournalImplTestUnit { @@ -39,7 +39,7 @@ public class NIOJournalImplTest extends JournalImplTestUnit file.mkdir(); - return new NIOSequentialFileFactory(getTestDirfile(), true); + return new NIOSequentialFileFactory(getTestDirfile(), true, 1); } @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONoBufferJournalImplTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONoBufferJournalImplTest.java index 059bf5919e..d82b28cd94 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONoBufferJournalImplTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONoBufferJournalImplTest.java @@ -19,8 +19,8 @@ package org.apache.activemq.artemis.tests.integration.journal; import java.io.File; import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestUnit; public class NIONoBufferJournalImplTest extends JournalImplTestUnit @@ -38,7 +38,7 @@ public class NIONoBufferJournalImplTest extends JournalImplTestUnit file.mkdir(); - return new NIOSequentialFileFactory(new File(getTestDir()), false); + return new NIOSequentialFileFactory(new File(getTestDir()), false, 1); } @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONonBufferedSequentialFileFactoryTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONonBufferedSequentialFileFactoryTest.java index 717d03ceaa..20723003b8 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONonBufferedSequentialFileFactoryTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIONonBufferedSequentialFileFactoryTest.java @@ -17,8 +17,8 @@ package org.apache.activemq.artemis.tests.integration.journal; import java.io.File; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.core.journal.impl.SequentialFileFactoryTestBase; public class NIONonBufferedSequentialFileFactoryTest extends SequentialFileFactoryTestBase @@ -27,7 +27,7 @@ public class NIONonBufferedSequentialFileFactoryTest extends SequentialFileFacto @Override protected SequentialFileFactory createFactory(String folder) { - return new NIOSequentialFileFactory(new File(folder), false); + return new NIOSequentialFileFactory(new File(folder), false, 1); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOSequentialFileFactoryTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOSequentialFileFactoryTest.java index 1ca667b9d7..bcab8e60c9 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOSequentialFileFactoryTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/NIOSequentialFileFactoryTest.java @@ -17,8 +17,8 @@ package org.apache.activemq.artemis.tests.integration.journal; import java.io.File; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.core.journal.impl.SequentialFileFactoryTestBase; public class NIOSequentialFileFactoryTest extends SequentialFileFactoryTestBase @@ -27,7 +27,7 @@ public class NIOSequentialFileFactoryTest extends SequentialFileFactoryTestBase @Override protected SequentialFileFactory createFactory(String folder) { - return new NIOSequentialFileFactory(new File(folder), true); + return new NIOSequentialFileFactory(new File(folder), true, 1); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/ValidateTransactionHealthTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/ValidateTransactionHealthTest.java index 5e8587d70c..7cebc4f3c0 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/ValidateTransactionHealthTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/journal/ValidateTransactionHealthTest.java @@ -20,17 +20,17 @@ import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.atomic.AtomicLong; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.util.SpawnedVMSupport; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalConstants; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.junit.Assert; import org.junit.Test; @@ -126,7 +126,7 @@ public class ValidateTransactionHealthTest extends ActiveMQTestBase { try { - if (type.equals("aio") && !AsynchronousFileImpl.isLoaded()) + if (type.equals("aio") && !LibaioContext.isLoaded()) { // Using System.out as this output will go towards junit report System.out.println("AIO not found, test being ignored on this platform"); @@ -381,15 +381,16 @@ public class ValidateTransactionHealthTest extends ActiveMQTestBase return new AIOSequentialFileFactory(new File(directory), JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, JournalConstants.DEFAULT_JOURNAL_BUFFER_TIMEOUT_AIO, + 10, false); } else if (factoryType.equals("nio2")) { - return new NIOSequentialFileFactory(new File(directory), true); + return new NIOSequentialFileFactory(new File(directory), true, 1); } else { - return new NIOSequentialFileFactory(new File(directory), false); + return new NIOSequentialFileFactory(new File(directory), false, 1); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java index c8f5d8baca..22c96283bb 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java @@ -16,6 +16,10 @@ */ package org.apache.activemq.artemis.tests.integration.management; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import java.util.HashMap; + import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.TransportConfiguration; import org.apache.activemq.artemis.api.core.client.ActiveMQClient; @@ -32,7 +36,6 @@ import org.apache.activemq.artemis.api.core.management.DivertControl; import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; import org.apache.activemq.artemis.api.core.management.QueueControl; import org.apache.activemq.artemis.api.core.management.RoleInfo; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.messagecounter.impl.MessageCounterManagerImpl; import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory; @@ -41,6 +44,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.core.settings.impl.SlowConsumerPolicy; import org.apache.activemq.artemis.core.transaction.impl.XidImpl; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.util.RandomUtil; import org.apache.activemq.artemis.utils.UUIDGenerator; import org.apache.activemq.artemis.utils.json.JSONArray; @@ -49,10 +53,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; -import java.util.HashMap; - public class ActiveMQServerControlTest extends ManagementTestBase { @@ -118,7 +118,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase Assert.assertEquals(conf.isJournalSyncNonTransactional(), serverControl.isJournalSyncNonTransactional()); Assert.assertEquals(conf.getJournalFileSize(), serverControl.getJournalFileSize()); Assert.assertEquals(conf.getJournalMinFiles(), serverControl.getJournalMinFiles()); - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { Assert.assertEquals(conf.getJournalMaxIO_AIO(), serverControl.getJournalMaxIO()); Assert.assertEquals(conf.getJournalBufferSize_AIO(), serverControl.getJournalBufferSize()); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/replication/ReplicationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/replication/ReplicationTest.java index 2990294663..d1f475562b 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/replication/ReplicationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/replication/ReplicationTest.java @@ -44,18 +44,18 @@ import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ServerLocator; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.config.ClusterConnectionConfiguration; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.ha.SharedStoreSlavePolicyConfiguration; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.journal.IOCompletion; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.JournalLoadInformation; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.paging.PagedMessage; @@ -377,7 +377,7 @@ public final class ReplicationTest extends ActiveMQTestBase final CountDownLatch latch = new CountDownLatch(1); - ctx.executeOnCompletion(new IOAsyncTask() + ctx.executeOnCompletion(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { @@ -402,7 +402,7 @@ public final class ReplicationTest extends ActiveMQTestBase final CountDownLatch latch2 = new CountDownLatch(1); // Adding the Task after the exception should still throw an exception - ctx.executeOnCompletion(new IOAsyncTask() + ctx.executeOnCompletion(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { @@ -426,7 +426,7 @@ public final class ReplicationTest extends ActiveMQTestBase final CountDownLatch latch3 = new CountDownLatch(1); - ctx.executeOnCompletion(new IOAsyncTask() + ctx.executeOnCompletion(new IOCallback() { public void onError(final int errorCode, final String errorMessage) { @@ -488,7 +488,7 @@ public final class ReplicationTest extends ActiveMQTestBase private void blockOnReplication(final StorageManager storage, final ReplicationManager manager1) throws Exception { final CountDownLatch latch = new CountDownLatch(1); - storage.afterCompleteOperations(new IOAsyncTask() + storage.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) @@ -518,7 +518,7 @@ public final class ReplicationTest extends ActiveMQTestBase replicatedJournal.appendPrepareRecord(1, new FakeData(), false); final CountDownLatch latch = new CountDownLatch(1); - storage.afterCompleteOperations(new IOAsyncTask() + storage.afterCompleteOperations(new IOCallback() { public void onError(final int errorCode, final String errorMessage) @@ -563,7 +563,7 @@ public final class ReplicationTest extends ActiveMQTestBase replicatedJournal.appendPrepareRecord(i, new FakeData(), false); } - ctx.executeOnCompletion(new IOAsyncTask() + ctx.executeOnCompletion(new IOCallback() { public void onError(final int errorCode, final String errorMessage) diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/FileLockTimeoutTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/FileLockTimeoutTest.java index 6f4b08d386..4797e23781 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/FileLockTimeoutTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/FileLockTimeoutTest.java @@ -21,9 +21,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.integration.IntegrationTestLogger; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.config.ha.SharedStoreMasterPolicyConfiguration; import org.apache.activemq.artemis.core.server.ActiveMQServer; @@ -53,7 +53,7 @@ public class FileLockTimeoutTest extends ActiveMQTestBase { Assert.assertTrue(String.format("libAIO is not loaded on %s %s %s", System.getProperty("os.name"), System.getProperty("os.arch"), System.getProperty("os.version")), - AsynchronousFileImpl.isLoaded() + LibaioContext.isLoaded() ); } Configuration config = super.createDefaultInVMConfig() diff --git a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/FakeJournalImplTest.java b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/FakeJournalImplTest.java index 2548b1aede..a7f42102bc 100644 --- a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/FakeJournalImplTest.java +++ b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/FakeJournalImplTest.java @@ -16,7 +16,7 @@ */ package org.apache.activemq.artemis.tests.performance.journal; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; /** diff --git a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/JournalImplTestUnit.java b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/JournalImplTestUnit.java index 11d6186092..17bf397904 100644 --- a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/JournalImplTestUnit.java +++ b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/JournalImplTestUnit.java @@ -15,22 +15,19 @@ * limitations under the License. */ package org.apache.activemq.artemis.tests.performance.journal; -import org.junit.After; - -import org.junit.Test; - import java.util.ArrayList; -import org.junit.Assert; - -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.SimpleEncoding; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; public abstract class JournalImplTestUnit extends JournalImplTestBase { @@ -42,7 +39,7 @@ public abstract class JournalImplTestUnit extends JournalImplTestBase { super.tearDown(); - Assert.assertEquals(0, AsynchronousFileImpl.getTotalMaxIO()); + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); } @Test diff --git a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplAIOTest.java b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplAIOTest.java index 7fa9e14993..a73a84182c 100644 --- a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplAIOTest.java +++ b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplAIOTest.java @@ -17,8 +17,8 @@ package org.apache.activemq.artemis.tests.performance.journal; import java.io.File; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.junit.Before; import org.junit.BeforeClass; @@ -51,7 +51,7 @@ public class RealJournalImplAIOTest extends JournalImplTestUnit file.mkdir(); - return new AIOSequentialFileFactory(getTestDirfile()); + return new AIOSequentialFileFactory(getTestDirfile(), 1); } } diff --git a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplNIOTest.java b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplNIOTest.java index 4d2fbcf604..bc0e7c2ddc 100644 --- a/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplNIOTest.java +++ b/tests/performance-tests/src/test/java/org/apache/activemq/artemis/tests/performance/journal/RealJournalImplNIOTest.java @@ -18,8 +18,8 @@ package org.apache.activemq.artemis.tests.performance.journal; import java.io.File; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; public class RealJournalImplNIOTest extends JournalImplTestUnit @@ -37,7 +37,7 @@ public class RealJournalImplNIOTest extends JournalImplTestUnit file.mkdir(); - return new NIOSequentialFileFactory(getTestDirfile()); + return new NIOSequentialFileFactory(getTestDirfile(), 1); } } diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOAllPossibilitiesCompactStressTest.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOAllPossibilitiesCompactStressTest.java index a3a9e1fe4f..eddc347c16 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOAllPossibilitiesCompactStressTest.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOAllPossibilitiesCompactStressTest.java @@ -18,8 +18,8 @@ package org.apache.activemq.artemis.tests.stress.journal; import java.io.File; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalConstants; public class AIOAllPossibilitiesCompactStressTest extends AllPossibilitiesCompactStressTest @@ -53,7 +53,7 @@ public class AIOAllPossibilitiesCompactStressTest extends AllPossibilitiesCompac return new AIOSequentialFileFactory(getTestDirfile(), JournalConstants.DEFAULT_JOURNAL_BUFFER_SIZE_AIO, - 1000000, + 1000000, 1000, false); } diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOMultiThreadCompactorStressTest.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOMultiThreadCompactorStressTest.java index 5b0765354f..b2a31292d8 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOMultiThreadCompactorStressTest.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AIOMultiThreadCompactorStressTest.java @@ -16,7 +16,7 @@ */ package org.apache.activemq.artemis.tests.stress.journal; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.server.JournalType; import org.junit.BeforeClass; diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AddAndRemoveStressTest.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AddAndRemoveStressTest.java index 83ed360e60..7abc703bff 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AddAndRemoveStressTest.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/AddAndRemoveStressTest.java @@ -23,8 +23,8 @@ import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.junit.Assert; import org.junit.Test; @@ -76,7 +76,7 @@ public class AddAndRemoveStressTest extends ActiveMQTestBase public void testInsertAndLoad() throws Exception { - SequentialFileFactory factory = new AIOSequentialFileFactory(getTestDirfile()); + SequentialFileFactory factory = new AIOSequentialFileFactory(getTestDirfile(), 1000); JournalImpl impl = new JournalImpl(10 * 1024 * 1024, AddAndRemoveStressTest.NUMBER_OF_FILES_ON_JOURNAL, 0, @@ -101,7 +101,7 @@ public class AddAndRemoveStressTest extends ActiveMQTestBase impl.stop(); - factory = new AIOSequentialFileFactory(getTestDirfile()); + factory = new AIOSequentialFileFactory(getTestDirfile(), 1000); impl = new JournalImpl(10 * 1024 * 1024, AddAndRemoveStressTest.NUMBER_OF_FILES_ON_JOURNAL, 0, @@ -127,7 +127,7 @@ public class AddAndRemoveStressTest extends ActiveMQTestBase impl.stop(); - factory = new AIOSequentialFileFactory(getTestDirfile()); + factory = new AIOSequentialFileFactory(getTestDirfile(), 1000); impl = new JournalImpl(10 * 1024 * 1024, AddAndRemoveStressTest.NUMBER_OF_FILES_ON_JOURNAL, 0, @@ -164,7 +164,7 @@ public class AddAndRemoveStressTest extends ActiveMQTestBase public void testInsertUpdateAndLoad() throws Exception { - SequentialFileFactory factory = new AIOSequentialFileFactory(getTestDirfile()); + SequentialFileFactory factory = new AIOSequentialFileFactory(getTestDirfile(), 1000); JournalImpl impl = new JournalImpl(10 * 1024 * 1024, AddAndRemoveStressTest.NUMBER_OF_FILES_ON_JOURNAL, 0, @@ -190,7 +190,7 @@ public class AddAndRemoveStressTest extends ActiveMQTestBase impl.stop(); - factory = new AIOSequentialFileFactory(getTestDirfile()); + factory = new AIOSequentialFileFactory(getTestDirfile(), 1000); impl = new JournalImpl(10 * 1024 * 1024, 10, 0, 0, factory, "amq", "amq", 1000); impl.start(); @@ -209,7 +209,7 @@ public class AddAndRemoveStressTest extends ActiveMQTestBase impl.stop(); - factory = new AIOSequentialFileFactory(getTestDirfile()); + factory = new AIOSequentialFileFactory(getTestDirfile(), 1000); impl = new JournalImpl(10 * 1024 * 1024, AddAndRemoveStressTest.NUMBER_OF_FILES_ON_JOURNAL, 0, diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/CompactingStressTest.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/CompactingStressTest.java index 60816b9a4e..49354e4b54 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/CompactingStressTest.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/CompactingStressTest.java @@ -16,6 +16,9 @@ */ package org.apache.activemq.artemis.tests.stress.journal; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.client.ClientConsumer; @@ -24,17 +27,14 @@ import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ServerLocator; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.JournalType; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; import org.junit.Test; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; - public class CompactingStressTest extends ActiveMQTestBase { @@ -69,7 +69,7 @@ public class CompactingStressTest extends ActiveMQTestBase @Test public void testCleanupAIO() throws Throwable { - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { internalTestCleanup(JournalType.ASYNCIO); } @@ -164,7 +164,7 @@ public class CompactingStressTest extends ActiveMQTestBase @Test public void testMultiProducerAndCompactAIO() throws Throwable { - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { internalTestMultiProducer(JournalType.ASYNCIO); } diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/JournalCleanupCompactStressTest.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/JournalCleanupCompactStressTest.java index 9516700f2a..3675cd8c43 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/JournalCleanupCompactStressTest.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/JournalCleanupCompactStressTest.java @@ -16,26 +16,6 @@ */ package org.apache.activemq.artemis.tests.stress.journal; -import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; -import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; -import org.apache.activemq.artemis.core.persistence.impl.journal.OperationContextImpl; -import org.apache.activemq.artemis.tests.util.RandomUtil; -import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; -import org.apache.activemq.artemis.utils.OrderedExecutorFactory; -import org.apache.activemq.artemis.utils.SimpleIDGenerator; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -52,6 +32,26 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; +import org.apache.activemq.artemis.core.journal.RecordInfo; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.journal.impl.JournalImpl; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.persistence.impl.journal.OperationContextImpl; +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; +import org.apache.activemq.artemis.tests.util.RandomUtil; +import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; +import org.apache.activemq.artemis.utils.OrderedExecutorFactory; +import org.apache.activemq.artemis.utils.SimpleIDGenerator; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + public class JournalCleanupCompactStressTest extends ActiveMQTestBase { @@ -112,14 +112,14 @@ public class JournalCleanupCompactStressTest extends ActiveMQTestBase SequentialFileFactory factory; int maxAIO; - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { - factory = new AIOSequentialFileFactory(dir); + factory = new AIOSequentialFileFactory(dir, 10); maxAIO = ActiveMQDefaultConfiguration.getDefaultJournalMaxIoAio(); } else { - factory = new NIOSequentialFileFactory(dir, true); + factory = new NIOSequentialFileFactory(dir, true, 1); maxAIO = ActiveMQDefaultConfiguration.getDefaultJournalMaxIoNio(); } @@ -380,7 +380,7 @@ public class JournalCleanupCompactStressTest extends ActiveMQTestBase } journal.appendCommitRecord(txID, true, ctx); - ctx.executeOnCompletion(new IOAsyncTask() + ctx.executeOnCompletion(new IOCallback() { public void onError(final int errorCode, final String errorMessage) @@ -493,7 +493,7 @@ public class JournalCleanupCompactStressTest extends ActiveMQTestBase } } - class DeleteTask implements IOAsyncTask + class DeleteTask implements IOCallback { final long[] ids; diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/MixupCompactorTestBase.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/MixupCompactorTestBase.java index d351fe5efe..f7edebe824 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/MixupCompactorTestBase.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/MixupCompactorTestBase.java @@ -20,9 +20,9 @@ import java.io.File; import java.io.FilenameFilter; import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.utils.ReusableLatch; import org.apache.activemq.artemis.utils.SimpleIDGenerator; import org.junit.After; @@ -241,6 +241,6 @@ public abstract class MixupCompactorTestBase extends JournalImplTestBase @Override protected SequentialFileFactory getFileFactory() throws Exception { - return new NIOSequentialFileFactory(getTestDirfile()); + return new NIOSequentialFileFactory(getTestDirfile(), 1); } } diff --git a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/NIOMultiThreadCompactorStressTest.java b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/NIOMultiThreadCompactorStressTest.java index 616c4a356e..4ad8f4ee1a 100644 --- a/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/NIOMultiThreadCompactorStressTest.java +++ b/tests/stress-tests/src/test/java/org/apache/activemq/artemis/tests/stress/journal/NIOMultiThreadCompactorStressTest.java @@ -32,14 +32,14 @@ import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ServerLocator; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.JournalType; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; import org.junit.Before; @@ -90,7 +90,7 @@ public class NIOMultiThreadCompactorStressTest extends ActiveMQTestBase internalTestProduceAndConsume(); stopServer(); - NIOSequentialFileFactory factory = new NIOSequentialFileFactory(new File(getJournalDir())); + NIOSequentialFileFactory factory = new NIOSequentialFileFactory(new File(getJournalDir()), 1); JournalImpl journal = new JournalImpl(ActiveMQDefaultConfiguration.getDefaultJournalFileSize(), 2, 0, @@ -339,7 +339,7 @@ public class NIOMultiThreadCompactorStressTest extends ActiveMQTestBase private void setupServer(JournalType journalType) throws Exception { - if (!AsynchronousFileImpl.isLoaded()) + if (!LibaioContext.isLoaded()) { journalType = JournalType.NIO; } diff --git a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/AIOJournalImplTest.java b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/AIOJournalImplTest.java index 385d604d40..717188af3c 100644 --- a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/AIOJournalImplTest.java +++ b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/AIOJournalImplTest.java @@ -18,8 +18,8 @@ package org.apache.activemq.artemis.tests.timing.core.journal.impl; import java.io.File; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; import org.junit.BeforeClass; public class AIOJournalImplTest extends JournalImplTestUnit @@ -39,7 +39,7 @@ public class AIOJournalImplTest extends JournalImplTestUnit file.mkdir(); - return new AIOSequentialFileFactory(getTestDirfile()); + return new AIOSequentialFileFactory(getTestDirfile(), 10); } } diff --git a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/FakeJournalImplTest.java b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/FakeJournalImplTest.java index 5702d9d296..9e1fb68c4f 100644 --- a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/FakeJournalImplTest.java +++ b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/FakeJournalImplTest.java @@ -17,7 +17,7 @@ package org.apache.activemq.artemis.tests.timing.core.journal.impl; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; public class FakeJournalImplTest extends JournalImplTestUnit { diff --git a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/JournalImplTestUnit.java b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/JournalImplTestUnit.java index 0eab8308dd..3ae3255922 100644 --- a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/JournalImplTestUnit.java +++ b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/JournalImplTestUnit.java @@ -15,19 +15,16 @@ * limitations under the License. */ package org.apache.activemq.artemis.tests.timing.core.journal.impl; -import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase; -import org.junit.After; - -import org.junit.Test; - import java.util.ArrayList; -import org.junit.Assert; - -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; +import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; public abstract class JournalImplTestUnit extends JournalImplTestBase { @@ -39,7 +36,7 @@ public abstract class JournalImplTestUnit extends JournalImplTestBase { super.tearDown(); - Assert.assertEquals(0, AsynchronousFileImpl.getTotalMaxIO()); + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); } @Test diff --git a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/NIOJournalImplTest.java b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/NIOJournalImplTest.java index c607493591..842ad3b8ea 100644 --- a/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/NIOJournalImplTest.java +++ b/tests/timing-tests/src/test/java/org/apache/activemq/artemis/tests/timing/core/journal/impl/NIOJournalImplTest.java @@ -18,8 +18,8 @@ package org.apache.activemq.artemis.tests.timing.core.journal.impl; import java.io.File; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; public class NIOJournalImplTest extends JournalImplTestUnit @@ -31,7 +31,7 @@ public class NIOJournalImplTest extends JournalImplTestUnit { File file = new File(getTemporaryDir()); - return new NIOSequentialFileFactory(file); + return new NIOSequentialFileFactory(file, 1); } } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AIOTestBase.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AIOTestBase.java index fc17c09f88..adfccaa605 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AIOTestBase.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AIOTestBase.java @@ -22,9 +22,10 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.artemis.api.core.ActiveMQException; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.jlibaio.LibaioContext; +import org.apache.activemq.artemis.jlibaio.LibaioFile; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.asyncio.AIOCallback; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -37,25 +38,24 @@ public abstract class AIOTestBase extends ActiveMQTestBase // The AIO Test must use a local filesystem. Sometimes $HOME is on a NFS on // most enterprise systems - protected String fileName; + protected String fileName = "fileUsedOnNativeTests.log"; @Override @Before public void setUp() throws Exception { super.setUp(); - fileName = getTestDir() + "/fileUsedOnNativeTests.log"; Assert.assertTrue(String.format("libAIO is not loaded on %s %s %s", System.getProperty("os.name"), System.getProperty("os.arch"), System.getProperty("os.version")), - AsynchronousFileImpl.isLoaded()); + LibaioContext.isLoaded()); } @Override @After public void tearDown() throws Exception { - Assert.assertEquals(0, AsynchronousFileImpl.getTotalMaxIO()); + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); super.tearDown(); } @@ -73,12 +73,12 @@ public abstract class AIOTestBase extends ActiveMQTestBase } - protected void preAlloc(final AsynchronousFileImpl controller, final long size) throws ActiveMQException + protected void preAlloc(final LibaioFile controller, final long size) throws ActiveMQException { - controller.fill(0L, 1, size, (byte)0); + controller.fill(size); } - protected static class CountDownCallback implements AIOCallback + protected static class CountDownCallback implements IOCallback { private final CountDownLatch latch; diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AsynchronousFileTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AsynchronousFileTest.java deleted file mode 100644 index 434dcc8953..0000000000 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/AsynchronousFileTest.java +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.activemq.artemis.tests.unit.core.asyncio; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.lang.ref.WeakReference; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.activemq.artemis.api.core.ActiveMQException; -import org.apache.activemq.artemis.core.asyncio.AIOCallback; -import org.apache.activemq.artemis.core.asyncio.BufferCallback; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; -import org.apache.activemq.artemis.tests.unit.UnitTestLogger; -import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * you need to define -Djava.library.path=${project-root}/native/src/.libs when calling the JVM - * If you are running this test in eclipse you should do: - * I - Run->Open Run Dialog - * II - Find the class on the list (you will find it if you already tried running this testcase before) - * III - Add -Djava.library.path=/native/src/.libs - */ -public class AsynchronousFileTest extends AIOTestBase -{ - - @BeforeClass - public static void hasAIO() - { - org.junit.Assume.assumeTrue("Test case needs AIO to run", AIOSequentialFileFactory.isSupported()); - } - - private static CharsetEncoder UTF_8_ENCODER = StandardCharsets.UTF_8.newEncoder(); - - byte[] commonBuffer = null; - - ExecutorService executor; - - ExecutorService pollerExecutor; - - private AsynchronousFileImpl controller; - private ByteBuffer buffer; - - private final BufferCallback bufferCallbackDestroy = new BufferCallback() - { - - public void bufferDone(final ByteBuffer buffer1) - { - AsynchronousFileImpl.destroyBuffer(buffer1); - } - - }; - - private static void debug(final String msg) - { - UnitTestLogger.LOGGER.debug(msg); - } - - @Override - @Before - public void setUp() throws Exception - { - super.setUp(); - pollerExecutor = Executors.newCachedThreadPool(new ActiveMQThreadFactory("ActiveMQ-AIO-poller-pool" + System.identityHashCode(this), - false, - this.getClass().getClassLoader())); - executor = Executors.newSingleThreadExecutor(); - } - - @Override - @After - public void tearDown() throws Exception - { - destroy(buffer); - if (controller != null) - { - try - { - controller.close(); - } - catch (Exception e) - { - // ignored - } - } - executor.shutdown(); - pollerExecutor.shutdown(); - super.tearDown(); - } - - /** - * Opening and closing a file immediately can lead to races on the native layer, - * creating crash conditions. - */ - @Test - public void testOpenClose() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - for (int i = 0; i < 100; i++) - { - controller.open(fileName, 10000); - controller.close(); - - } - } - - @Test - public void testReleaseBuffers() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - WeakReference bufferCheck = null; - - controller.open(fileName, 10000); - bufferCheck = new WeakReference(controller.getHandler()); - controller.fill(0, 10, 1024, (byte) 0); - - ByteBuffer write = AsynchronousFileImpl.newBuffer(1024); - - for (int i = 0; i < 1024; i++) - { - write.put(ActiveMQTestBase.getSamplebyte(i)); - } - - final CountDownLatch latch = new CountDownLatch(1); - - controller.write(0, 1024, write, new AIOCallback() - { - - public void onError(final int errorCode, final String errorMessage) - { - } - - public void done() - { - latch.countDown(); - } - }); - - assertTrue(latch.await(10, TimeUnit.SECONDS)); - - WeakReference bufferCheck2 = new WeakReference(write); - - destroy(write); - - write = null; - - ActiveMQTestBase.forceGC(bufferCheck2, 5000); - - assertNull(bufferCheck2.get()); - - controller.close(); - - controller = null; - - ActiveMQTestBase.forceGC(bufferCheck, 5000); - - assertNull(bufferCheck.get()); - } - - @Test - public void testFileNonExistent() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - for (int i = 0; i < 100; i++) - { - try - { - controller.open("/non-existent/IDontExist.error", 10000); - fail("Exception expected! The test could create a file called /non-existent/IDontExist.error when it was supposed to fail."); - } - catch (Exception ignored) - { - } - try - { - controller.close(); - fail("Supposed to throw exception as the file wasn't opened"); - } - catch (Exception ignored) - { - } - - } - } - - /** - * This test is validating if the AIO layer can open two different - * simultaneous files without loose any callbacks. This test made the native - * layer to crash at some point during development - */ - @Test - public void testTwoFiles() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - final AsynchronousFileImpl controller2 = new AsynchronousFileImpl(executor, pollerExecutor); - controller.open(fileName + ".1", 10000); - controller2.open(fileName + ".2", 10000); - - int numberOfLines = 1000; - int size = 1024; - - ArrayList listResult1 = new ArrayList(); - ArrayList listResult2 = new ArrayList(); - - AtomicInteger errors = new AtomicInteger(0); - - - try - { - CountDownLatch latchDone = new CountDownLatch(numberOfLines); - CountDownLatch latchDone2 = new CountDownLatch(numberOfLines); - - buffer = AsynchronousFileImpl.newBuffer(size); - encodeBufer(buffer); - - preAlloc(controller, numberOfLines * size); - preAlloc(controller2, numberOfLines * size); - - ArrayList list = new ArrayList(); - ArrayList list2 = new ArrayList(); - - for (int i = 0; i < numberOfLines; i++) - { - list.add(new CountDownCallback(latchDone, errors, listResult1, i)); - list2.add(new CountDownCallback(latchDone2, errors, listResult2, i)); - } - - int counter = 0; - - Iterator iter2 = list2.iterator(); - - for (CountDownCallback cb1 : list) - { - CountDownCallback cb2 = iter2.next(); - - controller.write(counter * size, size, buffer, cb1); - controller2.write(counter * size, size, buffer, cb2); - ++counter; - - } - - ActiveMQTestBase.waitForLatch(latchDone); - ActiveMQTestBase.waitForLatch(latchDone2); - - CountDownCallback.checkResults(numberOfLines, listResult1); - CountDownCallback.checkResults(numberOfLines, listResult2); - - for (CountDownCallback callback : list) - { - assertEquals(1, callback.timesDoneCalled.get()); - assertTrue(callback.doneCalled); - } - - for (CountDownCallback callback : list2) - { - assertEquals(1, callback.timesDoneCalled.get()); - assertTrue(callback.doneCalled); - } - - assertEquals(0, errors.get()); - - controller.close(); - } - finally - { - try - { - controller2.close(); - } - catch (Exception ignored) - { - } - } - } - - @Test - public void testAddBeyongSimultaneousLimit() throws Exception - { - asyncData(3000, 1024, 10); - } - - @Test - public void testAddAsyncData() throws Exception - { - asyncData(10000, 1024, 30000); - } - - private static final class LocalCallback implements AIOCallback - { - private final CountDownLatch latch = new CountDownLatch(1); - - volatile boolean error; - - public void done() - { - latch.countDown(); - } - - public void onError(final int errorCode, final String errorMessage) - { - error = true; - latch.countDown(); - } - } - - @Test - public void testReleaseNullBuffer() throws Exception - { - boolean failed = false; - try - { - AsynchronousFileImpl.destroyBuffer(null); - } - catch (Exception expected) - { - failed = true; - } - - assertTrue("Exception expected", failed); - } - - @Test - public void testInvalidReads() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - - final int SIZE = 512; - - controller.open(fileName, 10); - controller.close(); - - controller = new AsynchronousFileImpl(executor, pollerExecutor); - - controller.open(fileName, 10); - - controller.fill(0, 1, 512, (byte) 'j'); - - buffer = AsynchronousFileImpl.newBuffer(SIZE); - - buffer.clear(); - - for (int i = 0; i < SIZE; i++) - { - buffer.put((byte) (i % 100)); - } - - LocalCallback callbackLocal = new LocalCallback(); - - controller.write(0, 512, buffer, callbackLocal); - - waitForLatch(callbackLocal.latch); - - { - ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(512); - - try - { - callbackLocal = new LocalCallback(); - - controller.read(0, 50, newBuffer, callbackLocal); - - waitForLatch(callbackLocal.latch); - - assertTrue(callbackLocal.error); - - } - finally - { - // We have to destroy the native buffer manually as it was created with a malloc like C function - destroy(newBuffer); - newBuffer = null; - } - } - callbackLocal = new LocalCallback(); - - byte[] bytes = new byte[512]; - - { - try - { - ByteBuffer newBuffer = ByteBuffer.wrap(bytes); - - controller.read(0, 512, newBuffer, callbackLocal); - - fail("An exception was supposed to be thrown"); - } - catch (ActiveMQException ignored) - { - System.out.println(ignored); - } - } - - { - final ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(512); - try - { - callbackLocal = new LocalCallback(); - controller.read(0, 512, newBuffer, callbackLocal); - waitForLatch(callbackLocal.latch); - assertFalse(callbackLocal.error); - - newBuffer.rewind(); - - byte[] bytesRead = new byte[SIZE]; - - newBuffer.get(bytesRead); - - for (int i = 0; i < SIZE; i++) - { - assertEquals((byte) (i % 100), bytesRead[i]); - } - } - finally - { - destroy(newBuffer); - } - } - } - - private static void destroy(ByteBuffer buffer0) - { - if (buffer0 != null) - { - AsynchronousFileImpl.destroyBuffer(buffer0); - } - } - - @Test - public void testBufferCallbackUniqueBuffers() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - final int NUMBER_LINES = 1000; - final int SIZE = 512; - - controller.open(fileName, 1000); - - controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); - - final ArrayList buffers = new ArrayList(); - - BufferCallback bufferCallback = new BufferCallback() - { - public void bufferDone(final ByteBuffer buffer) - { - buffers.add(buffer); - } - }; - - controller.setBufferCallback(bufferCallback); - - CountDownLatch latch = new CountDownLatch(NUMBER_LINES); - ArrayList result = new ArrayList(); - for (int i = 0; i < NUMBER_LINES; i++) - { - ByteBuffer buffer1 = AsynchronousFileImpl.newBuffer(SIZE); - buffer1.rewind(); - for (int j = 0; j < SIZE; j++) - { - buffer1.put((byte) (j % Byte.MAX_VALUE)); - } - CountDownCallback aio = new CountDownCallback(latch, null, result, i); - controller.write(i * SIZE, SIZE, buffer1, aio); - } - - // The buffer callback is only called after the complete callback was - // called. - // Because of that a race could happen on the assertions to - // buffers.size what would invalidate the test - // We close the file and that would guarantee the buffer callback was - // called for all the elements - controller.close(); - - CountDownCallback.checkResults(NUMBER_LINES, result); - - // Make sure all the buffers are unique - ByteBuffer lineOne = null; - for (ByteBuffer bufferTmp : buffers) - { - if (lineOne == null) - { - lineOne = bufferTmp; - } - else - { - assertTrue(lineOne != bufferTmp); - } - } - - for (ByteBuffer bufferTmp : buffers) - { - destroy(bufferTmp); - } - - buffers.clear(); - } - - @Test - public void testBufferCallbackAwaysSameBuffer() throws Exception - { - - controller = new AsynchronousFileImpl(executor, pollerExecutor); - - final int NUMBER_LINES = 1000; - final int SIZE = 512; - - controller.open(fileName, 1000); - - controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); - - final ArrayList buffers = new ArrayList(); - - BufferCallback bufferCallback = new BufferCallback() - { - public void bufferDone(final ByteBuffer buffer) - { - buffers.add(buffer); - } - }; - - controller.setBufferCallback(bufferCallback); - - CountDownLatch latch = new CountDownLatch(NUMBER_LINES); - - buffer = AsynchronousFileImpl.newBuffer(SIZE); - buffer.rewind(); - for (int j = 0; j < SIZE; j++) - { - buffer.put((byte) (j % Byte.MAX_VALUE)); - } - - ArrayList result = new ArrayList(); - - for (int i = 0; i < NUMBER_LINES; i++) - { - CountDownCallback aio = new CountDownCallback(latch, null, result, i); - controller.write(i * SIZE, SIZE, buffer, aio); - } - - // The buffer callback is only called after the complete callback was - // called. - // Because of that a race could happen on the assertions to - // buffers.size what would invalidate the test - // We close the file and that would guarantee the buffer callback was - // called for all the elements - controller.close(); - - CountDownCallback.checkResults(NUMBER_LINES, result); - - assertEquals(NUMBER_LINES, buffers.size()); - - // Make sure all the buffers are unique - ByteBuffer lineOne = null; - for (ByteBuffer bufferTmp : buffers) - { - if (lineOne == null) - { - lineOne = bufferTmp; - } - else - { - assertTrue(lineOne == bufferTmp); - } - } - - buffers.clear(); - } - - @Test - public void testRead() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - controller.setBufferCallback(bufferCallbackDestroy); - - final int NUMBER_LINES = 1000; - final int SIZE = 1024; - - controller.open(fileName, 1000); - - controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); - - { - CountDownLatch latch = new CountDownLatch(NUMBER_LINES); - ArrayList result = new ArrayList(); - - AtomicInteger errors = new AtomicInteger(0); - - for (int i = 0; i < NUMBER_LINES; i++) - { - if (i % 100 == 0) - { - System.out.println("Wrote " + i + " lines"); - } - final ByteBuffer buffer0 = AsynchronousFileImpl.newBuffer(SIZE); - for (int j = 0; j < SIZE; j++) - { - buffer0.put(ActiveMQTestBase.getSamplebyte(j)); - } - - CountDownCallback aio = new CountDownCallback(latch, errors, result, i); - controller.write(i * SIZE, SIZE, buffer0, aio); - } - - waitForLatch(latch); - - assertEquals(0, errors.get()); - - CountDownCallback.checkResults(NUMBER_LINES, result); - } - - // If you call close you're supposed to wait events to finish before - // closing it - controller.close(); - controller.setBufferCallback(null); - - controller.open(fileName, 10); - - buffer = AsynchronousFileImpl.newBuffer(SIZE); - - for (int i = 0; i < NUMBER_LINES; i++) - { - if (i % 100 == 0) - { - System.out.println("Read " + i + " lines"); - } - AsynchronousFileImpl.clearBuffer(buffer); - - CountDownLatch latch = new CountDownLatch(1); - AtomicInteger errors = new AtomicInteger(0); - CountDownCallback aio = new CountDownCallback(latch, errors, null, 0); - - controller.read(i * SIZE, SIZE, buffer, aio); - - waitForLatch(latch); - assertEquals(0, errors.get()); - assertTrue(aio.doneCalled); - - byte[] bytesRead = new byte[SIZE]; - buffer.get(bytesRead); - - for (int count = 0; count < SIZE; count++) - { - Assert.assertEquals("byte position " + count + " differs on line " + i + " position = " + count, - ActiveMQTestBase.getSamplebyte(count), - bytesRead[count]); - } - } - } - - /** - * This test will call file.close() when there are still callbacks being processed. - * This could cause a crash or callbacks missing and this test is validating both situations. - * The file is also read after being written to validate its correctness - */ - @Test - public void testConcurrentClose() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - final int NUMBER_LINES = 1000; - CountDownLatch readLatch = new CountDownLatch(NUMBER_LINES); - final int SIZE = 1024; - - controller.open(fileName, 10000); - - controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); - - controller.setBufferCallback(bufferCallbackDestroy); - - for (int i = 0; i < NUMBER_LINES; i++) - { - ByteBuffer buffer = AsynchronousFileImpl.newBuffer(SIZE); - - buffer.clear(); - addString("Str value " + i + "\n", buffer); - for (int j = buffer.position(); j < buffer.capacity() - 1; j++) - { - buffer.put((byte) ' '); - } - buffer.put((byte) '\n'); - - CountDownCallback aio = new CountDownCallback(readLatch, null, null, 0); - controller.write(i * SIZE, SIZE, buffer, aio); - } - - // If you call close you're supposed to wait events to finish before - // closing it - controller.close(); - - controller.setBufferCallback(null); - - assertEquals(0, readLatch.getCount()); - waitForLatch(readLatch); - controller.open(fileName, 10); - - ByteBuffer newBuffer = AsynchronousFileImpl.newBuffer(SIZE); - - ByteBuffer buffer = AsynchronousFileImpl.newBuffer(SIZE); - - for (int i = 0; i < NUMBER_LINES; i++) - { - newBuffer.clear(); - addString("Str value " + i + "\n", newBuffer); - for (int j = newBuffer.position(); j < newBuffer.capacity() - 1; j++) - { - newBuffer.put((byte) ' '); - } - newBuffer.put((byte) '\n'); - - CountDownLatch latch = new CountDownLatch(1); - CountDownCallback aio = new CountDownCallback(latch, null, null, 0); - controller.read(i * SIZE, SIZE, buffer, aio); - waitForLatch(latch); - assertEquals(0, aio.errorCalled); - assertTrue(aio.doneCalled); - - byte[] bytesRead = new byte[SIZE]; - byte[] bytesCompare = new byte[SIZE]; - - newBuffer.rewind(); - newBuffer.get(bytesCompare); - buffer.rewind(); - buffer.get(bytesRead); - - for (int count = 0; count < SIZE; count++) - { - assertEquals("byte position " + count + " differs on line " + i, - bytesCompare[count], - bytesRead[count]); - } - - assertTrue(buffer.equals(newBuffer)); - } - - destroy(newBuffer); - } - - private void asyncData(final int numberOfLines, final int size, final int aioLimit) throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - controller.open(fileName, aioLimit); - - - CountDownLatch latchDone = new CountDownLatch(numberOfLines); - - buffer = AsynchronousFileImpl.newBuffer(size); - encodeBufer(buffer); - - preAlloc(controller, numberOfLines * size); - - ArrayList list = new ArrayList(); - - ArrayList result = new ArrayList(); - - for (int i = 0; i < numberOfLines; i++) - { - list.add(new CountDownCallback(latchDone, null, result, i)); - } - - long valueInitial = System.currentTimeMillis(); - - long lastTime = System.currentTimeMillis(); - int counter = 0; - for (CountDownCallback tmp : list) - { - controller.write(counter * size, size, buffer, tmp); - if (++counter % 20000 == 0) - { - AsynchronousFileTest.debug(20000 * 1000 / (System.currentTimeMillis() - lastTime) + " rec/sec (Async)"); - lastTime = System.currentTimeMillis(); - } - - } - - ActiveMQTestBase.waitForLatch(latchDone); - - long timeTotal = System.currentTimeMillis() - valueInitial; - - CountDownCallback.checkResults(numberOfLines, result); - - AsynchronousFileTest.debug("After completions time = " + timeTotal + - " for " + - numberOfLines + - " registers " + - " size each line = " + - size + - ", Records/Sec=" + - numberOfLines * - 1000 / - timeTotal + - " (Assynchronous)"); - - for (CountDownCallback tmp : list) - { - assertEquals(1, tmp.timesDoneCalled.get()); - assertTrue(tmp.doneCalled); - assertEquals(0, tmp.errorCalled); - } - - controller.close(); - } - - @Test - public void testDirectSynchronous() throws Exception - { - - final int NUMBER_LINES = 3000; - final int SIZE = 1024; - - controller = new AsynchronousFileImpl(executor, pollerExecutor); - controller.open(fileName, 2000); - - buffer = AsynchronousFileImpl.newBuffer(SIZE); - encodeBufer(buffer); - - preAlloc(controller, NUMBER_LINES * SIZE); - - long startTime = System.currentTimeMillis(); - - for (int i = 0; i < NUMBER_LINES; i++) - { - CountDownLatch latchDone = new CountDownLatch(1); - CountDownCallback aioBlock = new CountDownCallback(latchDone, null, null, 0); - controller.write(i * 512, 512, buffer, aioBlock); - ActiveMQTestBase.waitForLatch(latchDone); - assertTrue(aioBlock.doneCalled); - assertEquals(0, aioBlock.errorCalled); - } - - long timeTotal = System.currentTimeMillis() - startTime; - AsynchronousFileTest.debug("time = " + timeTotal + - " for " + - NUMBER_LINES + - " registers " + - " size each line = " + - SIZE + - " Records/Sec=" + - NUMBER_LINES * - 1000 / - timeTotal + - " Synchronous"); - - controller.close(); - } - - - @Test - public void testInternalWrite() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - controller.open(fileName, 2000); - - final int SIZE = 10 * 512; - - buffer = AsynchronousFileImpl.newBuffer(SIZE); - - for (int i = 0; i < SIZE; i++) - { - buffer.put(getSamplebyte(i)); - } - - controller.writeInternal(0, SIZE, buffer); - - InputStream fileInput = new BufferedInputStream(new FileInputStream(new File(fileName))); - - for (int i = 0; i < SIZE; i++) - { - assertEquals(getSamplebyte(i), fileInput.read()); - } - - assertEquals(-1, fileInput.read()); - - } - - - @Test - public void testInvalidWrite() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - controller.open(fileName, 2000); - - final int SIZE = 512; - - buffer = AsynchronousFileImpl.newBuffer(SIZE); - encodeBufer(buffer); - - preAlloc(controller, 10 * 512); - - CountDownLatch latchDone = new CountDownLatch(1); - - CountDownCallback aioBlock = new CountDownCallback(latchDone, null, null, 0); - controller.write(11, 512, buffer, aioBlock); - - ActiveMQTestBase.waitForLatch(latchDone); - - assertTrue(aioBlock.errorCalled != 0); - assertFalse(aioBlock.doneCalled); - } - - @Test - public void testInvalidAlloc() throws Exception - { - try - { - @SuppressWarnings("unused") - ByteBuffer buffer = AsynchronousFileImpl.newBuffer(300); - fail("Exception expected"); - } - catch (Exception ignored) - { - } - - } - - // This is in particular testing for http://bugs.sun.com/view_bug.do?bug_id=6791815 - @Test - public void testAllocations() throws Exception - { - final AtomicInteger errors = new AtomicInteger(0); - - Thread[] ts = new Thread[100]; - - final CountDownLatch align = new CountDownLatch(ts.length); - final CountDownLatch start = new CountDownLatch(1); - - for (int i = 0; i < ts.length; i++) - { - ts[i] = new Thread() - { - @Override - public void run() - { - try - { - align.countDown(); - start.await(); - for (int j = 0; j < 1000; j++) - { - ByteBuffer buffer = AsynchronousFileImpl.newBuffer(512); - AsynchronousFileTest.destroy(buffer); - } - } - catch (Throwable e) - { - e.printStackTrace(); - errors.incrementAndGet(); - } - } - }; - ts[i].start(); - } - - align.await(); - start.countDown(); - - for (Thread t : ts) - { - t.join(); - } - - assertEquals(0, errors.get()); - } - - @Test - public void testSize() throws Exception - { - controller = new AsynchronousFileImpl(executor, pollerExecutor); - - final int NUMBER_LINES = 10; - final int SIZE = 1024; - - controller.open(fileName, 1); - - controller.fill(0, 1, NUMBER_LINES * SIZE, (byte) 'j'); - - assertEquals(NUMBER_LINES * SIZE, controller.size()); - } - - private static void addString(final String str, final ByteBuffer buffer) - { - CharBuffer charBuffer = CharBuffer.wrap(str); - AsynchronousFileTest.UTF_8_ENCODER.encode(charBuffer, buffer, true); - } -} diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/MultiThreadAsynchronousFileTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/MultiThreadAsynchronousFileTest.java index aa8422ad2c..c9d3ce4280 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/MultiThreadAsynchronousFileTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/asyncio/MultiThreadAsynchronousFileTest.java @@ -16,10 +16,10 @@ */ package org.apache.activemq.artemis.tests.unit.core.asyncio; -import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; -import org.apache.activemq.artemis.core.asyncio.AIOCallback; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFile; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.utils.ActiveMQThreadFactory; @@ -55,7 +55,7 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase static final int SIZE = 1024; - static final int NUMBER_OF_THREADS = 10; + static final int NUMBER_OF_THREADS = 1; static final int NUMBER_OF_LINES = 1000; @@ -65,7 +65,7 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase private static void debug(final String msg) { - UnitTestLogger.LOGGER.debug(msg); + UnitTestLogger.LOGGER.info(msg); } @Override @@ -102,16 +102,18 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase private void executeTest(final boolean sync) throws Throwable { MultiThreadAsynchronousFileTest.debug(sync ? "Sync test:" : "Async test"); - AsynchronousFileImpl jlibAIO = new AsynchronousFileImpl(executor, pollerExecutor); - jlibAIO.open(fileName, 21000); + AIOSequentialFileFactory factory = new AIOSequentialFileFactory(getTestDirfile(), 21000); + factory.start(); + factory.disableBufferReuse(); + + AIOSequentialFile file = (AIOSequentialFile)factory.createSequentialFile(fileName); + file.open(); try { MultiThreadAsynchronousFileTest.debug("Preallocating file"); - jlibAIO.fill(0L, - MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS, - MultiThreadAsynchronousFileTest.SIZE * MultiThreadAsynchronousFileTest.NUMBER_OF_LINES, - (byte) 0); + file.fill(MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS * + MultiThreadAsynchronousFileTest.SIZE * MultiThreadAsynchronousFileTest.NUMBER_OF_LINES); MultiThreadAsynchronousFileTest.debug("Done Preallocating file"); CountDownLatch latchStart = new CountDownLatch(MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS + 1); @@ -119,7 +121,7 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase ArrayList list = new ArrayList(MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS); for (int i = 0; i < MultiThreadAsynchronousFileTest.NUMBER_OF_THREADS; i++) { - ThreadProducer producer = new ThreadProducer("Thread " + i, latchStart, jlibAIO, sync); + ThreadProducer producer = new ThreadProducer("Thread " + i, latchStart, file, sync); list.add(producer); producer.start(); } @@ -152,7 +154,8 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase } finally { - jlibAIO.close(); + file.close(); + factory.stop(); } } @@ -170,11 +173,11 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase boolean sync; - AsynchronousFileImpl libaio; + AIOSequentialFile libaio; public ThreadProducer(final String name, final CountDownLatch latchStart, - final AsynchronousFileImpl libaio, + final AIOSequentialFile libaio, final boolean sync) { super(name); @@ -190,10 +193,7 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase ByteBuffer buffer = null; - synchronized (MultiThreadAsynchronousFileTest.class) - { - buffer = AsynchronousFileImpl.newBuffer(MultiThreadAsynchronousFileTest.SIZE); - } + buffer = LibaioContext.newAlignedBuffer(MultiThreadAsynchronousFileTest.SIZE, 512); try { @@ -268,7 +268,7 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase { synchronized (MultiThreadAsynchronousFileTest.class) { - AsynchronousFileImpl.destroyBuffer(buffer); + LibaioContext.freeBuffer(buffer); } } @@ -281,44 +281,9 @@ public class MultiThreadAsynchronousFileTest extends AIOTestBase buffer.put(bytes); } - private void addData(final AsynchronousFileImpl aio, final ByteBuffer buffer, final AIOCallback callback) throws Exception + private void addData(final AIOSequentialFile aio, final ByteBuffer buffer, final IOCallback callback) throws Exception { - executor.execute(new WriteRunnable(aio, buffer, callback)); - } - - private class WriteRunnable implements Runnable - { - - AsynchronousFileImpl aio; - - ByteBuffer buffer; - - AIOCallback callback; - - public WriteRunnable(final AsynchronousFileImpl aio, final ByteBuffer buffer, final AIOCallback callback) - { - this.aio = aio; - this.buffer = buffer; - this.callback = callback; - } - - public void run() - { - try - { - aio.write(getNewPosition() * MultiThreadAsynchronousFileTest.SIZE, - MultiThreadAsynchronousFileTest.SIZE, - buffer, - callback); - - } - catch (Exception e) - { - callback.onError(ActiveMQExceptionType.GENERIC_EXCEPTION.getCode(), e.toString()); - e.printStackTrace(); - } - } - + aio.writeDirect(buffer, true, callback); } } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/AlignedJournalImplTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/AlignedJournalImplTest.java index aa5c68b137..e08ef556a1 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/AlignedJournalImplTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/AlignedJournalImplTest.java @@ -37,8 +37,8 @@ import org.apache.activemq.artemis.core.journal.EncodingSupport; import org.apache.activemq.artemis.core.journal.LoaderCallback; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TransactionFailureCallback; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; @@ -100,7 +100,7 @@ public class AlignedJournalImplTest extends ActiveMQTestBase FakeSequentialFileFactory factory = new FakeSequentialFileFactory(200, true); - SequentialFile file = factory.createSequentialFile("test1", 1); + SequentialFile file = factory.createSequentialFile("test1"); file.open(); @@ -590,7 +590,7 @@ public class AlignedJournalImplTest extends ActiveMQTestBase System.out.println("Files = " + factory.listFiles("tt")); - SequentialFile file = factory.createSequentialFile("tt-1.tt", 1); + SequentialFile file = factory.createSequentialFile("tt-1.tt"); file.open(); @@ -656,7 +656,7 @@ public class AlignedJournalImplTest extends ActiveMQTestBase journalImpl.appendCommitRecord(2L, false); - SequentialFile file = factory.createSequentialFile("tt-1.tt", 1); + SequentialFile file = factory.createSequentialFile("tt-1.tt"); file.open(); @@ -761,7 +761,7 @@ public class AlignedJournalImplTest extends ActiveMQTestBase journalImpl.appendCommitRecord(1L, false); - SequentialFile file = factory.createSequentialFile("tt-1.tt", 1); + SequentialFile file = factory.createSequentialFile("tt-1.tt"); file.open(); @@ -1046,7 +1046,7 @@ public class AlignedJournalImplTest extends ActiveMQTestBase Assert.assertEquals(0, records.size()); Assert.assertEquals(1, transactions.size()); - SequentialFile file = factory.createSequentialFile("tt-1.tt", 1); + SequentialFile file = factory.createSequentialFile("tt-1.tt"); file.open(); diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/CleanBufferTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/CleanBufferTest.java index e078043482..c2f88acf44 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/CleanBufferTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/CleanBufferTest.java @@ -19,10 +19,10 @@ package org.apache.activemq.artemis.tests.unit.core.journal.impl; import java.io.File; import java.nio.ByteBuffer; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.AIOSequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; @@ -44,7 +44,7 @@ public class CleanBufferTest extends ActiveMQTestBase @Test public void testCleanOnNIO() { - SequentialFileFactory factory = new NIOSequentialFileFactory(new File("Whatever")); + SequentialFileFactory factory = new NIOSequentialFileFactory(new File("Whatever"), 1); testBuffer(factory); } @@ -52,9 +52,9 @@ public class CleanBufferTest extends ActiveMQTestBase @Test public void testCleanOnAIO() { - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { - SequentialFileFactory factory = new AIOSequentialFileFactory(new File("Whatever")); + SequentialFileFactory factory = new AIOSequentialFileFactory(new File("Whatever"), 50); testBuffer(factory); } @@ -70,6 +70,7 @@ public class CleanBufferTest extends ActiveMQTestBase private void testBuffer(final SequentialFileFactory factory) { + factory.start(); ByteBuffer buffer = factory.newBuffer(100); try @@ -107,6 +108,7 @@ public class CleanBufferTest extends ActiveMQTestBase finally { factory.releaseBuffer(buffer); + factory.stop(); } } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeJournalImplTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeJournalImplTest.java index aaffffa6b1..eabb89e73a 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeJournalImplTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeJournalImplTest.java @@ -17,7 +17,7 @@ package org.apache.activemq.artemis.tests.unit.core.journal.impl; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; public class FakeJournalImplTest extends JournalImplTestUnit { diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeSequentialFileFactoryTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeSequentialFileFactoryTest.java index 74312334b0..aee1e067a6 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeSequentialFileFactoryTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FakeSequentialFileFactoryTest.java @@ -17,7 +17,7 @@ package org.apache.activemq.artemis.tests.unit.core.journal.impl; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; public class FakeSequentialFileFactoryTest extends SequentialFileFactoryTestBase { diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FileFactoryTestBase.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FileFactoryTestBase.java index 8eacec1e74..73bf1483fc 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FileFactoryTestBase.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/FileFactoryTestBase.java @@ -15,15 +15,13 @@ * limitations under the License. */ package org.apache.activemq.artemis.tests.unit.core.journal.impl; -import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.junit.Before; - import java.nio.ByteBuffer; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; - -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.junit.Before; public abstract class FileFactoryTestBase extends ActiveMQTestBase { @@ -42,15 +40,15 @@ public abstract class FileFactoryTestBase extends ActiveMQTestBase // Protected --------------------------------- - protected void checkFill(final SequentialFile file, final int pos, final int size, final byte fillChar) throws Exception + protected void checkFill(final SequentialFile file, final int size) throws Exception { - file.fill(pos, size, fillChar); + file.fill(size); file.close(); file.open(); - file.position(pos); + file.position(0); ByteBuffer bb = ByteBuffer.allocateDirect(size); @@ -67,7 +65,7 @@ public abstract class FileFactoryTestBase extends ActiveMQTestBase for (int i = 0; i < size; i++) { // log.debug(" i is " + i); - Assert.assertEquals(fillChar, bytes[i]); + Assert.assertEquals(0, bytes[i]); } } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestBase.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestBase.java index e340cf2d34..7e1347e92d 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestBase.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestBase.java @@ -30,7 +30,7 @@ import org.apache.activemq.artemis.cli.commands.tools.EncodeJournal; import org.apache.activemq.artemis.core.journal.EncodingSupport; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; import org.apache.activemq.artemis.core.journal.TestableJournal; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; @@ -104,6 +104,10 @@ public abstract class JournalImplTestBase extends ActiveMQTestBase protected void resetFileFactory() throws Exception { + if (fileFactory != null) + { + fileFactory.stop(); + } fileFactory = getFileFactory(); } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestUnit.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestUnit.java index ab86abc3fe..b009092538 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestUnit.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/JournalImplTestUnit.java @@ -25,7 +25,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQIOErrorException; import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.SimpleEncoding; import org.apache.activemq.artemis.core.journal.EncodingSupport; import org.apache.activemq.artemis.core.journal.RecordInfo; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.tests.util.RandomUtil; @@ -42,7 +42,7 @@ public abstract class JournalImplTestUnit extends JournalImplTestBase for (String file : files) { - SequentialFile seqFile = fileFactory.createSequentialFile(file, 1); + SequentialFile seqFile = fileFactory.createSequentialFile(file); Assert.assertEquals(fileSize, seqFile.size()); } @@ -222,7 +222,7 @@ public abstract class JournalImplTestUnit extends JournalImplTestBase for (String fileStr : files) { - SequentialFile file = fileFactory.createSequentialFile(fileStr, 1); + SequentialFile file = fileFactory.createSequentialFile(fileStr); ByteBuffer buffer = fileFactory.newBuffer(JournalImpl.SIZE_HEADER); @@ -284,7 +284,7 @@ public abstract class JournalImplTestUnit extends JournalImplTestBase long fileID = Integer.MAX_VALUE; for (String fileStr : files) { - SequentialFile file = fileFactory.createSequentialFile(fileStr, 1); + SequentialFile file = fileFactory.createSequentialFile(fileStr); file.open(); @@ -2138,6 +2138,7 @@ public abstract class JournalImplTestUnit extends JournalImplTestBase createJournal(); startJournal(); loadAndCheck(); + stopJournal(); } @Test diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/ReclaimerTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/ReclaimerTest.java index b5b721e828..858227a9ce 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/ReclaimerTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/ReclaimerTest.java @@ -27,7 +27,7 @@ import java.util.Set; import org.junit.Assert; -import org.apache.activemq.artemis.core.journal.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFile; import org.apache.activemq.artemis.core.journal.impl.JournalFile; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; import org.apache.activemq.artemis.core.journal.impl.Reclaimer; diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java index 469bdf2ed6..60ca28d79d 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/SequentialFileFactoryTestBase.java @@ -23,9 +23,9 @@ import java.util.UUID; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.After; import org.junit.Assert; @@ -49,14 +49,14 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @After public void tearDown() throws Exception { - Assert.assertEquals(0, AsynchronousFileImpl.getTotalMaxIO()); - factory.stop(); factory = null; ActiveMQTestBase.forceGC(); + Assert.assertEquals(0, LibaioContext.getTotalMaxIO()); + super.tearDown(); } @@ -86,7 +86,7 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase expectedFiles.add(fileName); - SequentialFile sf = factory.createSequentialFile(fileName, 1); + SequentialFile sf = factory.createSequentialFile(fileName); sf.open(); @@ -98,10 +98,10 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase // Create a couple with a different extension - they shouldn't be picked // up - SequentialFile sf1 = factory.createSequentialFile("different.file", 1); + SequentialFile sf1 = factory.createSequentialFile("different.file"); sf1.open(); - SequentialFile sf2 = factory.createSequentialFile("different.cheese", 1); + SequentialFile sf2 = factory.createSequentialFile("different.cheese"); sf2.open(); List fileNames = factory.listFiles("amq"); @@ -132,22 +132,18 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @Test public void testFill() throws Exception { - SequentialFile sf = factory.createSequentialFile("fill.amq", 1); + SequentialFile sf = factory.createSequentialFile("fill.amq"); sf.open(); try { - checkFill(sf, 0, 2048, (byte)'X'); + checkFill(sf, 2048); - checkFill(sf, 512, 512, (byte)'Y'); + checkFill(sf, 512); - checkFill(sf, 0, 1, (byte)'Z'); - - checkFill(sf, 512, 1, (byte)'A'); - - checkFill(sf, 1024, 512 * 4, (byte)'B'); + checkFill(sf, 512 * 4); } finally { @@ -158,11 +154,11 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @Test public void testDelete() throws Exception { - SequentialFile sf = factory.createSequentialFile("delete-me.amq", 1); + SequentialFile sf = factory.createSequentialFile("delete-me.amq"); sf.open(); - SequentialFile sf2 = factory.createSequentialFile("delete-me2.amq", 1); + SequentialFile sf2 = factory.createSequentialFile("delete-me2.amq"); sf2.open(); @@ -189,7 +185,7 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @Test public void testRename() throws Exception { - SequentialFile sf = factory.createSequentialFile("test1.amq", 1); + SequentialFile sf = factory.createSequentialFile("test1.amq"); sf.open(); @@ -222,7 +218,7 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @Test public void testWriteandRead() throws Exception { - SequentialFile sf = factory.createSequentialFile("write.amq", 1); + SequentialFile sf = factory.createSequentialFile("write.amq"); sf.open(); @@ -291,14 +287,14 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @Test public void testPosition() throws Exception { - SequentialFile sf = factory.createSequentialFile("position.amq", 1); + SequentialFile sf = factory.createSequentialFile("position.amq"); sf.open(); try { - sf.fill(0, 3 * 512, (byte)0); + sf.fill(3 * 512); String s1 = "orange"; byte[] bytes1 = s1.getBytes(StandardCharsets.UTF_8); @@ -376,11 +372,11 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase @Test public void testOpenClose() throws Exception { - SequentialFile sf = factory.createSequentialFile("openclose.amq", 1); + SequentialFile sf = factory.createSequentialFile("openclose.amq"); sf.open(); - sf.fill(0, 512, (byte)0); + sf.fill(512); String s1 = "cheesecake"; byte[] bytes1 = s1.getBytes(StandardCharsets.UTF_8); @@ -418,15 +414,15 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase return ActiveMQBuffers.wrappedBuffer(bytes); } - protected void checkFill(final SequentialFile file, final int pos, final int size, final byte fillChar) throws Exception + protected void checkFill(final SequentialFile file, final int size) throws Exception { - file.fill(pos, size, fillChar); + file.fill(size); file.close(); file.open(); - file.position(pos); + file.position(0); ByteBuffer bb = factory.newBuffer(size); @@ -437,7 +433,7 @@ public abstract class SequentialFileFactoryTestBase extends ActiveMQTestBase for (int i = 0; i < size; i++) { // log.debug(" i is " + i); - Assert.assertEquals(fillChar, bb.get(i)); + Assert.assertEquals(0, bb.get(i)); } } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/TimedBufferTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/TimedBufferTest.java index 76234b8b3b..21866c6cf1 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/TimedBufferTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/TimedBufferTest.java @@ -16,11 +16,6 @@ */ package org.apache.activemq.artemis.tests.unit.core.journal.impl; -import org.apache.activemq.artemis.api.core.ActiveMQBuffer; -import org.apache.activemq.artemis.api.core.ActiveMQBuffers; -import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.junit.Test; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -28,11 +23,14 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.activemq.artemis.api.core.ActiveMQBuffer; +import org.apache.activemq.artemis.api.core.ActiveMQBuffers; +import org.apache.activemq.artemis.core.io.IOCallback; +import org.apache.activemq.artemis.core.io.buffer.TimedBuffer; +import org.apache.activemq.artemis.core.io.buffer.TimedBufferObserver; +import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; - -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.impl.TimedBuffer; -import org.apache.activemq.artemis.core.journal.impl.TimedBufferObserver; +import org.junit.Test; public class TimedBufferTest extends ActiveMQTestBase { @@ -49,7 +47,7 @@ public class TimedBufferTest extends ActiveMQTestBase // Public -------------------------------------------------------- - IOAsyncTask dummyCallback = new IOAsyncTask() + IOCallback dummyCallback = new IOCallback() { public void done() @@ -69,7 +67,7 @@ public class TimedBufferTest extends ActiveMQTestBase final AtomicInteger flushTimes = new AtomicInteger(0); class TestObserver implements TimedBufferObserver { - public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) + public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) { buffers.add(buffer); flushTimes.incrementAndGet(); @@ -144,7 +142,7 @@ public class TimedBufferTest extends ActiveMQTestBase final AtomicInteger flushTimes = new AtomicInteger(0); class TestObserver implements TimedBufferObserver { - public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) + public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) { buffers.add(buffer); flushTimes.incrementAndGet(); @@ -235,7 +233,7 @@ public class TimedBufferTest extends ActiveMQTestBase { class TestObserver implements TimedBufferObserver { - public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) + public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) { } @@ -321,7 +319,7 @@ public class TimedBufferTest extends ActiveMQTestBase { class TestObserver implements TimedBufferObserver { - public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) + public void flushBuffer(final ByteBuffer buffer, final boolean sync, final List callbacks) { } diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java index 59586fd656..75a95351c5 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/journal/impl/fakes/FakeSequentialFileFactory.java @@ -27,12 +27,11 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; -import org.apache.activemq.artemis.core.asyncio.BufferCallback; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.core.journal.EncodingSupport; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.TimedBuffer; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.buffer.TimedBuffer; public class FakeSequentialFileFactory implements SequentialFileFactory { @@ -63,9 +62,16 @@ public class FakeSequentialFileFactory implements SequentialFileFactory this(1, false); } + @Override + public int getMaxIO() + { + return 1; + } + + // Public -------------------------------------------------------- - public SequentialFile createSequentialFile(final String fileName, final int maxAIO) + public SequentialFile createSequentialFile(final String fileName) { FakeSequentialFile sf = fileMap.get(fileName); @@ -233,11 +239,11 @@ public class FakeSequentialFileFactory implements SequentialFileFactory final ByteBuffer bytes; - final IOAsyncTask callback; + final IOCallback callback; volatile boolean sendError; - CallbackRunnable(final FakeSequentialFile file, final ByteBuffer bytes, final IOAsyncTask callback) + CallbackRunnable(final FakeSequentialFile file, final ByteBuffer bytes, final IOCallback callback) { this.file = file; this.bytes = bytes; @@ -260,11 +266,6 @@ public class FakeSequentialFileFactory implements SequentialFileFactory { callback.done(); } - - if (file.bufferCallback != null) - { - file.bufferCallback.bufferDone(bytes); - } } catch (Throwable e) { @@ -288,8 +289,6 @@ public class FakeSequentialFileFactory implements SequentialFileFactory private ByteBuffer data; - private BufferCallback bufferCallback; - public ByteBuffer getData() { return data; @@ -321,14 +320,6 @@ public class FakeSequentialFileFactory implements SequentialFileFactory notifyAll(); } - public synchronized void waitForClose() throws Exception - { - while (open) - { - this.wait(); - } - } - public void delete() { if (open) @@ -355,26 +346,21 @@ public class FakeSequentialFileFactory implements SequentialFileFactory checkAndResize(0); } - public void setBufferCallback(final BufferCallback callback) - { - bufferCallback = callback; - } - - public void fill(final int pos, final int size, final byte fillCharacter) throws Exception + public void fill(final int size) throws Exception { if (!open) { throw new IllegalStateException("Is closed"); } - checkAndResize(pos + size); + checkAndResize(size); // log.debug("size is " + size + " pos is " + pos); - for (int i = pos; i < size + pos; i++) + for (int i = 0; i < size; i++) { byte[] array = data.array(); - array[i] = fillCharacter; + array[i] = 0; // log.debug("Filling " + pos + " with char " + fillCharacter); } @@ -385,7 +371,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory return read(bytes, null); } - public int read(final ByteBuffer bytes, final IOAsyncTask callback) throws Exception + public int read(final ByteBuffer bytes, final IOCallback callback) throws Exception { if (!open) { @@ -426,7 +412,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory return data.position(); } - public synchronized void writeDirect(final ByteBuffer bytes, final boolean sync, final IOAsyncTask callback) + public synchronized void writeDirect(final ByteBuffer bytes, final boolean sync, final IOCallback callback) { if (!open) { @@ -485,7 +471,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#writeInternal(java.nio.ByteBuffer) + * @see org.apache.activemq.artemis.core.io.SequentialFile#writeInternal(java.nio.ByteBuffer) */ public void writeInternal(ByteBuffer bytes) throws Exception { @@ -555,7 +541,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#renameTo(org.apache.activemq.artemis.core.journal.SequentialFile) + * @see org.apache.activemq.artemis.core.io.SequentialFile#renameTo(org.apache.activemq.artemis.core.io.SequentialFile) */ public void renameTo(final String newFileName) throws Exception { @@ -565,7 +551,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#fits(int) + * @see org.apache.activemq.artemis.core.io.SequentialFile#fits(int) */ public boolean fits(final int size) { @@ -573,21 +559,21 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#setBuffering(boolean) + * @see org.apache.activemq.artemis.core.io.SequentialFile#setBuffering(boolean) */ public void setBuffering(final boolean buffering) { } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#lockBuffer() + * @see org.apache.activemq.artemis.core.io.SequentialFile#lockBuffer() */ public void disableAutoFlush() { } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#unlockBuffer() + * @see org.apache.activemq.artemis.core.io.SequentialFile#unlockBuffer() */ public void enableAutoFlush() { @@ -599,9 +585,9 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#write(org.apache.activemq.artemis.spi.core.remoting.ActiveMQBuffer, boolean, org.apache.activemq.artemis.core.journal.IOCallback) + * @see org.apache.activemq.artemis.core.io.SequentialFile#write(org.apache.activemq.artemis.spi.core.remoting.ActiveMQBuffer, boolean, org.apache.activemq.artemis.core.journal.IOCallback) */ - public void write(final ActiveMQBuffer bytes, final boolean sync, final IOAsyncTask callback) throws Exception + public void write(final ActiveMQBuffer bytes, final boolean sync, final IOCallback callback) throws Exception { bytes.writerIndex(bytes.capacity()); bytes.readerIndex(0); @@ -610,7 +596,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#write(org.apache.activemq.artemis.spi.core.remoting.ActiveMQBuffer, boolean) + * @see org.apache.activemq.artemis.core.io.SequentialFile#write(org.apache.activemq.artemis.spi.core.remoting.ActiveMQBuffer, boolean) */ public void write(final ActiveMQBuffer bytes, final boolean sync) throws Exception { @@ -620,9 +606,9 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#write(org.apache.activemq.artemis.core.journal.EncodingSupport, boolean, org.apache.activemq.artemis.core.journal.IOCompletion) + * @see org.apache.activemq.artemis.core.io.SequentialFile#write(org.apache.activemq.artemis.core.journal.EncodingSupport, boolean, org.apache.activemq.artemis.core.journal.IOCompletion) */ - public void write(final EncodingSupport bytes, final boolean sync, final IOAsyncTask callback) throws Exception + public void write(final EncodingSupport bytes, final boolean sync, final IOCallback callback) throws Exception { ByteBuffer buffer = newBuffer(bytes.getEncodeSize()); ActiveMQBuffer outbuffer = ActiveMQBuffers.wrappedBuffer(buffer); @@ -631,7 +617,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#write(org.apache.activemq.artemis.core.journal.EncodingSupport, boolean) + * @see org.apache.activemq.artemis.core.io.SequentialFile#write(org.apache.activemq.artemis.core.journal.EncodingSupport, boolean) */ public void write(final EncodingSupport bytes, final boolean sync) throws Exception { @@ -642,7 +628,7 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#exists() + * @see org.apache.activemq.artemis.core.io.SequentialFile#exists() */ public boolean exists() { @@ -652,14 +638,14 @@ public class FakeSequentialFileFactory implements SequentialFileFactory } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#setTimedBuffer(org.apache.activemq.artemis.core.journal.impl.TimedBuffer) + * @see org.apache.activemq.artemis.core.io.SequentialFile#setTimedBuffer(org.apache.activemq.artemis.core.io.buffer.TimedBuffer) */ public void setTimedBuffer(final TimedBuffer buffer) { } /* (non-Javadoc) - * @see org.apache.activemq.artemis.core.journal.SequentialFile#copyTo(org.apache.activemq.artemis.core.journal.SequentialFile) + * @see org.apache.activemq.artemis.core.io.SequentialFile#copyTo(org.apache.activemq.artemis.core.io.SequentialFile) */ public void copyTo(SequentialFile newFileName) { diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PageTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PageTest.java index 8c4ff47fcb..5accdac05e 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PageTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PageTest.java @@ -22,9 +22,9 @@ import java.util.List; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.impl.Page; import org.apache.activemq.artemis.core.paging.impl.PagedMessageImpl; @@ -52,14 +52,14 @@ public class PageTest extends ActiveMQTestBase public void testPageWithNIO() throws Exception { recreateDirectory(getTestDir()); - testAdd(new NIOSequentialFileFactory(getTestDirfile()), 1000); + testAdd(new NIOSequentialFileFactory(getTestDirfile(), 1), 1000); } @Test public void testDamagedDataWithNIO() throws Exception { recreateDirectory(getTestDir()); - testDamagedPage(new NIOSequentialFileFactory(getTestDirfile()), 1000); + testDamagedPage(new NIOSequentialFileFactory(getTestDirfile(), 1), 1000); } @Test @@ -83,7 +83,7 @@ public class PageTest extends ActiveMQTestBase protected void testAdd(final SequentialFileFactory factory, final int numberOfElements) throws Exception { - SequentialFile file = factory.createSequentialFile("00010.page", 1); + SequentialFile file = factory.createSequentialFile("00010.page"); Page impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); @@ -100,7 +100,7 @@ public class PageTest extends ActiveMQTestBase impl.sync(); impl.close(); - file = factory.createSequentialFile("00010.page", 1); + file = factory.createSequentialFile("00010.page"); file.open(); impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); @@ -130,7 +130,7 @@ public class PageTest extends ActiveMQTestBase protected void testDamagedPage(final SequentialFileFactory factory, final int numberOfElements) throws Exception { - SequentialFile file = factory.createSequentialFile("00010.page", 1); + SequentialFile file = factory.createSequentialFile("00010.page"); Page impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); @@ -172,7 +172,7 @@ public class PageTest extends ActiveMQTestBase impl.close(); - file = factory.createSequentialFile("00010.page", 1); + file = factory.createSequentialFile("00010.page"); file.open(); impl = new Page(new SimpleString("something"), new NullStorageManager(), factory, file, 10); diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PagingStoreImplTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PagingStoreImplTest.java index 1a657c1583..3863c128cb 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PagingStoreImplTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/paging/impl/PagingStoreImplTest.java @@ -34,9 +34,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.SimpleString; -import org.apache.activemq.artemis.core.journal.SequentialFile; -import org.apache.activemq.artemis.core.journal.SequentialFileFactory; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.SequentialFile; +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.paging.PageTransactionInfo; import org.apache.activemq.artemis.core.paging.PagedMessage; import org.apache.activemq.artemis.core.paging.PagingManager; @@ -129,7 +129,7 @@ public class PagingStoreImplTest extends ActiveMQTestBase public void testPageWithNIO() throws Exception { ActiveMQTestBase.recreateDirectory(getTestDir()); - testConcurrentPaging(new NIOSequentialFileFactory(new File(getTestDir())), 1); + testConcurrentPaging(new NIOSequentialFileFactory(new File(getTestDir()), 1), 1); } @Test @@ -565,7 +565,7 @@ public class PagingStoreImplTest extends ActiveMQTestBase for (String file : files) { - SequentialFile fileTmp = factory.createSequentialFile(file, 1); + SequentialFile fileTmp = factory.createSequentialFile(file); fileTmp.open(); Assert.assertTrue("The page file size (" + fileTmp.size() + ") shouldn't be > " + MAX_SIZE, fileTmp.size() <= MAX_SIZE); @@ -645,7 +645,7 @@ public class PagingStoreImplTest extends ActiveMQTestBase public void testRestartPage() throws Throwable { clearDataRecreateServerDirs(); - SequentialFileFactory factory = new NIOSequentialFileFactory(new File(getPageDir())); + SequentialFileFactory factory = new NIOSequentialFileFactory(new File(getPageDir()), 1); PagingStoreFactory storeFactory = new FakeStoreFactory(factory); @@ -682,7 +682,7 @@ public class PagingStoreImplTest extends ActiveMQTestBase public void testOrderOnPaging() throws Throwable { clearDataRecreateServerDirs(); - SequentialFileFactory factory = new NIOSequentialFileFactory(new File(getPageDir())); + SequentialFileFactory factory = new NIOSequentialFileFactory(new File(getPageDir()), 1); PagingStoreFactory storeFactory = new FakeStoreFactory(factory); diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/BatchIDGeneratorUnitTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/BatchIDGeneratorUnitTest.java index 3c1fb882e2..f89d61c080 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/BatchIDGeneratorUnitTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/BatchIDGeneratorUnitTest.java @@ -25,7 +25,7 @@ import org.apache.activemq.artemis.core.journal.Journal; import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo; import org.apache.activemq.artemis.core.journal.RecordInfo; import org.apache.activemq.artemis.core.journal.impl.JournalImpl; -import org.apache.activemq.artemis.core.journal.impl.NIOSequentialFileFactory; +import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.persistence.impl.journal.BatchingIDGenerator; import org.apache.activemq.artemis.core.persistence.impl.journal.JournalRecordIds; @@ -39,7 +39,7 @@ public class BatchIDGeneratorUnitTest extends ActiveMQTestBase @Test public void testSequence() throws Exception { - NIOSequentialFileFactory factory = new NIOSequentialFileFactory(new File(getTestDir())); + NIOSequentialFileFactory factory = new NIOSequentialFileFactory(new File(getTestDir()), 1); Journal journal = new JournalImpl(10 * 1024, 2, 0, 0, factory, "activemq-bindings", "bindings", 1); journal.start(); diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/OperationContextUnitTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/OperationContextUnitTest.java index 8e14647211..f4abbaad50 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/OperationContextUnitTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/persistence/impl/OperationContextUnitTest.java @@ -23,8 +23,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.artemis.api.core.ActiveMQExceptionType; +import org.apache.activemq.artemis.core.io.IOCallback; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.core.journal.IOAsyncTask; import org.apache.activemq.artemis.core.persistence.impl.journal.OperationContextImpl; import org.junit.Assert; import org.junit.Test; @@ -52,7 +52,7 @@ public class OperationContextUnitTest extends ActiveMQTestBase final CountDownLatch latch1 = new CountDownLatch(1); final CountDownLatch latch2 = new CountDownLatch(1); - impl.executeOnCompletion(new IOAsyncTask() + impl.executeOnCompletion(new IOCallback() { public void onError(int errorCode, String errorMessage) @@ -70,7 +70,7 @@ public class OperationContextUnitTest extends ActiveMQTestBase for (int i = 0; i < 10; i++) impl.storeLineUp(); for (int i = 0; i < 3; i++) impl.pageSyncLineUp(); - impl.executeOnCompletion(new IOAsyncTask() + impl.executeOnCompletion(new IOCallback() { public void onError(int errorCode, String errorMessage) @@ -213,7 +213,7 @@ public class OperationContextUnitTest extends ActiveMQTestBase final AtomicInteger operations = new AtomicInteger(0); // We should be up to date with lineUps and executions. this should now just finish processing - context.executeOnCompletion(new IOAsyncTask() + context.executeOnCompletion(new IOCallback() { public void done() diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/FileLockTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/FileLockTest.java index 643e6c2ce5..89c017b30e 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/FileLockTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/server/impl/FileLockTest.java @@ -17,9 +17,9 @@ package org.apache.activemq.artemis.tests.unit.core.server.impl; import java.io.File; -import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; import org.apache.activemq.artemis.core.server.impl.AIOFileLockNodeManager; import org.apache.activemq.artemis.core.server.impl.FileLockNodeManager; +import org.apache.activemq.artemis.jlibaio.LibaioContext; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Before; import org.junit.Test; @@ -47,7 +47,7 @@ public class FileLockTest extends ActiveMQTestBase @Test public void testAIOLock() throws Exception { - if (AsynchronousFileImpl.isLoaded()) + if (LibaioContext.isLoaded()) { doTestLock(new AIOFileLockNodeManager(getTestDirfile(), false), new AIOFileLockNodeManager(getTestDirfile(), false)); }