mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
JPS mappings for incremental compilation refactoring: extract data caching functionality into a reusable wrapper; for MultiMaplet collections support configurable internal collection type
GitOrigin-RevId: a9fdaed773b1f58ebfb8cb984aefa006d12300c0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f2b323600b
commit
2b9519e024
@@ -0,0 +1,23 @@
|
||||
// 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.Nullable;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Maplet<K, V> extends Closeable {
|
||||
boolean containsKey(final K key);
|
||||
|
||||
@Nullable
|
||||
V get(final K key);
|
||||
|
||||
void put(K key, V value);
|
||||
|
||||
void remove(K key);
|
||||
|
||||
Iterable<K> getKeys();
|
||||
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
}
|
||||
@@ -2,7 +2,11 @@
|
||||
package org.jetbrains.jps.dependency;
|
||||
|
||||
public interface MapletFactory {
|
||||
<K extends ExternalizableGraphElement, V extends ExternalizableGraphElement> MultiMaplet<K, V> createSetMultiMaplet(
|
||||
<K, V> MultiMaplet<K, V> createSetMultiMaplet(
|
||||
String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer
|
||||
);
|
||||
|
||||
<K, V> Maplet<K, V> createMaplet(
|
||||
String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
// 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.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface MultiMaplet<K, V> {
|
||||
boolean containsKey(final K key);
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
@Nullable
|
||||
Iterable<V> get(final K key);
|
||||
public interface MultiMaplet<K, V> extends Closeable {
|
||||
|
||||
boolean containsKey(K key);
|
||||
|
||||
void put(final K key, final Iterable<? extends V> values);
|
||||
@NotNull
|
||||
Iterable<V> get(K key);
|
||||
|
||||
void remove(final K key);
|
||||
void put(K key, @NotNull Iterable<? extends V> values);
|
||||
|
||||
void appendValue(final K key, final V value);
|
||||
void remove(K key);
|
||||
|
||||
default void appendValues(final K key, final Iterable<? extends V> values) {
|
||||
void appendValue(K key, final V value);
|
||||
|
||||
default void appendValues(K key, @NotNull Iterable<? extends V> values) {
|
||||
for (V value : values) {
|
||||
appendValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void removeValue(final K key, final V value);
|
||||
void removeValue(K key, V value);
|
||||
|
||||
default void removeValues(final K key, final Iterable<? extends V> values) {
|
||||
default void removeValues(K key, @NotNull Iterable<? extends V> values) {
|
||||
for (V value : values) {
|
||||
removeValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Iterable<K> getKeys();
|
||||
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ import org.jetbrains.jps.dependency.java.JvmNodeElementExternalizer;
|
||||
import org.jetbrains.jps.dependency.java.JvmNodeReferenceID;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class BackDependencyIndexImpl implements BackDependencyIndex {
|
||||
private final String myName;
|
||||
@@ -38,8 +41,7 @@ public abstract class BackDependencyIndexImpl implements BackDependencyIndex {
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<ReferenceID> getDependencies(@NotNull ReferenceID id) {
|
||||
Iterable<ReferenceID> nodes = myMap.get(id);
|
||||
return nodes != null? nodes : Collections.emptyList();
|
||||
return myMap.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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.impl;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.dependency.Maplet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CachingMaplet<K, V> implements Maplet<K, V> {
|
||||
private static final Object NULL_OBJECT = new Object();
|
||||
private final LoadingCache<K, V> myCache;
|
||||
private final Maplet<K, V> myDelegate;
|
||||
|
||||
public CachingMaplet(Maplet<K, V> delegate, int maxCacheSize) {
|
||||
myDelegate = delegate;
|
||||
myCache = Caffeine.newBuilder().maximumSize(maxCacheSize).build(key -> {
|
||||
V val = myDelegate.get(key);
|
||||
//noinspection unchecked
|
||||
return val != null? val : (V)NULL_OBJECT;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return myDelegate.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable V get(K key) {
|
||||
V val = myCache.get(key);
|
||||
return val == NULL_OBJECT? null : val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, @NotNull V value) {
|
||||
myCache.invalidate(key);
|
||||
myDelegate.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
myCache.invalidate(key);
|
||||
myDelegate.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<K> getKeys() {
|
||||
return myDelegate.getKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
myCache.invalidateAll();
|
||||
myDelegate.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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.impl;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.dependency.MultiMaplet;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class CachingMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
|
||||
private final LoadingCache<K, Iterable<V>> myCache;
|
||||
private final MultiMaplet<K, V> myDelegate;
|
||||
|
||||
public CachingMultiMaplet(MultiMaplet<K, V> delegate, int maxCacheSize) {
|
||||
myDelegate = delegate;
|
||||
myCache = Caffeine.newBuilder().maximumSize(maxCacheSize).build(key -> {
|
||||
return myDelegate.get(key);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return myDelegate.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<V> get(K key) {
|
||||
return myCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, @NotNull Iterable<? extends V> values) {
|
||||
myCache.invalidate(key);
|
||||
myDelegate.put(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
myCache.invalidate(key);
|
||||
myDelegate.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendValue(K key, V value) {
|
||||
appendValues(key, Collections.singleton(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendValues(K key, @NotNull Iterable<? extends V> values) {
|
||||
if (!Iterators.isEmpty(values)) {
|
||||
myCache.invalidate(key);
|
||||
myDelegate.appendValues(key, values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValue(K key, V value) {
|
||||
removeValues(key, Collections.singleton(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValues(K key, @NotNull Iterable<? extends V> values) {
|
||||
if (Iterators.isEmpty(values)) {
|
||||
return;
|
||||
}
|
||||
Iterable<V> currentData = myCache.get(key);
|
||||
Collection<V> collection = currentData instanceof Collection? (Collection<V>)currentData : Iterators.collect(currentData, new SmartList<>());
|
||||
if (!collection.isEmpty()) {
|
||||
boolean changes = false;
|
||||
for (V value : values) {
|
||||
changes |= collection.remove(value);
|
||||
}
|
||||
if (changes) {
|
||||
myCache.invalidate(key);
|
||||
if (collection.isEmpty()) {
|
||||
myDelegate.remove(key);
|
||||
}
|
||||
else {
|
||||
myDelegate.put(key, collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<K> getKeys() {
|
||||
return myDelegate.getKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
myCache.invalidateAll();
|
||||
myDelegate.close();
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,11 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
import org.jetbrains.jps.dependency.ExternalizableGraphElement;
|
||||
import org.jetbrains.jps.dependency.Externalizer;
|
||||
import org.jetbrains.jps.dependency.Maplet;
|
||||
import org.jetbrains.jps.dependency.MapletFactory;
|
||||
import org.jetbrains.jps.dependency.MultiMaplet;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
@@ -29,8 +30,13 @@ public final class Containers {
|
||||
|
||||
public static final MapletFactory MEMORY_CONTAINER_FACTORY = new MapletFactory() {
|
||||
@Override
|
||||
public <K extends ExternalizableGraphElement, V extends ExternalizableGraphElement> MultiMaplet<K, V> createSetMultiMaplet(String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer) {
|
||||
return new MemorySetMultiMaplet<>();
|
||||
public <K, V> MultiMaplet<K, V> createSetMultiMaplet(String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer) {
|
||||
return new MemoryMultiMaplet<>(() -> (Set<V>)new HashSet<V>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Maplet<K, V> createMaplet(String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer) {
|
||||
return new MemoryMaplet<>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,27 +67,37 @@ public final class Containers {
|
||||
}
|
||||
|
||||
private static class PersistentMapletFactory implements MapletFactory, Closeable {
|
||||
|
||||
private static final int MAX_CACHE_SIZE = 1024; // todo: make configurable?
|
||||
private final String myRootDirPath;
|
||||
private final List<PersistentSetMultiMaplet<?, ?>> myContainers = new ArrayList<>();
|
||||
private final List<MultiMaplet<?, ?>> myMultiMaplets = new ArrayList<>();
|
||||
private final List<Maplet<?, ?>> myMaplets = new ArrayList<>();
|
||||
|
||||
PersistentMapletFactory(String rootDirPath) {
|
||||
myRootDirPath = rootDirPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K extends ExternalizableGraphElement, V extends ExternalizableGraphElement> MultiMaplet<K, V> createSetMultiMaplet(String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer) {
|
||||
PersistentSetMultiMaplet<K, V> container = new PersistentSetMultiMaplet<>(
|
||||
getMapFile(storageName), new ElementKeyDescriptor<>(keyExternalizer), new ElementDataExternalizer<>(valueExternalizer)
|
||||
public <K, V> MultiMaplet<K, V> createSetMultiMaplet(String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer) {
|
||||
MultiMaplet<K, V> container = new CachingMultiMaplet<>(
|
||||
new PersistentMultiMaplet<>(getMapFile(storageName), new ElementKeyDescriptor<>(keyExternalizer), new ElementDataExternalizer<>(valueExternalizer), () -> (Set<V>)new HashSet<V>()), MAX_CACHE_SIZE
|
||||
);
|
||||
myContainers.add(container);
|
||||
myMultiMaplets.add(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K, V> Maplet<K, V> createMaplet(String storageName, Externalizer<K> keyExternalizer, Externalizer<V> valueExternalizer) {
|
||||
Maplet<K, V> container = new CachingMaplet<>(
|
||||
new PersistentMaplet<>(getMapFile(storageName), new ElementKeyDescriptor<>(keyExternalizer), new ElementDataExternalizer<>(valueExternalizer)), MAX_CACHE_SIZE
|
||||
);
|
||||
myMaplets.add(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
Throwable ex = null;
|
||||
for (PersistentSetMultiMaplet<?, ?> container : myContainers) {
|
||||
for (Closeable container : Iterators.flat(myMultiMaplets, myMaplets)) {
|
||||
try {
|
||||
container.close();
|
||||
}
|
||||
@@ -91,7 +107,8 @@ public final class Containers {
|
||||
}
|
||||
}
|
||||
}
|
||||
myContainers.clear();
|
||||
myMultiMaplets.clear();
|
||||
myMaplets.clear();
|
||||
if (ex instanceof IOException) {
|
||||
throw new BuildDataCorruptedException((IOException)ex);
|
||||
}
|
||||
@@ -107,7 +124,7 @@ public final class Containers {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ElementDataExternalizer<T extends ExternalizableGraphElement> implements DataExternalizer<T> {
|
||||
private static class ElementDataExternalizer<T> implements DataExternalizer<T> {
|
||||
private final Externalizer<T> myExternalizer;
|
||||
|
||||
ElementDataExternalizer(Externalizer<T> externalizer) {
|
||||
@@ -116,16 +133,16 @@ public final class Containers {
|
||||
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, T value) throws IOException {
|
||||
myExternalizer.save(out, value);
|
||||
myExternalizer.save(GraphDataOutput.wrap(out), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(@NotNull DataInput in) throws IOException {
|
||||
return myExternalizer.load(in);
|
||||
return myExternalizer.load(GraphDataInput.wrap(in));
|
||||
}
|
||||
}
|
||||
|
||||
private static class ElementKeyDescriptor<T extends ExternalizableGraphElement> extends ElementDataExternalizer<T> implements KeyDescriptor<T> {
|
||||
private static class ElementKeyDescriptor<T> extends ElementDataExternalizer<T> implements KeyDescriptor<T> {
|
||||
|
||||
ElementKeyDescriptor(Externalizer<T> externalizer) {
|
||||
super(externalizer);
|
||||
@@ -142,18 +159,4 @@ public final class Containers {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//private static <T> DataExternalizer<Collection<T>> asCollectionExternalizer(DataExternalizer<T> ext) {
|
||||
// return new DataExternalizer<>() {
|
||||
// @Override
|
||||
// public void save(@NotNull DataOutput out, Collection<T> value) throws IOException {
|
||||
// RW.writeCollection(out, value, v -> ext.save(out, v));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Collection<T> read(@NotNull DataInput in) throws IOException {
|
||||
// return RW.readCollection(in, () -> ext.read(in), new HashSet<>());
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -95,4 +95,17 @@ public class GraphDataInput implements DataInput {
|
||||
public static DataInput wrap(DataInput in) {
|
||||
return new GraphDataInput(in);
|
||||
}
|
||||
|
||||
public interface StringEnumerator {
|
||||
String toString(int num) throws IOException;
|
||||
}
|
||||
|
||||
public static DataInput wrap(DataInput in, StringEnumerator enumerator) {
|
||||
return new GraphDataInput(in) {
|
||||
@Override
|
||||
public @NotNull String readUTF() throws IOException {
|
||||
return enumerator.toString(readInt());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,4 +89,17 @@ public class GraphDataOutput implements DataOutput {
|
||||
public static DataOutput wrap(DataOutput out) {
|
||||
return new GraphDataOutput(out);
|
||||
}
|
||||
|
||||
public interface StringEnumerator {
|
||||
int toNumber(String str) throws IOException;
|
||||
}
|
||||
|
||||
public static DataOutput wrap(DataOutput out, StringEnumerator enumerator) {
|
||||
return new GraphDataOutput(out) {
|
||||
@Override
|
||||
public void writeUTF(@NotNull String s) throws IOException {
|
||||
writeInt(enumerator.toNumber(s));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.jetbrains.jps.dependency.java.JvmNodeReferenceID;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
abstract class GraphImpl implements Graph {
|
||||
@@ -61,8 +60,7 @@ abstract class GraphImpl implements Graph {
|
||||
|
||||
@Override
|
||||
public Iterable<NodeSource> getSources(@NotNull ReferenceID id) {
|
||||
Iterable<NodeSource> nodeSources = myNodeToSourcesMap.get(id);
|
||||
return nodeSources != null? nodeSources : Collections.emptyList();
|
||||
return myNodeToSourcesMap.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,8 +75,7 @@ abstract class GraphImpl implements Graph {
|
||||
|
||||
@Override
|
||||
public Iterable<Node<?, ?>> getNodes(@NotNull NodeSource source) {
|
||||
var nodes = mySourceToNodesMap.get(source);
|
||||
return nodes != null? nodes : Collections.emptyList();
|
||||
return mySourceToNodesMap.get(source);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// 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.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.dependency.Maplet;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class MemoryMaplet<K, V> implements Maplet<K, V> {
|
||||
private final Map<K, V> myMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return myMap.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable V get(K key) {
|
||||
return myMap.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
myMap.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<K> getKeys() {
|
||||
return myMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
myMap.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// 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.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.dependency.MultiMaplet;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class MemoryMultiMaplet<K, V, C extends Collection<V>> implements MultiMaplet<K, V> {
|
||||
private final Map<K, C> myMap = new HashMap<>();
|
||||
private final Supplier<? extends C> myCollectionFactory;
|
||||
private final C myEmptyCollection;
|
||||
|
||||
public MemoryMultiMaplet(Supplier<? extends C> collectionFactory) {
|
||||
myCollectionFactory = collectionFactory;
|
||||
C col = collectionFactory.get();
|
||||
//noinspection unchecked
|
||||
myEmptyCollection = col instanceof List? (C)Collections.emptyList() : col instanceof Set? (C)Collections.emptySet() : col;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return myMap.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<V> get(K key) {
|
||||
C col = myMap.get(key);
|
||||
return col != null? col : Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, @NotNull Iterable<? extends V> values) {
|
||||
//noinspection unchecked
|
||||
myMap.put(key, ensureCollection(values));
|
||||
}
|
||||
|
||||
private C ensureCollection(Iterable<? extends V> seq) {
|
||||
if (myEmptyCollection instanceof Set && seq instanceof Set) {
|
||||
return (C)seq;
|
||||
}
|
||||
if (myEmptyCollection instanceof List && seq instanceof List) {
|
||||
return (C)seq;
|
||||
}
|
||||
return Iterators.collect(seq, myCollectionFactory.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendValue(K key, V value) {
|
||||
C values = myMap.get(key);
|
||||
if (values == null) {
|
||||
myMap.put(key, values = myCollectionFactory.get());
|
||||
}
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValue(K key, V value) {
|
||||
C values = myMap.get(key);
|
||||
if (values != null) {
|
||||
values.remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<K> getKeys() {
|
||||
return myMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
myMap.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// 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.impl;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.dependency.MultiMaplet;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class MemorySetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
private final Map<K, Set<V>> myMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return myMap.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Iterable<V> get(K key) {
|
||||
return myMap.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, Iterable<? extends V> values) {
|
||||
myMap.put(key, Iterators.collect(values, new HashSet<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendValue(K key, V value) {
|
||||
Set<V> values = myMap.get(key);
|
||||
if (values == null) {
|
||||
myMap.put(key, values = new HashSet<>());
|
||||
}
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValue(K key, V value) {
|
||||
Set<V> values = myMap.get(key);
|
||||
if (values != null) {
|
||||
values.remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<K> getKeys() {
|
||||
return myMap.keySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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.impl;
|
||||
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.io.PersistentHashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
import org.jetbrains.jps.dependency.Maplet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public final class PersistentMaplet<K, V> implements Maplet<K, V> {
|
||||
private final PersistentHashMap<K, V> myMap;
|
||||
|
||||
public PersistentMaplet(Path mapFile, KeyDescriptor<K> keyDescriptor, DataExternalizer<V> valueExternalizer) {
|
||||
try {
|
||||
myMap = new PersistentHashMap<>(mapFile, keyDescriptor, valueExternalizer);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
try {
|
||||
return myMap.containsMapping(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable V get(K key) {
|
||||
try {
|
||||
return myMap.get(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
try {
|
||||
if (value == null) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
myMap.put(key, value);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
try {
|
||||
myMap.remove(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<K> getKeys() {
|
||||
try {
|
||||
return myMap.getAllKeysWithExistingMapping();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException{
|
||||
myMap.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
// 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.impl;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.intellij.util.io.AppendablePersistentMap;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import com.intellij.util.io.PersistentHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
|
||||
import org.jetbrains.jps.dependency.MultiMaplet;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
@@ -18,75 +15,48 @@ import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
private static final Set<?> NULL_COLLECTION = Collections.emptySet();
|
||||
private static final int CACHE_SIZE = 1024;
|
||||
private final PersistentHashMap<K, Set<V>> myMap;
|
||||
private final LoadingCache<K, Set<V>> myCache;
|
||||
public final class PersistentMultiMaplet<K, V, C extends Collection<V>> implements MultiMaplet<K, V> {
|
||||
private final PersistentHashMap<K, C> myMap;
|
||||
private final DataExternalizer<V> myValuesExternalizer;
|
||||
private final C myEmptyCollection;
|
||||
private final Supplier<? extends C> myCollectionFactory;
|
||||
|
||||
public PersistentSetMultiMaplet(Path mapFile, KeyDescriptor<K> keyDescriptor, DataExternalizer<V> valueExternalizer) {
|
||||
public PersistentMultiMaplet(Path mapFile, KeyDescriptor<K> keyDescriptor, DataExternalizer<V> valueExternalizer, Supplier<? extends C> collectionFactory) {
|
||||
myCollectionFactory = collectionFactory;
|
||||
try {
|
||||
C col = collectionFactory.get();
|
||||
//noinspection unchecked
|
||||
myEmptyCollection = col instanceof List? (C)Collections.emptyList() : col instanceof Set? (C)Collections.emptySet() : col;
|
||||
|
||||
myValuesExternalizer = valueExternalizer;
|
||||
myMap = new PersistentHashMap<>(mapFile, new KeyDescriptor<>() {
|
||||
myMap = new PersistentHashMap<>(mapFile, keyDescriptor, new DataExternalizer<>() {
|
||||
@Override
|
||||
public int getHashCode(K value) {
|
||||
return keyDescriptor.getHashCode(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, K value) throws IOException {
|
||||
keyDescriptor.save(GraphDataOutput.wrap(out), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(K val1, K val2) {
|
||||
return keyDescriptor.isEqual(val1, val2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K read(@NotNull DataInput in) throws IOException {
|
||||
return keyDescriptor.read(GraphDataInput.wrap(in));
|
||||
}
|
||||
}, new DataExternalizer<>() {
|
||||
@Override
|
||||
public void save(@NotNull DataOutput out, Set<V> value) throws IOException {
|
||||
out = GraphDataOutput.wrap(out);
|
||||
public void save(@NotNull DataOutput out, C value) throws IOException {
|
||||
for (V v : value) {
|
||||
valueExternalizer.save(out, v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> read(@NotNull DataInput in) throws IOException {
|
||||
Set<V> acc = new HashSet<>();
|
||||
public C read(@NotNull DataInput in) throws IOException {
|
||||
C acc = myCollectionFactory.get();
|
||||
final DataInputStream stream = (DataInputStream)in;
|
||||
in = GraphDataInput.wrap(in);
|
||||
while (stream.available() > 0) {
|
||||
acc.add(valueExternalizer.read(in));
|
||||
acc.add(valueExternalizer.read(stream));
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e) {
|
||||
catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
myCache = Caffeine.newBuilder().maximumSize(CACHE_SIZE).build(key -> {
|
||||
try {
|
||||
Set<V> collection = myMap.get(key);
|
||||
//noinspection unchecked
|
||||
return collection == null ? (Set<V>)NULL_COLLECTION : collection;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,17 +70,21 @@ public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Set<V> get(K key) {
|
||||
final Set<V> collection = myCache.get(key);
|
||||
return collection == NULL_COLLECTION ? null : collection;
|
||||
public @NotNull C get(K key) {
|
||||
try {
|
||||
C col = myMap.get(key);
|
||||
return col != null? col : myEmptyCollection;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, Iterable<? extends V> values) {
|
||||
public void put(K key, @NotNull Iterable<? extends V> values) {
|
||||
try {
|
||||
myCache.invalidate(key);
|
||||
//noinspection unchecked
|
||||
Set<V> data = values instanceof Set? (Set<V>)values : Iterators.collect(values, new HashSet<>());
|
||||
C data = ensureCollection(values);
|
||||
if (data.isEmpty()) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
@@ -123,10 +97,19 @@ public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
private C ensureCollection(Iterable<? extends V> seq) {
|
||||
if (myEmptyCollection instanceof Set && seq instanceof Set) {
|
||||
return (C)seq;
|
||||
}
|
||||
if (myEmptyCollection instanceof List && seq instanceof List) {
|
||||
return (C)seq;
|
||||
}
|
||||
return Iterators.collect(seq, myCollectionFactory.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
try {
|
||||
myCache.invalidate(key);
|
||||
myMap.remove(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -140,12 +123,11 @@ public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendValues(K key, Iterable<? extends V> values) {
|
||||
public void appendValues(K key, @NotNull Iterable<? extends V> values) {
|
||||
try {
|
||||
myMap.appendData(key, new AppendablePersistentMap.ValueDataAppender() {
|
||||
@Override
|
||||
public void append(@NotNull DataOutput out) throws IOException {
|
||||
out = GraphDataOutput.wrap(out);
|
||||
for (V v : values) {
|
||||
myValuesExternalizer.save(out, v);
|
||||
}
|
||||
@@ -163,16 +145,15 @@ public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValues(K key, Iterable<? extends V> values) {
|
||||
public void removeValues(K key, @NotNull Iterable<? extends V> values) {
|
||||
try {
|
||||
final Set<V> collection = myCache.get(key);
|
||||
C collection = get(key);
|
||||
if (!collection.isEmpty()) {
|
||||
boolean changes = false;
|
||||
for (V value : values) {
|
||||
changes |= collection.remove(value);
|
||||
}
|
||||
if (changes) {
|
||||
myCache.invalidate(key);
|
||||
if (collection.isEmpty()) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
@@ -188,7 +169,7 @@ public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<K> getKeys() {
|
||||
public @NotNull Iterable<K> getKeys() {
|
||||
try {
|
||||
return myMap.getAllKeysWithExistingMapping();
|
||||
}
|
||||
@@ -197,9 +178,9 @@ public final class PersistentSetMultiMaplet<K, V> implements MultiMaplet<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
myCache.invalidateAll();
|
||||
myMap.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Reference in New Issue
Block a user