From debdc9a5cf74fbe7b377ddcc4a5bdb38f9876035 Mon Sep 17 00:00:00 2001 From: Lazar Petrovic Date: Mon, 7 Oct 2024 11:31:32 +0200 Subject: [PATCH] feat: use FileChannel for PCES (#15604) Signed-off-by: Lazar Petrovic --- .../core/jmh/PcesWriterBenchmark.java | 96 ++++++++++++++++ .../platform/event/preconsensus/PcesFile.java | 16 ++- .../preconsensus/PcesFileChannelWriter.java | 106 ++++++++++++++++++ .../event/preconsensus/PcesFileWriter.java | 56 +++++++++ .../event/preconsensus/PcesMutableFile.java | 42 +++---- .../PcesOutputStreamFileWriter.java | 97 ++++++++++++++++ .../preconsensus/PcesReadWriteTests.java | 33 ++++-- 7 files changed, 405 insertions(+), 41 deletions(-) create mode 100644 platform-sdk/swirlds-platform-core/src/jmh/java/com/swirlds/platform/core/jmh/PcesWriterBenchmark.java create mode 100644 platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileChannelWriter.java create mode 100644 platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileWriter.java create mode 100644 platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesOutputStreamFileWriter.java diff --git a/platform-sdk/swirlds-platform-core/src/jmh/java/com/swirlds/platform/core/jmh/PcesWriterBenchmark.java b/platform-sdk/swirlds-platform-core/src/jmh/java/com/swirlds/platform/core/jmh/PcesWriterBenchmark.java new file mode 100644 index 000000000000..88170304164c --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/jmh/java/com/swirlds/platform/core/jmh/PcesWriterBenchmark.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.swirlds.platform.core.jmh; + +import com.swirlds.common.io.utility.FileUtils; +import com.swirlds.common.test.fixtures.Randotron; +import com.swirlds.platform.event.AncientMode; +import com.swirlds.platform.event.PlatformEvent; +import com.swirlds.platform.event.preconsensus.PcesFile; +import com.swirlds.platform.event.preconsensus.PcesMutableFile; +import com.swirlds.platform.test.fixtures.event.TestingEventBuilder; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +@Fork(value = 1) +@Warmup(iterations = 1, time = 1) +@Measurement(iterations = 3, time = 10) +public class PcesWriterBenchmark { + + @Param({"true", "false"}) + public boolean useFileChannelWriter; + + @Param({"true", "false"}) + public boolean syncEveryEvent; + + private PlatformEvent event; + private Path directory; + private PcesMutableFile mutableFile; + + @Setup(Level.Iteration) + public void setup() throws IOException { + final Randotron r = Randotron.create(0); + + event = new TestingEventBuilder(r) + .setAppTransactionCount(3) + .setSystemTransactionCount(1) + .setSelfParent(new TestingEventBuilder(r).build()) + .setOtherParent(new TestingEventBuilder(r).build()) + .build(); + directory = Files.createTempDirectory("PcesWriterBenchmark"); + final PcesFile file = PcesFile.of(AncientMode.GENERATION_THRESHOLD, r.nextInstant(), 1, 0, 100, 0, directory); + + mutableFile = file.getMutableFile(useFileChannelWriter, syncEveryEvent); + } + + @TearDown(Level.Iteration) + public void cleanup() throws IOException { + mutableFile.close(); + FileUtils.deleteDirectory(directory); + } + /* + Results on a M1 Max MacBook Pro: + + Benchmark (syncEveryEvent) (useFileChannelWriter) Mode Cnt Score Error Units + PcesWriterBenchmark.writeEvent true true thrpt 3 12440.268 ± 42680.146 ops/s + PcesWriterBenchmark.writeEvent true false thrpt 3 16244.412 ± 38461.148 ops/s + PcesWriterBenchmark.writeEvent false true thrpt 3 411138.079 ± 110692.138 ops/s + PcesWriterBenchmark.writeEvent false false thrpt 3 643582.781 ± 154393.415 ops/s + */ + @Benchmark + @BenchmarkMode(Mode.Throughput) + @OutputTimeUnit(TimeUnit.SECONDS) + public void writeEvent() throws IOException { + mutableFile.writeEvent(event); + } +} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFile.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFile.java index 29a2c8fd282a..641e95b487f9 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFile.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFile.java @@ -392,15 +392,27 @@ public Path getPath() { return path; } + /** + * Same as {@link #getMutableFile(boolean, boolean)} with both parameters set to false. + */ + @NonNull + public PcesMutableFile getMutableFile() throws IOException { + return new PcesMutableFile(this, false, false); + } + /** * Get an object that can be used to write events to this file. Throws if there already exists a file on disk with * the same path. * + * @param useFileChannelWriter if true, use a {@link java.nio.channels.FileChannel} to write to the file. Otherwise, + * use a {@link java.io.FileOutputStream}. + * @param syncEveryEvent if true, sync the file after every event is written * @return a writer for this file */ @NonNull - public PcesMutableFile getMutableFile() throws IOException { - return new PcesMutableFile(this); + public PcesMutableFile getMutableFile(final boolean useFileChannelWriter, final boolean syncEveryEvent) + throws IOException { + return new PcesMutableFile(this, useFileChannelWriter, syncEveryEvent); } /** diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileChannelWriter.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileChannelWriter.java new file mode 100644 index 000000000000..346b98618d2e --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileChannelWriter.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.swirlds.platform.event.preconsensus; + +import com.hedera.hapi.platform.event.GossipEvent; +import com.hedera.pbj.runtime.io.WritableSequentialData; +import com.hedera.pbj.runtime.io.buffer.BufferedData; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +/** + * Writes preconsensus events to a file using a {@link FileChannel}. + */ +public class PcesFileChannelWriter implements PcesFileWriter { + /** The capacity of the ByteBuffer used to write events */ + private static final int BUFFER_CAPACITY = 1024 * 1024 * 10; + /** The file channel for writing events */ + private final FileChannel channel; + /** The buffer used to hold data being written to the file */ + private final ByteBuffer buffer; + /** Wraps a ByteBuffer so that the protobuf codec can write to it */ + private final WritableSequentialData writableSequentialData; + /** Tracks the size of the file in bytes */ + private int fileSize; + + /** + * Create a new writer that writes events to a file using a {@link FileChannel}. + * + * @param filePath the path to the file to write to + * @param syncEveryEvent if true, the file will be synced after every event is written + * @throws IOException if an error occurs while opening the file + */ + public PcesFileChannelWriter(@NonNull final Path filePath, final boolean syncEveryEvent) throws IOException { + if (syncEveryEvent) { + channel = FileChannel.open( + filePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DSYNC); + } else { + channel = FileChannel.open(filePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); + } + buffer = ByteBuffer.allocateDirect(BUFFER_CAPACITY); + writableSequentialData = BufferedData.wrap(buffer); + } + + @Override + public void writeVersion(final int version) throws IOException { + buffer.putInt(version); + flipWriteClear(); + } + + @Override + public void writeEvent(@NonNull final GossipEvent event) throws IOException { + buffer.putInt(GossipEvent.PROTOBUF.measureRecord(event)); + GossipEvent.PROTOBUF.write(event, writableSequentialData); + flipWriteClear(); + } + + /** + * Writes the data in the buffer to the file. This method expects that the buffer will have data that is written to + * it. The buffer will be flipped so that it can be read from, the data will be written to the file, and the buffer + * will be cleared so that it can be used again. + */ + private void flipWriteClear() throws IOException { + buffer.flip(); + final int bytesWritten = channel.write(buffer); + fileSize += bytesWritten; + if (bytesWritten != buffer.limit()) { + throw new IOException( + "Failed to write data to file. Wrote " + bytesWritten + " bytes out of " + buffer.limit()); + } + buffer.clear(); + } + + @Override + public void flush() throws IOException { + // benchmarks show that this has horrible performance + channel.force(false); + } + + @Override + public void close() throws IOException { + channel.close(); + } + + @Override + public long fileSize() { + return fileSize; + } +} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileWriter.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileWriter.java new file mode 100644 index 000000000000..01cc1d88ccdb --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesFileWriter.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.swirlds.platform.event.preconsensus; + +import com.hedera.hapi.platform.event.GossipEvent; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.IOException; + +/** + * Interface for writing events to a file. + */ +public interface PcesFileWriter { + + /** + * Write the version of the file format to the file. + * + * @param version the version of the file format + */ + void writeVersion(final int version) throws IOException; + + /** + * Write an event to the file. + * + * @param event the event to write + */ + void writeEvent(@NonNull final GossipEvent event) throws IOException; + + /** + * Flush the file. + */ + void flush() throws IOException; + + /** + * Close the file. + */ + void close() throws IOException; + + /** + * @return the size of the file in bytes + */ + long fileSize(); +} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesMutableFile.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesMutableFile.java index 87da9270f68b..faa107476886 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesMutableFile.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesMutableFile.java @@ -16,14 +16,8 @@ package com.swirlds.platform.event.preconsensus; -import com.hedera.hapi.platform.event.GossipEvent; -import com.swirlds.common.io.extendable.ExtendableOutputStream; -import com.swirlds.common.io.extendable.extensions.CountingStreamExtension; -import com.swirlds.common.io.streams.SerializableDataOutputStream; import com.swirlds.platform.event.PlatformEvent; import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.BufferedOutputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -38,27 +32,23 @@ public class PcesMutableFile { */ private final PcesFile descriptor; - /** - * Counts the bytes written to the file. - */ - private final CountingStreamExtension counter; + private final PcesFileWriter writer; /** * The highest ancient indicator of all events written to the file. */ private long highestAncientIdentifierInFile; - /** - * The output stream to write to. - */ - private final SerializableDataOutputStream out; - /** * Create a new preconsensus event file that can be written to. * - * @param descriptor a description of the file + * @param descriptor a description of the file + * @param useFileChannelWriter whether to use a FileChannel to write to the file as opposed to an OutputStream + * @param syncEveryEvent whether to sync the file after every event */ - PcesMutableFile(@NonNull final PcesFile descriptor) throws IOException { + PcesMutableFile( + @NonNull final PcesFile descriptor, final boolean useFileChannelWriter, final boolean syncEveryEvent) + throws IOException { if (Files.exists(descriptor.getPath())) { throw new IOException("File " + descriptor.getPath() + " already exists"); } @@ -66,12 +56,10 @@ public class PcesMutableFile { Files.createDirectories(descriptor.getPath().getParent()); this.descriptor = descriptor; - counter = new CountingStreamExtension(false); - out = new SerializableDataOutputStream(new ExtendableOutputStream( - new BufferedOutputStream( - new FileOutputStream(descriptor.getPath().toFile())), - counter)); - out.writeInt(PcesFileVersion.currentVersionNumber()); + writer = useFileChannelWriter + ? new PcesFileChannelWriter(descriptor.getPath(), syncEveryEvent) + : new PcesOutputStreamFileWriter(descriptor.getPath(), syncEveryEvent); + writer.writeVersion(PcesFileVersion.currentVersionNumber()); highestAncientIdentifierInFile = descriptor.getLowerBound(); } @@ -95,7 +83,7 @@ public void writeEvent(final PlatformEvent event) throws IOException { throw new IllegalStateException("Cannot write event " + event.getHash() + " with ancient indicator " + event.getAncientIndicator(descriptor.getFileType()) + " to file " + descriptor); } - out.writePbjRecord(event.getGossipEvent(), GossipEvent.PROTOBUF); + writer.writeEvent(event.getGossipEvent()); highestAncientIdentifierInFile = Math.max(highestAncientIdentifierInFile, event.getAncientIndicator(descriptor.getFileType())); } @@ -130,14 +118,14 @@ public PcesFile compressSpan(final long upperBoundInPreviousFile) { * Flush the file. */ public void flush() throws IOException { - out.flush(); + writer.flush(); } /** * Close the file. */ public void close() throws IOException { - out.close(); + writer.close(); } /** @@ -146,7 +134,7 @@ public void close() throws IOException { * @return the size of the file in bytes */ public long fileSize() { - return counter.getCount(); + return writer.fileSize(); } /** diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesOutputStreamFileWriter.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesOutputStreamFileWriter.java new file mode 100644 index 000000000000..92389213b9b5 --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/event/preconsensus/PcesOutputStreamFileWriter.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.swirlds.platform.event.preconsensus; + +import com.hedera.hapi.platform.event.GossipEvent; +import com.swirlds.common.io.extendable.ExtendableOutputStream; +import com.swirlds.common.io.extendable.extensions.CountingStreamExtension; +import com.swirlds.common.io.streams.SerializableDataOutputStream; +import com.swirlds.logging.legacy.LogMarker; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.BufferedOutputStream; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.SyncFailedException; +import java.nio.file.Path; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Writes events to a file using an output stream. + */ +public class PcesOutputStreamFileWriter implements PcesFileWriter { + private static final Logger logger = LogManager.getLogger(PcesOutputStreamFileWriter.class); + + /** The output stream to write to */ + private final SerializableDataOutputStream out; + /** The file descriptor of the file being written to */ + private final FileDescriptor fileDescriptor; + /** Counts the bytes written to the file */ + private final CountingStreamExtension counter; + /** Whether to sync the file after every event */ + private final boolean syncEveryEvent; + + /** + * Create a new file writer. + * + * @param filePath the path to the file to write to + * @param syncEveryEvent whether to sync the file after every event + * @throws IOException if the file cannot be opened + */ + public PcesOutputStreamFileWriter(@NonNull final Path filePath, final boolean syncEveryEvent) throws IOException { + this.syncEveryEvent = syncEveryEvent; + counter = new CountingStreamExtension(false); + final FileOutputStream fileOutputStream = new FileOutputStream(filePath.toFile()); + fileDescriptor = fileOutputStream.getFD(); + out = new SerializableDataOutputStream( + new ExtendableOutputStream(new BufferedOutputStream(fileOutputStream), counter)); + } + + @Override + public void writeVersion(final int version) throws IOException { + out.writeInt(version); + } + + @Override + public void writeEvent(@NonNull final GossipEvent event) throws IOException { + out.writePbjRecord(event, GossipEvent.PROTOBUF); + if (syncEveryEvent) { + out.flush(); + try { + fileDescriptor.sync(); + } catch (final SyncFailedException e) { + logger.error(LogMarker.EXCEPTION.getMarker(), "Failed to sync file after writing event", e); + } + } + } + + @Override + public void flush() throws IOException { + out.flush(); + } + + @Override + public void close() throws IOException { + out.close(); + } + + @Override + public long fileSize() { + return counter.getCount(); + } +} diff --git a/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/event/preconsensus/PcesReadWriteTests.java b/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/event/preconsensus/PcesReadWriteTests.java index 9514f865cda8..1f497eb65e6f 100644 --- a/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/event/preconsensus/PcesReadWriteTests.java +++ b/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/event/preconsensus/PcesReadWriteTests.java @@ -96,14 +96,23 @@ void afterEach() throws IOException { FileUtils.deleteDirectory(testDirectory); } - protected static Stream buildArguments() { + protected static Stream ancientModeArguments() { return Stream.of(Arguments.of(GENERATION_THRESHOLD), Arguments.of(BIRTH_ROUND_THRESHOLD)); } + protected static Stream ancientAndWriterTypeArguments() { + return Stream.of( + Arguments.of(GENERATION_THRESHOLD, false), + Arguments.of(BIRTH_ROUND_THRESHOLD, false), + Arguments.of(GENERATION_THRESHOLD, true), + Arguments.of(BIRTH_ROUND_THRESHOLD, true)); + } + @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientAndWriterTypeArguments") @DisplayName("Write Then Read Test") - void writeThenReadTest(@NonNull final AncientMode ancientMode) throws IOException { + void writeThenReadTest(@NonNull final AncientMode ancientMode, final boolean useFileChannelWriter) + throws IOException { final Random random = RandomUtils.getRandomPrintSeed(); final int numEvents = 100; @@ -137,7 +146,7 @@ void writeThenReadTest(@NonNull final AncientMode ancientMode) throws IOExceptio 0, testDirectory); - final PcesMutableFile mutableFile = file.getMutableFile(); + final PcesMutableFile mutableFile = file.getMutableFile(useFileChannelWriter, false); for (final PlatformEvent event : events) { mutableFile.writeEvent(event); } @@ -154,7 +163,7 @@ void writeThenReadTest(@NonNull final AncientMode ancientMode) throws IOExceptio } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Read Files After Minimum Test") void readFilesAfterMinimumTest(@NonNull final AncientMode ancientMode) throws IOException { final Random random = RandomUtils.getRandomPrintSeed(); @@ -219,7 +228,7 @@ void readFilesAfterMinimumTest(@NonNull final AncientMode ancientMode) throws IO } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Read Empty File Test") void readEmptyFileTest(@NonNull final AncientMode ancientMode) throws IOException { final Random random = RandomUtils.getRandomPrintSeed(); @@ -241,7 +250,7 @@ void readEmptyFileTest(@NonNull final AncientMode ancientMode) throws IOExceptio } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Truncated Event Test") void truncatedEventTest(@NonNull final AncientMode ancientMode) throws IOException { for (final boolean truncateOnBoundary : List.of(true, false)) { @@ -311,7 +320,7 @@ void truncatedEventTest(@NonNull final AncientMode ancientMode) throws IOExcepti } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Corrupted Events Test") void corruptedEventsTest(@NonNull final AncientMode ancientMode) throws IOException { final Random random = RandomUtils.getRandomPrintSeed(); @@ -375,7 +384,7 @@ void corruptedEventsTest(@NonNull final AncientMode ancientMode) throws IOExcept } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Write Invalid Event Test") void writeInvalidEventTest(@NonNull final AncientMode ancientMode) throws IOException { final Random random = RandomUtils.getRandomPrintSeed(); @@ -438,7 +447,7 @@ void writeInvalidEventTest(@NonNull final AncientMode ancientMode) throws IOExce } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Span Compression Test") void spanCompressionTest(@NonNull final AncientMode ancientMode) throws IOException { final Random random = RandomUtils.getRandomPrintSeed(0); @@ -504,7 +513,7 @@ void spanCompressionTest(@NonNull final AncientMode ancientMode) throws IOExcept } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Partial Span Compression Test") void partialSpanCompressionTest(@NonNull final AncientMode ancientMode) throws IOException { final Random random = RandomUtils.getRandomPrintSeed(0); @@ -573,7 +582,7 @@ void partialSpanCompressionTest(@NonNull final AncientMode ancientMode) throws I } @ParameterizedTest - @MethodSource("buildArguments") + @MethodSource("ancientModeArguments") @DisplayName("Empty File Test") void emptyFileTest(@NonNull final AncientMode ancientMode) throws IOException { final PcesFile file = PcesFile.of(ancientMode, Instant.now(), 0, 0, 100, 0, testDirectory);