diff --git a/pom.xml b/pom.xml index 5fdc59f77d..87f13b5c39 100644 --- a/pom.xml +++ b/pom.xml @@ -184,6 +184,7 @@ 3.3.0 3.1.0 1.6.1 + 2.4.0 2.2.0 0.6.1 @@ -529,7 +530,36 @@ + + + de.skuzzle.enforcer + restrict-imports-enforcer-rule + ${restrict-imports-enforcer-rules.version} + + + + + bannedImports-finalizers + process-sources + + enforce + + + + + false + Classes (e.g. FileInputStream, FileOutputStream) overriding the Object.finalize() method will cause gc to run a much longer time. As stated in Effective Java, there is a severe performance penalty for using finalizers. + + java.io.FileInputStream + java.io.FileOutputStream + + + + + + + org.apache.maven.plugins maven-assembly-plugin diff --git a/ratis-common/src/main/java/org/apache/ratis/protocol/RaftId.java b/ratis-common/src/main/java/org/apache/ratis/protocol/RaftId.java index f1d07a9800..161bd830bd 100644 --- a/ratis-common/src/main/java/org/apache/ratis/protocol/RaftId.java +++ b/ratis-common/src/main/java/org/apache/ratis/protocol/RaftId.java @@ -20,7 +20,7 @@ import org.apache.ratis.thirdparty.com.google.common.cache.Cache; import org.apache.ratis.thirdparty.com.google.common.cache.CacheBuilder; import org.apache.ratis.thirdparty.com.google.protobuf.ByteString; -import org.apache.ratis.thirdparty.com.google.protobuf.ByteStringUtils; +import org.apache.ratis.thirdparty.com.google.protobuf.UnsafeByteOperations; import org.apache.ratis.util.JavaUtils; import org.apache.ratis.util.Preconditions; @@ -49,7 +49,7 @@ static ByteString toByteString(UUID uuid) { ByteBuffer.wrap(array) .putLong(uuid.getMostSignificantBits()) .putLong(uuid.getLeastSignificantBits()); - return ByteStringUtils.unsafeWrap(array); + return UnsafeByteOperations.unsafeWrap(array); } abstract static class Factory { diff --git a/ratis-common/src/main/java/org/apache/ratis/thirdparty/com/google/protobuf/ByteStringUtils.java b/ratis-common/src/main/java/org/apache/ratis/thirdparty/com/google/protobuf/ByteStringUtils.java deleted file mode 100644 index 85174979fb..0000000000 --- a/ratis-common/src/main/java/org/apache/ratis/thirdparty/com/google/protobuf/ByteStringUtils.java +++ /dev/null @@ -1,30 +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.ratis.thirdparty.com.google.protobuf; - -/** Utilities for {@link ByteString}. */ -public interface ByteStringUtils { - /** - * Wrap the given array. - * Note that the content of the array must not be changed. - * Otherwise, it violates the immutability of {@link ByteString}. - */ - static ByteString unsafeWrap(byte[] array) { - return ByteString.wrap(array); - } -} diff --git a/ratis-examples/src/main/java/org/apache/ratis/examples/arithmetic/ArithmeticStateMachine.java b/ratis-examples/src/main/java/org/apache/ratis/examples/arithmetic/ArithmeticStateMachine.java index ac7b199fc6..28e3fb1c7d 100644 --- a/ratis-examples/src/main/java/org/apache/ratis/examples/arithmetic/ArithmeticStateMachine.java +++ b/ratis-examples/src/main/java/org/apache/ratis/examples/arithmetic/ArithmeticStateMachine.java @@ -34,14 +34,13 @@ import org.apache.ratis.statemachine.impl.SimpleStateMachineStorage; import org.apache.ratis.statemachine.impl.SingleFileSnapshotInfo; import org.apache.ratis.util.AutoCloseableLock; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.JavaUtils; import org.apache.ratis.util.MD5FileUtil; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -97,8 +96,8 @@ public long takeSnapshot() { final File snapshotFile = storage.getSnapshotFile(last.getTerm(), last.getIndex()); LOG.info("Taking a snapshot to file {}", snapshotFile); - try(ObjectOutputStream out = new ObjectOutputStream( - new BufferedOutputStream(new FileOutputStream(snapshotFile)))) { + try(ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream( + FileUtils.newOutputStream(snapshotFile)))) { out.writeObject(copy); } catch(IOException ioe) { LOG.warn("Failed to write snapshot file \"" + snapshotFile @@ -130,8 +129,8 @@ public long loadSnapshot(SingleFileSnapshotInfo snapshot) throws IOException { final TermIndex last = SimpleStateMachineStorage.getTermIndexFromSnapshotFile(snapshotFile); try(AutoCloseableLock writeLock = writeLock(); - ObjectInputStream in = new ObjectInputStream( - new BufferedInputStream(new FileInputStream(snapshotFile)))) { + ObjectInputStream in = new ObjectInputStream(new BufferedInputStream( + FileUtils.newInputStream(snapshotFile)))) { reset(); setLastAppliedTermIndex(last); variables.putAll(JavaUtils.cast(in.readObject())); diff --git a/ratis-examples/src/main/java/org/apache/ratis/examples/common/Constants.java b/ratis-examples/src/main/java/org/apache/ratis/examples/common/Constants.java index c7559597e0..cfe5757146 100644 --- a/ratis-examples/src/main/java/org/apache/ratis/examples/common/Constants.java +++ b/ratis-examples/src/main/java/org/apache/ratis/examples/common/Constants.java @@ -21,14 +21,12 @@ import org.apache.ratis.protocol.RaftGroup; import org.apache.ratis.protocol.RaftGroupId; import org.apache.ratis.protocol.RaftPeer; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.TimeDuration; import java.io.BufferedReader; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; -import java.io.Reader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -52,10 +50,9 @@ public final class Constants { static { final Properties properties = new Properties(); final String conf = "ratis-examples/src/main/resources/conf.properties"; - try(InputStream inputStream = new FileInputStream(conf); - Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); - BufferedReader bufferedReader = new BufferedReader(reader)) { - properties.load(bufferedReader); + try(BufferedReader in = new BufferedReader(new InputStreamReader( + FileUtils.newInputStream(conf), StandardCharsets.UTF_8))) { + properties.load(in); } catch (IOException e) { throw new IllegalStateException("Failed to load " + conf, e); } diff --git a/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/DataStream.java b/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/DataStream.java index bb9942a806..4e4b4dbc64 100644 --- a/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/DataStream.java +++ b/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/DataStream.java @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -26,14 +26,15 @@ import org.apache.ratis.protocol.RoutingTable; import org.apache.ratis.thirdparty.io.netty.buffer.ByteBuf; import org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.JavaUtils; import org.apache.ratis.util.Preconditions; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -238,8 +239,7 @@ List> transfer( final List> futures = new ArrayList<>(); final DataStreamOutput out = client.getStreamOutput(file.getName(), fileSize, routingTable); - try (FileInputStream fis = new FileInputStream(file)) { - final FileChannel in = fis.getChannel(); + try (FileChannel in = FileUtils.newFileChannel(file, StandardOpenOption.READ)) { for (long offset = 0L; offset < fileSize; ) { offset += write(in, out, offset, futures); } diff --git a/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/LoadGen.java b/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/LoadGen.java index 3fd4714d23..8225df9eef 100644 --- a/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/LoadGen.java +++ b/ratis-examples/src/main/java/org/apache/ratis/examples/filestore/cli/LoadGen.java @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -22,11 +22,12 @@ import org.apache.ratis.examples.filestore.FileStoreClient; import org.apache.ratis.thirdparty.io.netty.buffer.ByteBuf; import org.apache.ratis.thirdparty.io.netty.buffer.PooledByteBufAllocator; +import org.apache.ratis.util.FileUtils; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.nio.channels.FileChannel; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -97,8 +98,7 @@ private Map>>> writeByHea CompletableFuture.supplyAsync(() -> { List> futures = new ArrayList<>(); File file = new File(path); - try (FileInputStream fis = new FileInputStream(file)) { - final FileChannel in = fis.getChannel(); + try (FileChannel in = FileUtils.newFileChannel(file, StandardOpenOption.READ)) { for (long offset = 0L; offset < getFileSizeInBytes(); ) { offset += write(in, offset, client, file.getName(), futures); } diff --git a/ratis-server/src/main/java/org/apache/ratis/server/raftlog/segmented/SegmentedRaftLogReader.java b/ratis-server/src/main/java/org/apache/ratis/server/raftlog/segmented/SegmentedRaftLogReader.java index 53cb061861..c8170f9b1a 100644 --- a/ratis-server/src/main/java/org/apache/ratis/server/raftlog/segmented/SegmentedRaftLogReader.java +++ b/ratis-server/src/main/java/org/apache/ratis/server/raftlog/segmented/SegmentedRaftLogReader.java @@ -19,12 +19,13 @@ import org.apache.ratis.io.CorruptedFileException; import org.apache.ratis.metrics.Timekeeper; +import org.apache.ratis.proto.RaftProtos.LogEntryProto; import org.apache.ratis.protocol.exceptions.ChecksumException; import org.apache.ratis.server.metrics.SegmentedRaftLogMetrics; import org.apache.ratis.server.raftlog.RaftLog; import org.apache.ratis.thirdparty.com.google.protobuf.CodedInputStream; import org.apache.ratis.thirdparty.com.google.protobuf.CodedOutputStream; -import org.apache.ratis.proto.RaftProtos.LogEntryProto; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.IOUtils; import org.apache.ratis.util.Preconditions; import org.apache.ratis.util.PureJavaCrc32C; @@ -33,7 +34,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.Closeable; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.Optional; import java.util.zip.Checksum; @@ -41,7 +49,7 @@ class SegmentedRaftLogReader implements Closeable { static final Logger LOG = LoggerFactory.getLogger(SegmentedRaftLogReader.class); /** * InputStream wrapper that keeps track of the current stream position. - * + *

* This stream also allows us to set a limit on how many bytes we can read * without getting an exception. */ @@ -141,11 +149,9 @@ public long skip(long amt) throws IOException { private final SegmentedRaftLogMetrics raftLogMetrics; private final SizeInBytes maxOpSize; - SegmentedRaftLogReader(File file, SizeInBytes maxOpSize, SegmentedRaftLogMetrics raftLogMetrics) - throws FileNotFoundException { + SegmentedRaftLogReader(File file, SizeInBytes maxOpSize, SegmentedRaftLogMetrics raftLogMetrics) throws IOException { this.file = file; - this.limiter = new LimitedInputStream( - new BufferedInputStream(new FileInputStream(file))); + this.limiter = new LimitedInputStream(new BufferedInputStream(FileUtils.newInputStream(file))); in = new DataInputStream(limiter); checksum = new PureJavaCrc32C(); this.maxOpSize = maxOpSize; @@ -154,13 +160,10 @@ public long skip(long amt) throws IOException { /** * Read header from the log file: - * * (1) The header in file is verified successfully. * Then, return true. - * * (2) The header in file is partially written. * Then, return false. - * * (3) The header in file is corrupted or there is some other {@link IOException}. * Then, throw an exception. */ @@ -197,7 +200,7 @@ LogEntryProto readEntry() throws IOException { final Timekeeper timekeeper = Optional.ofNullable(raftLogMetrics) .map(SegmentedRaftLogMetrics::getReadEntryTimer) .orElse(null); - try(AutoCloseable readEntryContext = Timekeeper.start(timekeeper)) { + try(AutoCloseable ignored = Timekeeper.start(timekeeper)) { return decodeEntry(); } catch (EOFException eof) { in.reset(); diff --git a/ratis-server/src/main/java/org/apache/ratis/server/storage/FileChunkReader.java b/ratis-server/src/main/java/org/apache/ratis/server/storage/FileChunkReader.java index dfed2790f7..65bfc8b809 100644 --- a/ratis-server/src/main/java/org/apache/ratis/server/storage/FileChunkReader.java +++ b/ratis-server/src/main/java/org/apache/ratis/server/storage/FileChunkReader.java @@ -21,12 +21,12 @@ import org.apache.ratis.proto.RaftProtos.FileChunkProto; import org.apache.ratis.thirdparty.com.google.protobuf.ByteString; import org.apache.ratis.thirdparty.com.google.protobuf.UnsafeByteOperations; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.IOUtils; import org.apache.ratis.util.JavaUtils; import java.io.Closeable; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; @@ -57,13 +57,19 @@ public FileChunkReader(FileInfo info, Path relativePath) throws IOException { final File f = info.getPath().toFile(); if (info.getFileDigest() == null) { digester = MD5Hash.getDigester(); - this.in = new DigestInputStream(new FileInputStream(f), digester); + this.in = new DigestInputStream(FileUtils.newInputStream(f), digester); } else { digester = null; - this.in = new FileInputStream(f); + this.in = FileUtils.newInputStream(f); } } + static ByteString readFileChunk(int chunkLength, InputStream in) throws IOException { + final byte[] chunkBuffer = new byte[chunkLength]; + IOUtils.readFully(in, chunkBuffer, 0, chunkBuffer.length); + return UnsafeByteOperations.unsafeWrap(chunkBuffer); + } + /** * Read the next chunk. * @@ -74,9 +80,7 @@ public FileChunkReader(FileInfo info, Path relativePath) throws IOException { public FileChunkProto readFileChunk(int chunkMaxSize) throws IOException { final long remaining = info.getFileSize() - offset; final int chunkLength = remaining < chunkMaxSize ? (int) remaining : chunkMaxSize; - final byte[] chunkBuffer = new byte[chunkLength]; - IOUtils.readFully(in, chunkBuffer, 0, chunkBuffer.length); - final ByteString data = UnsafeByteOperations.unsafeWrap(chunkBuffer); + final ByteString data = readFileChunk(chunkLength, in); // whether this chunk is the last chunk of current file final boolean isDone = offset + chunkLength == info.getFileSize(); final ByteString fileDigest; diff --git a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java index 4fcf46389c..fbb7bf7d46 100644 --- a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java +++ b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java @@ -17,21 +17,23 @@ */ package org.apache.ratis.server.storage; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.NoSuchFileException; import java.util.concurrent.atomic.AtomicReference; import org.apache.ratis.proto.RaftProtos.LogEntryProto; import org.apache.ratis.server.RaftConfiguration; import org.apache.ratis.server.RaftServerConfigKeys.Log.CorruptionPolicy; import org.apache.ratis.server.raftlog.LogProtoUtils; import org.apache.ratis.server.storage.RaftStorageDirectoryImpl.StorageState; +import org.apache.ratis.util.AtomicFileOutputStream; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.JavaUtils; import org.apache.ratis.util.SizeInBytes; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.nio.file.Files; import java.util.Optional; /** The storage of a {@link org.apache.ratis.server.RaftServer}. */ @@ -98,7 +100,7 @@ private void format() throws IOException { } private void cleanMetaTmpFile() throws IOException { - Files.deleteIfExists(storageDir.getMetaTmpFile().toPath()); + FileUtils.deleteIfExists(storageDir.getMetaTmpFile()); } private StorageState analyzeAndRecoverStorage(boolean toLock) throws IOException { @@ -142,7 +144,7 @@ public RaftStorageMetadataFile getMetadataFile() { public void writeRaftConfiguration(LogEntryProto conf) { File confFile = storageDir.getMetaConfFile(); - try (FileOutputStream fio = new FileOutputStream(confFile)) { + try (OutputStream fio = new AtomicFileOutputStream(confFile)) { conf.writeTo(fio); } catch (Exception e) { LOG.error("Failed writing configuration to file:" + confFile, e); @@ -151,10 +153,10 @@ public void writeRaftConfiguration(LogEntryProto conf) { public RaftConfiguration readRaftConfiguration() { File confFile = storageDir.getMetaConfFile(); - try (FileInputStream fio = new FileInputStream(confFile)) { + try (InputStream fio = FileUtils.newInputStream(confFile)) { LogEntryProto confProto = LogEntryProto.newBuilder().mergeFrom(fio).build(); return LogProtoUtils.toRaftConfiguration(confProto); - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { return null; } catch (Exception e) { LOG.error("Failed reading configuration from file:" + confFile, e); diff --git a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageMetadataFileImpl.java b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageMetadataFileImpl.java index 1fb723f811..896a5f21e6 100644 --- a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageMetadataFileImpl.java +++ b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageMetadataFileImpl.java @@ -20,12 +20,12 @@ import org.apache.ratis.protocol.RaftPeerId; import org.apache.ratis.util.AtomicFileOutputStream; import org.apache.ratis.util.ConcurrentUtils; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.JavaUtils; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -110,7 +110,7 @@ static RaftStorageMetadata load(File file) throws IOException { return RaftStorageMetadata.getDefault(); } try(BufferedReader br = new BufferedReader(new InputStreamReader( - new FileInputStream(file), StandardCharsets.UTF_8))) { + FileUtils.newInputStream(file), StandardCharsets.UTF_8))) { Properties properties = new Properties(); properties.load(br); return RaftStorageMetadata.valueOf(getTerm(properties), getVotedFor(properties)); diff --git a/ratis-server/src/main/java/org/apache/ratis/server/storage/SnapshotManager.java b/ratis-server/src/main/java/org/apache/ratis/server/storage/SnapshotManager.java index 8d291acb28..c49a86ec59 100644 --- a/ratis-server/src/main/java/org/apache/ratis/server/storage/SnapshotManager.java +++ b/ratis-server/src/main/java/org/apache/ratis/server/storage/SnapshotManager.java @@ -27,7 +27,6 @@ import org.apache.ratis.statemachine.StateMachine; import org.apache.ratis.statemachine.StateMachineStorage; import org.apache.ratis.util.FileUtils; -import org.apache.ratis.util.IOUtils; import org.apache.ratis.util.JavaUtils; import org.apache.ratis.util.MD5FileUtil; import org.apache.ratis.util.MemoizedSupplier; @@ -37,11 +36,12 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileOutputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Path; -import java.security.DigestOutputStream; +import java.nio.file.StandardOpenOption; import java.security.MessageDigest; import java.util.Optional; import java.util.function.Function; @@ -77,6 +77,28 @@ public class SnapshotManager { new File(dir.get().getRoot(), c.getFilename()).toPath()).toString(); } + private FileChannel open(FileChunkProto chunk, File tmpSnapshotFile) throws IOException { + final FileChannel out; + final boolean exists = tmpSnapshotFile.exists(); + if (chunk.getOffset() == 0) { + // if offset is 0, delete any existing temp snapshot file if it has the same last index. + if (exists) { + FileUtils.deleteFully(tmpSnapshotFile); + } + // create the temp snapshot file and put padding inside + out = FileUtils.newFileChannel(tmpSnapshotFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE); + digester.get().reset(); + } else { + if (!exists) { + throw new FileNotFoundException("Chunk offset is non-zero but file is not found: " + tmpSnapshotFile + + ", chunk=" + chunk); + } + out = FileUtils.newFileChannel(tmpSnapshotFile, StandardOpenOption.WRITE) + .position(chunk.getOffset()); + } + return out; + } + public void installSnapshot(InstallSnapshotRequestProto request, StateMachine stateMachine) throws IOException { final InstallSnapshotRequestProto.SnapshotChunkProto snapshotChunkRequest = request.getSnapshotChunk(); final long lastIncludedIndex = snapshotChunkRequest.getTermIndex().getIndex(); @@ -103,30 +125,15 @@ public void installSnapshot(InstallSnapshotRequestProto request, StateMachine st final File tmpSnapshotFile = new File(tmpDir, getRelativePath.apply(chunk)); FileUtils.createDirectoriesDeleteExistingNonDirectory(tmpSnapshotFile.getParentFile()); - FileOutputStream out = null; - try { - // if offset is 0, delete any existing temp snapshot file if it has the - // same last index. - if (chunk.getOffset() == 0) { - if (tmpSnapshotFile.exists()) { - FileUtils.deleteFully(tmpSnapshotFile); - } - // create the temp snapshot file and put padding inside - out = new FileOutputStream(tmpSnapshotFile); - digester.get().reset(); - } else { - Preconditions.assertTrue(tmpSnapshotFile.exists()); - out = new FileOutputStream(tmpSnapshotFile, true); - FileChannel fc = out.getChannel(); - fc.position(chunk.getOffset()); - } + try (FileChannel out = open(chunk, tmpSnapshotFile)) { + final ByteBuffer data = chunk.getData().asReadOnlyByteBuffer(); + digester.get().update(data.duplicate()); - // write data to the file - try (DigestOutputStream digestOut = new DigestOutputStream(out, digester.get())) { - digestOut.write(chunk.getData().toByteArray()); + int written = 0; + for(; data.remaining() > 0; ) { + written += out.write(data); } - } finally { - IOUtils.cleanup(null, out); + Preconditions.assertSame(chunk.getData().size(), written, "written"); } // rename the temp snapshot file if this is the last chunk. also verify diff --git a/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamClusterTests.java b/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamClusterTests.java index dcb54be3d8..959cb3fc04 100644 --- a/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamClusterTests.java +++ b/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamClusterTests.java @@ -32,13 +32,15 @@ import org.apache.ratis.protocol.RaftClientRequest; import org.apache.ratis.server.RaftServer; import org.apache.ratis.util.CollectionUtils; +import org.apache.ratis.util.FileUtils; import org.apache.ratis.util.Timestamp; import org.apache.ratis.util.function.CheckedConsumer; import org.junit.Assert; import org.junit.Test; import java.io.File; -import java.io.FileInputStream; +import java.nio.channels.FileChannel; +import java.nio.file.StandardOpenOption; import java.util.Collection; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; @@ -151,8 +153,8 @@ static CheckedConsumer transferToWritableByteCh return new CheckedConsumer() { @Override public void accept(DataStreamOutputImpl out) throws Exception { - try (FileInputStream in = new FileInputStream(f)) { - final long transferred = in.getChannel().transferTo(0, size, out.getWritableByteChannel()); + try (FileChannel in = FileUtils.newFileChannel(f, StandardOpenOption.READ)) { + final long transferred = in.transferTo(0, size, out.getWritableByteChannel()); Assert.assertEquals(size, transferred); } } diff --git a/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamTestUtils.java b/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamTestUtils.java index 906071dfaa..7666bacd96 100644 --- a/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamTestUtils.java +++ b/ratis-test/src/test/java/org/apache/ratis/datastream/DataStreamTestUtils.java @@ -54,9 +54,10 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileOutputStream; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -114,8 +115,8 @@ public int read(ByteBuffer dst) { } }; FileUtils.createDirectories(f.getParentFile()); - try(FileOutputStream out = new FileOutputStream(f)) { - final long transferred = out.getChannel().transferFrom(source, 0, size); + try(FileChannel out = FileUtils.newFileChannel(f, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { + final long transferred = out.transferFrom(source, 0, size); Assert.assertEquals(size, transferred); } } diff --git a/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java b/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java index a981282fdc..d6222b2271 100644 --- a/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java +++ b/ratis-test/src/test/java/org/apache/ratis/security/SecurityTestUtils.java @@ -20,6 +20,7 @@ import org.apache.ratis.security.TlsConf.Builder; import org.apache.ratis.security.TlsConf.CertificatesConf; import org.apache.ratis.security.TlsConf.PrivateKeyConf; +import org.apache.ratis.util.FileUtils; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; import org.junit.Assert; @@ -32,8 +33,8 @@ import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import java.io.File; -import java.io.FileInputStream; import java.io.FileReader; +import java.io.InputStream; import java.net.URL; import java.security.KeyFactory; import java.security.KeyStore; @@ -110,7 +111,7 @@ static X509Certificate[] getCertificate(String certPath) { // Read certificates X509Certificate[] certificate = new X509Certificate[1]; CertificateFactory fact = CertificateFactory.getInstance("X.509"); - try (FileInputStream is = new FileInputStream(getResource(certPath))) { + try (InputStream is = FileUtils.newInputStream(getResource(certPath))) { certificate[0] = (X509Certificate) fact.generateCertificate(is); } return certificate; diff --git a/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestLogSegment.java b/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestLogSegment.java index 0a58f44f67..755476bf52 100644 --- a/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestLogSegment.java +++ b/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestLogSegment.java @@ -108,9 +108,11 @@ File prepareLog(boolean isOpen, long startIndex, int numEntries, long term, bool // 0 < truncatedEntrySize < entrySize final long fileLength = file.length(); final long truncatedFileLength = fileLength - (entrySize - truncatedEntrySize); + Assert.assertTrue(truncatedFileLength < fileLength); LOG.info("truncate last entry: entry(size={}, truncated={}), file(length={}, truncated={})", entrySize, truncatedEntrySize, fileLength, truncatedFileLength); FileUtils.truncateFile(file, truncatedFileLength); + Assert.assertEquals(truncatedFileLength, file.length()); } storage.close(); diff --git a/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestRaftLogReadWrite.java b/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestRaftLogReadWrite.java index e79f9f7f97..a020b43bd8 100644 --- a/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestRaftLogReadWrite.java +++ b/ratis-test/src/test/java/org/apache/ratis/server/raftlog/segmented/TestRaftLogReadWrite.java @@ -35,10 +35,11 @@ import org.junit.Test; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -201,10 +202,10 @@ public void testReadWithCorruptPadding() throws IOException { // make sure the file contains padding Assert.assertEquals(4 * 1024 * 1024, openSegment.length()); - try (FileOutputStream fout = new FileOutputStream(openSegment, true)) { - ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[]{-1, 1}); - fout.getChannel() - .write(byteBuffer, 16 * 1024 * 1024 - 10); + try (FileChannel fout = FileUtils.newFileChannel(openSegment, StandardOpenOption.WRITE)) { + final byte[] array = {-1, 1}; + final int written = fout.write(ByteBuffer.wrap(array), 16 * 1024 * 1024 - 10); + Assert.assertEquals(array.length, written); } List list = new ArrayList<>();