diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/BaseMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/BaseMaplet.java new file mode 100644 index 000000000000..45f6401b7e76 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/BaseMaplet.java @@ -0,0 +1,24 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.jps.dependency; + +import org.jetbrains.annotations.NotNull; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; + +public interface BaseMaplet extends Closeable, Flushable { + + boolean containsKey(K key); + + void remove(K key); + + @NotNull + Iterable getKeys(); + + @Override + void close() throws IOException; + + @Override + void flush() throws IOException; +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/Maplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/Maplet.java index a3f56176691e..96d56cb28135 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/Maplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/Maplet.java @@ -3,21 +3,10 @@ package org.jetbrains.jps.dependency; import org.jetbrains.annotations.Nullable; -import java.io.Closeable; -import java.io.IOException; - -public interface Maplet extends Closeable { - boolean containsKey(final K key); +public interface Maplet extends BaseMaplet { @Nullable V get(final K key); void put(K key, V value); - - void remove(K key); - - Iterable getKeys(); - - @Override - void close() throws IOException; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/MultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/MultiMaplet.java index e084bc64dfc3..d44831624285 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/MultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/MultiMaplet.java @@ -3,20 +3,13 @@ package org.jetbrains.jps.dependency; import org.jetbrains.annotations.NotNull; -import java.io.Closeable; -import java.io.IOException; - -public interface MultiMaplet extends Closeable { - - boolean containsKey(K key); +public interface MultiMaplet extends BaseMaplet { @NotNull Iterable get(K key); void put(K key, @NotNull Iterable values); - void remove(K key); - void appendValue(K key, final V value); default void appendValues(K key, @NotNull Iterable values) { @@ -33,9 +26,4 @@ public interface MultiMaplet extends Closeable { } } - @NotNull - Iterable getKeys(); - - @Override - void close() throws IOException; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMaplet.java index e313ef210f34..68c3083bfa27 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMaplet.java @@ -56,4 +56,10 @@ public class CachingMaplet implements Maplet { myCache.invalidateAll(); myDelegate.close(); } + + @Override + public void flush() throws IOException { + myCache.invalidateAll(); + myDelegate.flush(); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMultiMaplet.java index 10454233b3c3..05c858794511 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/CachingMultiMaplet.java @@ -98,4 +98,10 @@ public class CachingMultiMaplet implements MultiMaplet { myCache.invalidateAll(); myDelegate.close(); } + + @Override + public void flush() throws IOException { + myCache.invalidateAll(); + myDelegate.flush(); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/Containers.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/Containers.java index 7b06685c5d50..14fd96cad19b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/Containers.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/Containers.java @@ -3,6 +3,7 @@ package org.jetbrains.jps.dependency.impl; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.intellij.openapi.util.LowMemoryWatcher; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.KeyDescriptor; @@ -71,10 +72,11 @@ public final class Containers { private static final int CACHE_SIZE = 512; // todo: make configurable? private final String myRootDirPath; private final PersistentStringEnumerator myStringTable; - private final List myMaps = new ArrayList<>(); + private final List> myMaps = new ArrayList<>(); private final Enumerator myEnumerator; private final Function myDataInterner; private final LoadingCache myInternerCache; + private final LowMemoryWatcher myMemWatcher; PersistentMapletFactory(String rootDirPath) throws IOException { myRootDirPath = rootDirPath; @@ -90,10 +92,22 @@ public final class Containers { return myStringTable.enumerate(str); } }; - myInternerCache = Caffeine.newBuilder().maximumSize(2 * CACHE_SIZE).build(key -> key); + myInternerCache = Caffeine.newBuilder().maximumSize(CACHE_SIZE).build(key -> key); myDataInterner = elem -> { return elem instanceof Usage || elem instanceof String? myInternerCache.get(elem) : elem; }; + myMemWatcher = LowMemoryWatcher.register(() -> { + myInternerCache.invalidateAll(); + myStringTable.force(); + for (BaseMaplet map : myMaps) { + try { + map.flush(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); } @Override @@ -118,6 +132,7 @@ public final class Containers { @Override public void close() { + myMemWatcher.stop(); Throwable ex = null; for (Closeable container : Iterators.flat(myMaps, Iterators.asIterable(myStringTable))) { try { diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMaplet.java index 3a9d149d6e05..e0364c4c760f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMaplet.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.dependency.Maplet; +import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -40,4 +41,9 @@ public final class MemoryMaplet implements Maplet { public void close() { myMap.clear(); } + + @Override + public void flush() throws IOException { + // empty + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMultiMaplet.java index dae0e6af36ba..8807866a9acf 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/MemoryMultiMaplet.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.dependency.MultiMaplet; import org.jetbrains.jps.javac.Iterators; +import java.io.IOException; import java.util.*; import java.util.function.Supplier; @@ -78,4 +79,9 @@ public final class MemoryMultiMaplet> implements M public void close() { myMap.clear(); } + + @Override + public void flush() throws IOException { + // empty + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMaplet.java index eeba954bb67f..d327f7054a1f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMaplet.java @@ -83,4 +83,8 @@ public final class PersistentMaplet implements Maplet { myMap.close(); } + @Override + public void flush() throws IOException { + myMap.force(); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMultiMaplet.java b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMultiMaplet.java index 2cddbb71f364..e4e3797d483c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMultiMaplet.java +++ b/jps/jps-builders/src/org/jetbrains/jps/dependency/impl/PersistentMultiMaplet.java @@ -188,4 +188,8 @@ public final class PersistentMultiMaplet> implemen } } + @Override + public void flush() throws IOException { + myMap.force(); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java index 956fcbde5a25..f0239c77509b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/OutputFilesSink.java @@ -8,6 +8,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FileCollectionFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.builders.JpsBuildBundle; +import org.jetbrains.jps.builders.java.JavaBuilderUtil; import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; import org.jetbrains.jps.builders.java.dependencyView.Callbacks; import org.jetbrains.jps.incremental.BinaryContent; @@ -38,6 +39,7 @@ final class OutputFilesSink implements OutputFileConsumer { private final ModuleLevelBuilder.OutputConsumer myOutputConsumer; private final Callbacks.Backend myMappingsCallback; private final String myChunkName; + private final String myChunkOutputRootName; private final Set mySuccessfullyCompiled = FileCollectionFactory.createCanonicalFileSet(); OutputFilesSink(CompileContext context, @@ -48,6 +50,7 @@ final class OutputFilesSink implements OutputFileConsumer { myOutputConsumer = outputConsumer; myMappingsCallback = callback; myChunkName = "[" +chunkName + "]"; + myChunkOutputRootName = "$" + chunkName.replaceAll("\\\\s", "_"); } @Override @@ -96,7 +99,10 @@ final class OutputFilesSink implements OutputFileConsumer { // register in mappings any non-temp class file try { final ClassReader reader = new FailSafeClassReader(content.getBuffer(), content.getOffset(), content.getLength()); - myMappingsCallback.associate(FileUtil.toSystemIndependentName(fileObject.getFile().getPath()), sourcePaths, reader, fileObject.isGenerated()); + String fileName = JavaBuilderUtil.isDepGraphEnabled()? + myChunkOutputRootName + "/" + FileUtil.toSystemIndependentName(fileObject.getRelativePath()) : + FileUtil.toSystemIndependentName(fileObject.getFile().getPath()); + myMappingsCallback.associate(fileName, sourcePaths, reader, fileObject.isGenerated()); } catch (Throwable e) { // need this to make sure that unexpected errors in, for example, ASM will not ruin the compilation