mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Remove trove and logging dependency
This commit is contained in:
@@ -17,7 +17,10 @@ package com.intellij.util;
|
||||
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.lang.IntObjectHashMap;
|
||||
import com.intellij.util.lang.UrlClassLoader;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import gnu.trove.TIntObjectProcedure;
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -44,6 +47,52 @@ public class UrlClassLoaderTest extends TestCase {
|
||||
assertNotNull(UrlClassLoader.build().allowBootstrapResources().get().getResourceAsStream(name));
|
||||
}
|
||||
|
||||
public void testIntObjectHashMap() {
|
||||
final IntObjectHashMap map = new IntObjectHashMap();
|
||||
final TIntObjectHashMap<Object> checkMap = new TIntObjectHashMap<Object>();
|
||||
final TIntObjectHashMap<Object> dupesMap = new TIntObjectHashMap<Object>();
|
||||
Random random = new Random();
|
||||
for(int i = 0; i < 1000000; ++i) {
|
||||
int key = random.nextInt();
|
||||
String value = String.valueOf(random.nextInt());
|
||||
|
||||
if (!checkMap.contains(key)) {
|
||||
map.put(key, value);
|
||||
checkMap.put(key, value);
|
||||
assertEquals(map.size(), checkMap.size());
|
||||
assertEquals(value, map.get(key));
|
||||
} else {
|
||||
dupesMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
dupesMap.put(0, "random string");
|
||||
|
||||
dupesMap.forEachEntry(new TIntObjectProcedure<Object>() {
|
||||
@Override
|
||||
public boolean execute(int key, Object value) {
|
||||
checkMap.put(key, value);
|
||||
map.put(key, value);
|
||||
assertEquals(map.size(), checkMap.size());
|
||||
assertEquals(value, map.get(key));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
String value = "random string2";
|
||||
checkMap.put(0, value);
|
||||
map.put(0, value);
|
||||
|
||||
checkMap.forEachEntry(new TIntObjectProcedure<Object>() {
|
||||
@Override
|
||||
public boolean execute(int key, Object value) {
|
||||
assertEquals(value, map.get(key));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assertEquals(map.size(), checkMap.size());
|
||||
}
|
||||
|
||||
public void testConcurrentResourceLoading() throws Exception {
|
||||
final List<String> resourceNames = ContainerUtil.newArrayList();
|
||||
List<URL> urls = ContainerUtil.newArrayList();
|
||||
|
||||
@@ -15,20 +15,14 @@
|
||||
*/
|
||||
package com.intellij.util.lang;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.text.StringHash;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.BloomFilterBase;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
@@ -38,22 +32,13 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
* @author max
|
||||
*/
|
||||
public class ClasspathCache {
|
||||
static final Logger LOG = Logger.getInstance(ClasspathCache.class);
|
||||
static final boolean doDebug = LOG.isDebugEnabled();
|
||||
private final IntObjectHashMap myResourcePackagesCache = new IntObjectHashMap();
|
||||
private final IntObjectHashMap myClassPackagesCache = new IntObjectHashMap();
|
||||
|
||||
private final DebugInfo myDebugInfo;
|
||||
|
||||
private final TIntObjectHashMap<Object> myResourcePackagesCache = new TIntObjectHashMap<Object>();
|
||||
private final TIntObjectHashMap<Object> myClassPackagesCache = new TIntObjectHashMap<Object>();
|
||||
|
||||
private THashMap<String, Object> myResources2LoadersTempMap = new THashMap<String, Object>();
|
||||
private Map<String, Object> myResources2LoadersTempMap = new HashMap<String, Object>();
|
||||
private static final double PROBABILITY = 0.005d;
|
||||
private Name2LoaderFilter myNameFilter;
|
||||
|
||||
public ClasspathCache() {
|
||||
myDebugInfo = doDebug ? new DebugInfo() : new NullDebugInfo();
|
||||
}
|
||||
|
||||
static class LoaderData {
|
||||
private final List<String> myResourcePaths = new ArrayList<String>();
|
||||
private final List<String> myNames = new ArrayList<String>();
|
||||
@@ -102,13 +87,12 @@ public class ClasspathCache {
|
||||
ParameterType2 parameter2) {
|
||||
myLock.readLock().lock();
|
||||
try {
|
||||
TIntObjectHashMap<Object> map = resourcePath.endsWith(UrlClassLoader.CLASS_EXTENSION) ?
|
||||
IntObjectHashMap map = resourcePath.endsWith(UrlClassLoader.CLASS_EXTENSION) ?
|
||||
myClassPackagesCache : myResourcePackagesCache;
|
||||
String packageName = getPackageName(resourcePath);
|
||||
|
||||
int hash = packageName.hashCode();
|
||||
Object o = map.get(hash);
|
||||
myDebugInfo.checkLoadersCount(resourcePath, o);
|
||||
|
||||
if (o == null) return null;
|
||||
if (o instanceof Loader) return iterator.process((Loader)o, parameter, parameter2);
|
||||
@@ -130,10 +114,8 @@ public class ClasspathCache {
|
||||
}
|
||||
|
||||
private void addResourceEntry(String resourcePath, Loader loader) {
|
||||
myDebugInfo.addResourceEntry(resourcePath, loader);
|
||||
|
||||
String packageName = getPackageName(resourcePath);
|
||||
TIntObjectHashMap<Object> map = resourcePath.endsWith(UrlClassLoader.CLASS_EXTENSION) ?
|
||||
IntObjectHashMap map = resourcePath.endsWith(UrlClassLoader.CLASS_EXTENSION) ?
|
||||
myClassPackagesCache : myResourcePackagesCache;
|
||||
int hash = packageName.hashCode();
|
||||
Object o = map.get(hash);
|
||||
@@ -151,18 +133,14 @@ public class ClasspathCache {
|
||||
|
||||
private void addNameEntry(String name, Loader loader) {
|
||||
name = transformName(name);
|
||||
myDebugInfo.addNameEntry(name, loader);
|
||||
|
||||
if (myNameFilter == null) {
|
||||
Object loaders = myResources2LoadersTempMap.get(name);
|
||||
boolean added = false;
|
||||
if (loaders == null) {
|
||||
myResources2LoadersTempMap.put(name, loader);
|
||||
added = true;
|
||||
}
|
||||
else if (loaders instanceof Loader && loaders != loader) {
|
||||
myResources2LoadersTempMap.put(name, new Loader[] {(Loader)loaders, loader});
|
||||
added = true;
|
||||
} else if (loaders instanceof Loader[]) {
|
||||
boolean weHaveThisLoader = false;
|
||||
|
||||
@@ -175,16 +153,9 @@ public class ClasspathCache {
|
||||
|
||||
if (!weHaveThisLoader) {
|
||||
myResources2LoadersTempMap.put(name, ArrayUtil.append((Loader[])loaders, loader));
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doDebug && added) ++registeredBeforeClose;
|
||||
} else {
|
||||
if (doDebug) {
|
||||
if (!myNameFilter.maybeContains(name, loader)) ++registeredAfterClose;
|
||||
}
|
||||
|
||||
myNameFilter.add(name, loader);
|
||||
}
|
||||
}
|
||||
@@ -200,53 +171,9 @@ public class ClasspathCache {
|
||||
if (myNameFilter == null) {
|
||||
Object loaders = myResources2LoadersTempMap.get(shortName);
|
||||
result = contains(loader, loaders);
|
||||
|
||||
if (doDebug) {
|
||||
++requestsWithoutNameFilter;
|
||||
if (!result) ++hits;
|
||||
boolean result2 = myDebugInfo.loaderHasName(shortName, loader);
|
||||
if (result2 != result) {
|
||||
++diffs3;
|
||||
}
|
||||
Resource resource = loader.getResource(name, true);
|
||||
if (resource != null && !result || resource == null && result) {
|
||||
++falseHits;
|
||||
}
|
||||
|
||||
if (requestsWithoutNameFilter % 1000 == 0) {
|
||||
LOG.debug("Avoided disk hits: " + hits + " from " + requestsWithoutNameFilter + ", false hits:" + falseHits + ", bitmap diffs:" + diffs3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = myNameFilter.maybeContains(shortName, loader);
|
||||
|
||||
if (doDebug) {
|
||||
++requestsWithNameFilter;
|
||||
if (!result) ++avoidedDiskHits2;
|
||||
boolean result2 = myDebugInfo.loaderHasName(shortName, loader);
|
||||
if (result2 != result) {
|
||||
++diffs2;
|
||||
}
|
||||
|
||||
Object loaders = myResources2LoadersTempMap.get(shortName);
|
||||
if (result != contains(loader, loaders)) {
|
||||
++diffs;
|
||||
}
|
||||
|
||||
Resource resource = loader.getResource(name, true);
|
||||
if (resource == null && result) {
|
||||
++falseHits2;
|
||||
}
|
||||
if (resource != null && !result) {
|
||||
++falseHits2;
|
||||
}
|
||||
|
||||
if (requestsWithNameFilter % 1000 == 0) {
|
||||
LOG.debug("Avoided disk hits2: " + avoidedDiskHits2 + " from " +
|
||||
requestsWithNameFilter + "," + diffs + ", false hits:" + falseHits2 + ", bitmap diffs:" + diffs2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -292,33 +219,14 @@ public class ClasspathCache {
|
||||
return name;
|
||||
}
|
||||
|
||||
private int registeredBeforeClose;
|
||||
private int registeredAfterClose;
|
||||
private int hits;
|
||||
private int requestsWithoutNameFilter;
|
||||
private int falseHits;
|
||||
private int requestsWithNameFilter;
|
||||
private int avoidedDiskHits2;
|
||||
private int falseHits2;
|
||||
private int diffs;
|
||||
private int diffs2;
|
||||
private int diffs3;
|
||||
|
||||
void nameSymbolsLoaded() {
|
||||
myLock.writeLock().lock();
|
||||
|
||||
try {
|
||||
if (myNameFilter != null) {
|
||||
if (doDebug && registeredAfterClose > 0) {
|
||||
LOG.debug("Registered number of classes after close " + registeredAfterClose + " " + toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (doDebug) {
|
||||
LOG.debug("Registered number of classes before classes " + registeredBeforeClose + " " + toString());
|
||||
}
|
||||
|
||||
int nBits = 0;
|
||||
//noinspection UnusedDeclaration
|
||||
int uniques = 0;
|
||||
@@ -348,9 +256,7 @@ public class ClasspathCache {
|
||||
}
|
||||
|
||||
myNameFilter = name2LoaderFilter;
|
||||
if (!doDebug) {
|
||||
myResources2LoadersTempMap = null;
|
||||
}
|
||||
myResources2LoadersTempMap = null;
|
||||
}
|
||||
finally {
|
||||
myLock.writeLock().unlock();
|
||||
@@ -388,80 +294,4 @@ public class ClasspathCache {
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DebugInfo {
|
||||
private final HashMap<String, List<Loader>> myClassPackagesCache = new HashMap<String, List<Loader>>();
|
||||
private final HashMap<String, List<Loader>> myResourcePackagesCache = new HashMap<String, List<Loader>>();
|
||||
private final TIntHashSet myResourceIndex = new TIntHashSet();
|
||||
|
||||
private List<Loader> getLoaders(String resourcePath) {
|
||||
boolean isClassFile = resourcePath.endsWith(UrlClassLoader.CLASS_EXTENSION);
|
||||
final int idx = resourcePath.lastIndexOf('/');
|
||||
String packageName = idx > 0 ? resourcePath.substring(0, idx) : "";
|
||||
|
||||
Map<String, List<Loader>> map = isClassFile ? myClassPackagesCache : myResourcePackagesCache;
|
||||
List<Loader> list = map.get(packageName);
|
||||
if (list == null) {
|
||||
list = new SmartList<Loader>();
|
||||
map.put(packageName, list);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
protected void addResourceEntry(String resourcePath, Loader loader) {
|
||||
final List<Loader> loaders = getLoaders(resourcePath);
|
||||
if (!loaders.contains(loader)) { // TODO Make linked hash set instead?
|
||||
loaders.add(loader);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addNameEntry(String name, Loader loader) {
|
||||
int hash = hashFromNameAndLoader(name, loader);
|
||||
myResourceIndex.add(hash);
|
||||
}
|
||||
|
||||
protected static int hashFromNameAndLoader(String name, Loader loader) {
|
||||
int hash = name.hashCode();
|
||||
int i = loader.getIndex();
|
||||
while(i > 0) {
|
||||
hash = hash * 31 + ((i % 10) + '0');
|
||||
i /= 10;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void checkLoadersCount(String resourcePath, Object o) {
|
||||
List<Loader> loaders1 = getLoaders(resourcePath);
|
||||
if (o == null && !loaders1.isEmpty() ||
|
||||
o instanceof Loader && loaders1.size() != 1 ||
|
||||
o instanceof Loader[] && loaders1.size() != ((Loader[])o).length
|
||||
) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean loaderHasName(String name, Loader loader) {
|
||||
return myResourceIndex.contains(hashFromNameAndLoader(name, loader));
|
||||
}
|
||||
}
|
||||
|
||||
private static class NullDebugInfo extends DebugInfo {
|
||||
@Override
|
||||
public void checkLoadersCount(String resourcePath, Object o) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addResourceEntry(String resourcePath, Loader loader) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNameEntry(String name, Loader loader) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean loaderHasName(String name, Loader loader) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.intellij.util.lang;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
@@ -30,8 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
class FileLoader extends Loader {
|
||||
private final File myRootDir;
|
||||
private final String myRootDirAbsolutePath;
|
||||
private static int misses;
|
||||
private static int hits;
|
||||
private final boolean myCanHavePersistentIndex;
|
||||
|
||||
FileLoader(URL url, int index, boolean canHavePersistentIndex) throws IOException {
|
||||
@@ -89,26 +86,10 @@ class FileLoader extends Loader {
|
||||
|
||||
file = new File(myRootDir, name.replace('/', File.separatorChar));
|
||||
if (!check || file.exists()) { // check means we load or process resource so we check its existence via old way
|
||||
if (check) {
|
||||
++misses;
|
||||
if (misses % 1000 == 0 && ClasspathCache.doDebug) {
|
||||
ClasspathCache.LOG.debug("[Sample of] missed resource " + name + " from " + myRootDir);
|
||||
}
|
||||
}
|
||||
|
||||
++hits;
|
||||
if (hits % 1000 == 0 && ClasspathCache.doDebug) {
|
||||
ClasspathCache.LOG.debug("Exists file loader: misses:" + misses + ", hits:" + hits);
|
||||
}
|
||||
|
||||
return new MyResource(name, url, file, !check);
|
||||
}
|
||||
}
|
||||
catch (Exception exception) {
|
||||
++misses;
|
||||
if (misses % 1000 == 0 && ClasspathCache.doDebug) {
|
||||
ClasspathCache.LOG.debug("Missed " + name + " from " + myRootDir);
|
||||
}
|
||||
if (!check && file != null && file.exists()) {
|
||||
try { // we can not open the file if it is directory, Resource still can be created
|
||||
return new MyResource(name, url, file, false);
|
||||
@@ -314,7 +295,6 @@ class FileLoader extends Loader {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
return "FileLoader [" + myRootDir + "]";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* 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.intellij.util.lang;
|
||||
|
||||
// Nongeneral purpose memory saving map implementation for UrlClassLoader to avoid extra dependencies
|
||||
// made public for tests
|
||||
public final class IntObjectHashMap {
|
||||
private int size;
|
||||
private int[] keys;
|
||||
private Object[] values;
|
||||
private Object specialZeroValue;
|
||||
private boolean hasZeroValue;
|
||||
|
||||
public IntObjectHashMap() {
|
||||
keys = new int[4];
|
||||
values = new Object[keys.length];
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size + (hasZeroValue ? 1 : 0);
|
||||
}
|
||||
|
||||
public void put(int key, Object value) {
|
||||
if (key == 0) {
|
||||
specialZeroValue = value;
|
||||
hasZeroValue = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (size >= (2 * values.length) / 3) rehash();
|
||||
Object previousValue = doPut(keys, values, key, value);
|
||||
if (previousValue == null) ++size;
|
||||
}
|
||||
|
||||
private static Object doPut(int[] keys, Object[] values, int key, Object value) {
|
||||
int index = hashIndex(keys, key);
|
||||
Object obj = values[index];
|
||||
values[index] = value;
|
||||
if (keys[index] == 0) keys[index] = key;
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static int hashIndex(int[] keys, int key) {
|
||||
int hash = (int)((key * 0x9E3779B9L) & 0x7fffffff);
|
||||
int index = hash & (keys.length - 1);
|
||||
int candidate;
|
||||
|
||||
while ((candidate = keys[index]) != 0) {
|
||||
if (candidate == key) return index;
|
||||
if (index == 0) index = keys.length;
|
||||
index--;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private void rehash() {
|
||||
int[] newKeys = new int[keys.length << 1];
|
||||
Object[] newValues = new Object[newKeys.length];
|
||||
|
||||
for (int i = keys.length; --i >= 0; ) {
|
||||
int key = keys[i];
|
||||
if (key != 0) doPut(newKeys, newValues, key, values[i]);
|
||||
}
|
||||
|
||||
keys = newKeys;
|
||||
values = newValues;
|
||||
}
|
||||
|
||||
public Object get(int key) {
|
||||
if (key == 0) {
|
||||
return specialZeroValue;
|
||||
}
|
||||
return values[hashIndex(keys, key)];
|
||||
}
|
||||
}
|
||||
@@ -16,14 +16,15 @@
|
||||
package com.intellij.util.lang;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import com.intellij.util.io.zip.ZipShort;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
@@ -36,7 +37,7 @@ import java.util.zip.ZipFile;
|
||||
public class JarMemoryLoader {
|
||||
public static final String SIZE_ENTRY = "META-INF/jb/$$size$$";
|
||||
|
||||
private final Map<String, Resource> myResources = new THashMap<String, Resource>();
|
||||
private final Map<String, Resource> myResources = Collections.synchronizedMap(new HashMap<String, Resource>()); // todo do we need it ?
|
||||
|
||||
private JarMemoryLoader() { }
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.io.win32.IdeaWin32;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.WeakStringInterner;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
@@ -46,7 +45,7 @@ import java.util.List;
|
||||
public class UrlClassLoader extends ClassLoader {
|
||||
// Feature enabling flag for saving / restoring file system information for local class directories, see Builder#usePersistentClasspathIndexForLocalClassDirectories
|
||||
private static final boolean INDEX_PERSISTENCE_ENABLED = Boolean.parseBoolean(System.getProperty("idea.classpath.index.enabled", "true"));
|
||||
@NonNls static final String CLASS_EXTENSION = ".class";
|
||||
static final String CLASS_EXTENSION = ".class";
|
||||
private static boolean ourParallel = false;
|
||||
|
||||
static {
|
||||
|
||||
Reference in New Issue
Block a user