diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FileHashUtil.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/FileHashUtil.java new file mode 100644 index 000000000000..8a2b892f2376 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/FileHashUtil.java @@ -0,0 +1,66 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.jps.incremental; + +import com.dynatrace.hash4j.hashing.HashSink; +import com.dynatrace.hash4j.hashing.Hashing; +import com.intellij.openapi.util.SystemInfoRt; +import com.intellij.openapi.util.text.StringUtilRt; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.incremental.storage.ProjectStamps; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +@ApiStatus.Internal +public final class FileHashUtil { + + /** + * @param path a normalized system-independent path, possibly relative, but without "." and ".." relative references + * @param hash hash sink to be updated + */ + public static void computePathHashCode(@Nullable String path, HashSink hash) { + int length = path == null? 0 : path.length(); + if (length == 0) { + hash.putInt(0); + } + else if (ProjectStamps.PORTABLE_CACHES || SystemInfoRt.isFileSystemCaseSensitive) { + hash.putString(path); + } + else { + for (int idx = 0; idx < length; idx++) { + hash.putChar(StringUtilRt.toLowerCase(path.charAt(idx))); + } + hash.putInt(length); + } + } + + public static long getFileHash(Path file) throws IOException { + var hash = Hashing.komihash5_0().hashStream(); + getFileHash(file, hash); + return hash.getAsLong(); + } + + public static void getFileHash(Path file, HashSink hash) throws IOException { + try (FileChannel channel = FileChannel.open(file, StandardOpenOption.READ)) { + long fileSize = channel.size(); + ByteBuffer buffer = ByteBuffer.allocate(256 * 1024); + long offset = 0L; + while (offset < fileSize) { + buffer.clear(); + int readBytes = channel.read(buffer, offset); + if (readBytes > 0) { + hash.putBytes(buffer.array(), 0, readBytes); + offset += readBytes; + } + else { + break; + } + } + hash.putLong(fileSize); + } + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/FileHashUtil.kt b/jps/jps-builders/src/org/jetbrains/jps/incremental/FileHashUtil.kt deleted file mode 100644 index 8bb883a3e179..000000000000 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/FileHashUtil.kt +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package org.jetbrains.jps.incremental - -import com.dynatrace.hash4j.hashing.HashSink -import com.dynatrace.hash4j.hashing.Hashing -import com.intellij.openapi.util.SystemInfoRt -import com.intellij.openapi.util.text.StringUtilRt -import org.jetbrains.annotations.ApiStatus.Internal -import org.jetbrains.jps.incremental.storage.ProjectStamps -import java.io.IOException -import java.nio.ByteBuffer -import java.nio.channels.FileChannel -import java.nio.file.Path -import java.nio.file.StandardOpenOption - -@Internal -@Throws(IOException::class) -fun getFileHash(file: Path): Long { - val hash = Hashing.komihash5_0().hashStream() - getFileHash(file, hash) - return hash.asLong -} - -@Internal -@Throws(IOException::class) -fun getFileHash(file: Path, hash: HashSink) { - FileChannel.open(file, StandardOpenOption.READ).use { channel -> - val fileSize = channel.size() - val buffer = ByteBuffer.allocate(256 * 1024) - var offset = 0L - var readBytes: Int - while (offset < fileSize) { - buffer.clear() - readBytes = channel.read(buffer, offset) - if (readBytes <= 0) { - break - } - - hash.putBytes(buffer.array(), 0, readBytes) - offset += readBytes - } - hash.putLong(fileSize) - } -} - -/** path must be absolute ([Path.toAbsolutePath]), normalized ([Path.normalize]) and system-independent */ -@Internal -fun normalizedPathHashCode(path: String, hash: HashSink) { - if (path.isEmpty()) { - hash.putInt(0) - return - } - - val length = path.length - if (ProjectStamps.PORTABLE_CACHES || SystemInfoRt.isFileSystemCaseSensitive) { - hash.putChars(path) - } - else { - for (offset in 0 until length) { - hash.putChar(StringUtilRt.toLowerCase(path[offset])) - } - } - - hash.putInt(length) -} \ No newline at end of file diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java index d1aea01a4736..8dee29200a0e 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleBuildTarget.java @@ -43,9 +43,6 @@ import java.util.Collection; import java.util.List; import java.util.Set; -import static org.jetbrains.jps.incremental.FileHashUtilKt.getFileHash; -import static org.jetbrains.jps.incremental.FileHashUtilKt.normalizedPathHashCode; - /** * Describes a step of compilation process which produces JVM *.class files from files in production/test source roots of a Java module. * These targets are built by {@link ModuleLevelBuilder} and they are the only targets that can have circular dependencies on each other. @@ -189,7 +186,7 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget roots = projectDescriptor.getBuildRootIndex().getTargetRoots(this, null); for (ResourceRootDescriptor root : roots) { String path = relativizer.toRelative(root.rootFile.toString()); - normalizedPathHashCode(path, hash); + FileHashUtil.computePathHashCode(path, hash); hash.putString(root.getPackagePrefix()); } hash.putInt(roots.size()); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildTargetSourcesState.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildTargetSourcesState.java index 28c101c38197..a5fffeefb237 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildTargetSourcesState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/BuildTargetSourcesState.java @@ -23,7 +23,7 @@ import org.jetbrains.jps.cache.model.BuildTargetState; import org.jetbrains.jps.cmdline.ProjectDescriptor; import org.jetbrains.jps.incremental.BuildListener; import org.jetbrains.jps.incremental.CompileContext; -import org.jetbrains.jps.incremental.FileHashUtilKt; +import org.jetbrains.jps.incremental.FileHashUtil; import org.jetbrains.jps.incremental.messages.FileDeletedEvent; import org.jetbrains.jps.incremental.messages.FileGeneratedEvent; import org.jetbrains.jps.incremental.relativizer.PathRelativizerService; @@ -334,7 +334,7 @@ public final class BuildTargetSourcesState implements BuildListener { private static long getOutputFileHash(@NotNull Path file, @NotNull Path rootPath, @NotNull HashStream64 hashToReuse) throws IOException { // reduce GC - reuse hashToReuse - do not inline fileHash variable - FileHashUtilKt.getFileHash(file, hashToReuse.reset()); + FileHashUtil.getFileHash(file, hashToReuse.reset()); long fileHash = hashToReuse.getAsLong(); return hashToReuse .reset() diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/HashStampStorage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/HashStampStorage.java index f25a6850617e..de4d84fcde60 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/HashStampStorage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/storage/HashStampStorage.java @@ -5,6 +5,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.io.DataExternalizer; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.builders.BuildTarget; +import org.jetbrains.jps.incremental.FileHashUtil; import org.jetbrains.jps.incremental.relativizer.PathRelativizerService; import java.io.DataInput; @@ -14,7 +15,6 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; -import static org.jetbrains.jps.incremental.FileHashUtilKt.getFileHash; import static org.jetbrains.jps.incremental.storage.FileTimestampStorage.FileTimestamp; import static org.jetbrains.jps.incremental.storage.HashStampStorage.HashStampPerTarget; @@ -122,7 +122,7 @@ final class HashStampStorage extends AbstractStateStorage