Rework SpringBootApp cache
This commit is contained in:
@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.commons.boot.app.cli;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@@ -60,64 +61,22 @@ public class SpringBootApp {
|
||||
|
||||
private VirtualMachine vm;
|
||||
private VirtualMachineDescriptor vmd;
|
||||
private Supplier<String> jmxConnect;
|
||||
|
||||
private static final Cache<VirtualMachineDescriptor, String> pidToJmxConnectUrl = CacheBuilder.newBuilder().build();
|
||||
|
||||
private static Callable<Collection<SpringBootApp>> cached(Callable<Collection<SpringBootApp>> provider) {
|
||||
LoadingCache<Object, CompletableFuture<Collection<SpringBootApp>>> cache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(500, TimeUnit.MILLISECONDS)
|
||||
.removalListener(removalNotification -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
CompletableFuture<Collection<SpringBootApp>> removed = (CompletableFuture<Collection<SpringBootApp>>) removalNotification.getValue();
|
||||
if (!removed.isCompletedExceptionally()) {
|
||||
try {
|
||||
Collection<SpringBootApp> apps = removed.get();
|
||||
for (SpringBootApp springBootApp : apps) {
|
||||
springBootApp.dispose();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.build(new CacheLoader<Object, CompletableFuture<Collection<SpringBootApp>>>() {
|
||||
@Override public CompletableFuture<Collection<SpringBootApp>> load(Object key) {
|
||||
try {
|
||||
return CompletableFuture.completedFuture(provider.call());
|
||||
} catch (Throwable e) {
|
||||
return Futures.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return () -> {
|
||||
Object key = SpringBootApp.class; //This key really doesn't matter, as long as we use the same non-null object each time.
|
||||
return cache.get(key).get();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static Collection<SpringBootApp> fetchRunningJavaApps() throws Exception {
|
||||
List<VirtualMachineDescriptor> list = VirtualMachine.list();
|
||||
ImmutableList.Builder<SpringBootApp> apps = ImmutableList.builder();
|
||||
for (VirtualMachineDescriptor vmd : list) {
|
||||
apps.add(new SpringBootApp(vmd));
|
||||
private final Supplier<String> jmxConnect = Suppliers.memoize(() -> {
|
||||
try {
|
||||
return vm.startLocalManagementAgent();
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Invalidate part of pidToJmxConnectUrl cache to remove old processes
|
||||
Set<VirtualMachineDescriptor> oldProcesses = new HashSet<>(pidToJmxConnectUrl.asMap().keySet());
|
||||
oldProcesses.removeAll(list);
|
||||
pidToJmxConnectUrl.invalidateAll(oldProcesses);
|
||||
|
||||
return apps.build();
|
||||
}
|
||||
private static SpringBootAppCache cache = new SpringBootAppCache();
|
||||
|
||||
public static Collection<SpringBootApp> getAllRunningJavaApps() throws Exception {
|
||||
return cachedJavaAppsGetter.call();
|
||||
return cache.getAllRunningJavaApps();
|
||||
}
|
||||
|
||||
private static Callable<Collection<SpringBootApp>> cachedJavaAppsGetter = cached(SpringBootApp::fetchRunningJavaApps);
|
||||
|
||||
/**
|
||||
* @return Map that contains the boot apps, mapping the process ID -> boot app accessor object
|
||||
*/
|
||||
@@ -128,7 +87,6 @@ public class SpringBootApp {
|
||||
public SpringBootApp(VirtualMachineDescriptor vmd) throws Exception {
|
||||
this.vmd = vmd;
|
||||
this.vm = VirtualMachine.attach(vmd);
|
||||
this.jmxConnect = Suppliers.memoize(() -> getJmxConnectUrl());
|
||||
System.err.println("SpringBootApp created: "+this);
|
||||
}
|
||||
|
||||
@@ -140,17 +98,6 @@ public class SpringBootApp {
|
||||
return vmd.displayName();
|
||||
}
|
||||
|
||||
private String getJmxConnectUrl() {
|
||||
try {
|
||||
return pidToJmxConnectUrl.get(vmd, () -> {
|
||||
return vm.startLocalManagementAgent();
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
Log.log(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getHost() throws Exception {
|
||||
JMXServiceURL serviceUrl = new JMXServiceURL(jmxConnect.get());
|
||||
return serviceUrl.getHost();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.boot.app.cli;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.VirtualMachineDescriptor;
|
||||
|
||||
public class SpringBootAppCache {
|
||||
|
||||
private static final Duration EXPIRE_AFTER = Duration.ofMillis(500); //Limits rate at which we refresh list of apps
|
||||
private long nextRefreshAfter = Long.MIN_VALUE;
|
||||
|
||||
private ImmutableMap<VirtualMachineDescriptor, SpringBootApp> apps = ImmutableMap.of();
|
||||
|
||||
public synchronized Collection<SpringBootApp> getAllRunningJavaApps() {
|
||||
if (System.currentTimeMillis()>=nextRefreshAfter) {
|
||||
refresh();
|
||||
}
|
||||
return apps.values();
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
List<VirtualMachineDescriptor> currentVms = VirtualMachine.list();
|
||||
HashSet<VirtualMachineDescriptor> oldVms = new HashSet<>(apps.keySet());
|
||||
ImmutableMap.Builder<VirtualMachineDescriptor, SpringBootApp> newApps = ImmutableMap.builder();
|
||||
for (VirtualMachineDescriptor vm : currentVms) {
|
||||
oldVms.remove(vm);
|
||||
SpringBootApp existingApp = apps.get(vm);
|
||||
if (existingApp!=null) {
|
||||
newApps.put(vm, existingApp);
|
||||
} else {
|
||||
try {
|
||||
newApps.put(vm, new SpringBootApp(vm));
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (VirtualMachineDescriptor oldVm : oldVms) {
|
||||
apps.get(oldVm).dispose();
|
||||
}
|
||||
apps = newApps.build();
|
||||
nextRefreshAfter = System.currentTimeMillis() + EXPIRE_AFTER.toMillis();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user