mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
hotswap: better implementation of modified classes discovery, does not require to postponed files in memory
This commit is contained in:
@@ -64,7 +64,10 @@ import com.sun.jdi.request.EventRequest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DebuggerSession implements AbstractDebuggerSession {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.impl.DebuggerSession");
|
||||
@@ -104,6 +107,8 @@ public class DebuggerSession implements AbstractDebuggerSession {
|
||||
private final Set<ThreadReferenceProxyImpl> mySteppingThroughThreads = new HashSet<ThreadReferenceProxyImpl>();
|
||||
protected final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
|
||||
|
||||
private boolean myModifiedClassesScanRequired = false;
|
||||
|
||||
public boolean isSteppingThrough(ThreadReferenceProxyImpl threadProxy) {
|
||||
return mySteppingThroughThreads.contains(threadProxy);
|
||||
}
|
||||
@@ -114,6 +119,14 @@ public class DebuggerSession implements AbstractDebuggerSession {
|
||||
return mySearchScope;
|
||||
}
|
||||
|
||||
public boolean isModifiedClassesScanRequired() {
|
||||
return myModifiedClassesScanRequired;
|
||||
}
|
||||
|
||||
public void setModifiedClassesScanRequired(boolean modifiedClassesScanRequired) {
|
||||
myModifiedClassesScanRequired = modifiedClassesScanRequired;
|
||||
}
|
||||
|
||||
private class MyDebuggerStateManager extends DebuggerStateManager {
|
||||
private DebuggerContextImpl myDebuggerContext;
|
||||
|
||||
@@ -192,21 +205,6 @@ public class DebuggerSession implements AbstractDebuggerSession {
|
||||
return myDebugProcess;
|
||||
}
|
||||
|
||||
private final Map<String, HotSwapFile> myDelayedHotswapFiles = new HashMap<String, HotSwapFile>();
|
||||
|
||||
public void addHotswapFiles(Map<String, HotSwapFile> files) {
|
||||
myDelayedHotswapFiles.putAll(files);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, HotSwapFile> getHotswapFiles() {
|
||||
return Collections.unmodifiableMap(myDelayedHotswapFiles);
|
||||
}
|
||||
|
||||
public void clearHotswapFiles() {
|
||||
myDelayedHotswapFiles.clear();
|
||||
}
|
||||
|
||||
private static class DebuggerSessionState {
|
||||
final int myState;
|
||||
final String myDescription;
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -155,11 +154,10 @@ public class HotSwapManager extends AbstractProjectComponent {
|
||||
return project.getComponent(HotSwapManager.class);
|
||||
}
|
||||
|
||||
private void reloadClasses(DebuggerSession session, HotSwapProgress progress) {
|
||||
private void reloadClasses(DebuggerSession session, Map<String, HotSwapFile> classesToReload, HotSwapProgress progress) {
|
||||
final long newSwapTime = System.currentTimeMillis();
|
||||
new ReloadClassesWorker(session, progress).reloadClasses();
|
||||
new ReloadClassesWorker(session, progress).reloadClasses(classesToReload);
|
||||
setTimeStamp(session, newSwapTime);
|
||||
session.clearHotswapFiles();
|
||||
}
|
||||
|
||||
public static Map<DebuggerSession, Map<String, HotSwapFile>> findModifiedClasses(List<DebuggerSession> sessions, Map<String, List<String>> generatedPaths) {
|
||||
@@ -225,7 +223,7 @@ public class HotSwapManager extends AbstractProjectComponent {
|
||||
return swapProgress.isCancelled() ? new HashMap<DebuggerSession, Map<String, HotSwapFile>>() : modifiedClasses;
|
||||
}
|
||||
|
||||
public static void reloadModifiedClasses(final Collection<DebuggerSession> sessions, final HotSwapProgress reloadClassesProgress) {
|
||||
public static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses, final HotSwapProgress reloadClassesProgress) {
|
||||
final MultiProcessCommand reloadClassesCommand = new MultiProcessCommand();
|
||||
|
||||
reloadClassesProgress.setCancelWorker(new Runnable() {
|
||||
@@ -234,11 +232,13 @@ public class HotSwapManager extends AbstractProjectComponent {
|
||||
}
|
||||
});
|
||||
|
||||
for (final DebuggerSession debuggerSession : sessions) {
|
||||
for (final DebuggerSession debuggerSession : modifiedClasses.keySet()) {
|
||||
reloadClassesCommand.addCommand(debuggerSession.getProcess(), new DebuggerCommandImpl() {
|
||||
protected void action() throws Exception {
|
||||
reloadClassesProgress.setDebuggerSession(debuggerSession);
|
||||
getInstance(reloadClassesProgress.getProject()).reloadClasses(debuggerSession, reloadClassesProgress);
|
||||
getInstance(reloadClassesProgress.getProject()).reloadClasses(
|
||||
debuggerSession, modifiedClasses.get(debuggerSession), reloadClassesProgress
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,12 +90,10 @@ class ReloadClassesWorker {
|
||||
}
|
||||
}
|
||||
|
||||
public void reloadClasses() {
|
||||
public void reloadClasses(final Map<String, HotSwapFile> modifiedClasses) {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread();
|
||||
|
||||
final Map<String, HotSwapFile> modifiedClasses = myDebuggerSession.getHotswapFiles();
|
||||
|
||||
if(modifiedClasses.isEmpty()) {
|
||||
if(modifiedClasses == null || modifiedClasses.size() == 0) {
|
||||
myProgress.addMessage(myDebuggerSession, MessageCategory.INFORMATION, DebuggerBundle.message("status.hotswap.loaded.classes.up.to.date"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,47 +149,68 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
|
||||
final boolean isOutOfProcessMode = CompilerWorkspaceConfiguration.getInstance(myProject).useOutOfProcessBuild();
|
||||
final boolean shouldPerformScan = !isOutOfProcessMode || generatedPaths == null;
|
||||
|
||||
final HotSwapProgressImpl findClassesProgress = shouldPerformScan ? new HotSwapProgressImpl(myProject) : null;
|
||||
|
||||
final HotSwapProgressImpl findClassesProgress;
|
||||
if (shouldPerformScan) {
|
||||
findClassesProgress = new HotSwapProgressImpl(myProject);
|
||||
}
|
||||
else {
|
||||
boolean createProgress = false;
|
||||
for (DebuggerSession session : sessions) {
|
||||
if (session.isModifiedClassesScanRequired()) {
|
||||
createProgress = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
findClassesProgress = createProgress? new HotSwapProgressImpl(myProject) : null;
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
final Map<DebuggerSession, Map<String, HotSwapFile>> newlyModifiedClasses = shouldPerformScan?
|
||||
scanForModifiedClassesWithProgress(sessions, findClassesProgress, !isOutOfProcessMode) :
|
||||
HotSwapManager.findModifiedClasses(sessions, generatedPaths);
|
||||
|
||||
for (Map.Entry<DebuggerSession, Map<String, HotSwapFile>> entry : newlyModifiedClasses.entrySet()) {
|
||||
final DebuggerSession session = entry.getKey();
|
||||
if (shouldPerformScan) {
|
||||
session.clearHotswapFiles();
|
||||
}
|
||||
session.addHotswapFiles(entry.getValue());
|
||||
final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses;
|
||||
if (shouldPerformScan) {
|
||||
modifiedClasses = scanForModifiedClassesWithProgress(sessions, findClassesProgress, !isOutOfProcessMode);
|
||||
}
|
||||
|
||||
boolean hasFilesToReload = false;
|
||||
for (DebuggerSession session : sessions) {
|
||||
if (!session.getHotswapFiles().isEmpty()) {
|
||||
hasFilesToReload = true;
|
||||
break;
|
||||
else {
|
||||
final List<DebuggerSession> toScan = new ArrayList<DebuggerSession>();
|
||||
final List<DebuggerSession> toUseGenerated = new ArrayList<DebuggerSession>();
|
||||
for (DebuggerSession session : sessions) {
|
||||
(session.isModifiedClassesScanRequired()? toScan : toUseGenerated).add(session);
|
||||
session.setModifiedClassesScanRequired(false);
|
||||
}
|
||||
modifiedClasses = new HashMap<DebuggerSession, Map<String, HotSwapFile>>();
|
||||
if (!toUseGenerated.isEmpty()) {
|
||||
modifiedClasses.putAll(HotSwapManager.findModifiedClasses(toUseGenerated, generatedPaths));
|
||||
}
|
||||
if (!toScan.isEmpty()) {
|
||||
modifiedClasses.putAll(scanForModifiedClassesWithProgress(toScan, findClassesProgress, !isOutOfProcessMode));
|
||||
}
|
||||
}
|
||||
if (!hasFilesToReload) {
|
||||
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (modifiedClasses.isEmpty()) {
|
||||
final String message = DebuggerBundle.message("status.hotswap.uptodate");
|
||||
HotSwapProgressImpl.NOTIFICATION_GROUP.createNotification(message, NotificationType.INFORMATION).notify(myProject);
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<DebuggerSession> sessionsToReload = new HashSet<DebuggerSession>(sessions);
|
||||
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
if (shouldAskBeforeHotswap && !DebuggerSettings.RUN_HOTSWAP_ALWAYS.equals(runHotswap)) {
|
||||
final RunHotswapDialog dialog = new RunHotswapDialog(myProject, sessions, shouldDisplayHangWarning);
|
||||
dialog.show();
|
||||
if (!dialog.isOK()) {
|
||||
for (DebuggerSession session : modifiedClasses.keySet()) {
|
||||
session.setModifiedClassesScanRequired(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sessionsToReload.retainAll(dialog.getSessionsToReload());
|
||||
final Set<DebuggerSession> toReload = new HashSet<DebuggerSession>(dialog.getSessionsToReload());
|
||||
for (DebuggerSession session : modifiedClasses.keySet()) {
|
||||
if (!toReload.contains(session)) {
|
||||
session.setModifiedClassesScanRequired(true);
|
||||
}
|
||||
}
|
||||
modifiedClasses.keySet().retainAll(toReload);
|
||||
}
|
||||
else {
|
||||
if (shouldDisplayHangWarning) {
|
||||
@@ -208,16 +229,19 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
|
||||
}
|
||||
);
|
||||
if (answer == DialogWrapper.CANCEL_EXIT_CODE) {
|
||||
for (DebuggerSession session : modifiedClasses.keySet()) {
|
||||
session.setModifiedClassesScanRequired(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sessionsToReload.isEmpty()) {
|
||||
if (!modifiedClasses.isEmpty()) {
|
||||
final HotSwapProgressImpl progress = new HotSwapProgressImpl(myProject);
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
reloadModifiedClasses(sessionsToReload, progress);
|
||||
reloadModifiedClasses(modifiedClasses, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -242,10 +266,10 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private static void reloadModifiedClasses(final Collection<DebuggerSession> sessions, final HotSwapProgressImpl progress) {
|
||||
private static void reloadModifiedClasses(final Map<DebuggerSession, Map<String, HotSwapFile>> modifiedClasses, final HotSwapProgressImpl progress) {
|
||||
ProgressManager.getInstance().runProcess(new Runnable() {
|
||||
public void run() {
|
||||
HotSwapManager.reloadModifiedClasses(sessions, progress);
|
||||
HotSwapManager.reloadModifiedClasses(modifiedClasses, progress);
|
||||
progress.finished();
|
||||
}
|
||||
}, progress.getProgressIndicator());
|
||||
|
||||
Reference in New Issue
Block a user