VCS: do not refresh local changes while doing post-startup
[fedora-idea.git] / vcs-impl / src / com / intellij / openapi / vcs / changes / UpdateRequestsQueue.java
blobc218d6acf22ba62125a46ad92fbedc2159c154c7
1 package com.intellij.openapi.vcs.changes;
3 import com.intellij.ide.startup.impl.StartupManagerImpl;
4 import com.intellij.lifecycle.ControlledAlarmFactory;
5 import com.intellij.lifecycle.ScheduledSlowlyClosingAlarm;
6 import com.intellij.openapi.application.ApplicationManager;
7 import com.intellij.openapi.application.ModalityState;
8 import com.intellij.openapi.diagnostic.Logger;
9 import com.intellij.openapi.project.Project;
10 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
11 import com.intellij.openapi.startup.StartupManager;
12 import com.intellij.util.Consumer;
14 import javax.swing.*;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.ScheduledExecutorService;
19 /**
20 * ChangeListManager updates scheduler.
21 * Tries to zip several update requests into one (if starts and see several requests in the queue)
22 * own inner synchronization
24 public class UpdateRequestsQueue {
25 private final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.UpdateRequestsQueue");
26 private final Project myProject;
27 private final LocalChangesUpdater myDelegate;
28 private final Object myLock;
29 private volatile boolean myStarted;
30 private volatile boolean myStopped;
32 private boolean myRequestSubmitted;
33 private final List<Runnable> myWaitingUpdateCompletionQueue;
34 private final ProjectLevelVcsManager myPlVcsManager;
35 private boolean myUpdateUnversionedRequested;
36 private ScheduledSlowlyClosingAlarm mySharedExecutor;
37 private StartupManager myStartupManager;
39 public UpdateRequestsQueue(final Project project, final ScheduledExecutorService executor, final LocalChangesUpdater delegate) {
40 mySharedExecutor = ControlledAlarmFactory.createScheduledOnSharedThread(project, "Local changes update", executor);
42 myDelegate = delegate;
43 myProject = project;
44 myPlVcsManager = ProjectLevelVcsManager.getInstance(myProject);
45 myStartupManager = StartupManagerImpl.getInstance(myProject);
46 myLock = new Object();
47 myWaitingUpdateCompletionQueue = new ArrayList<Runnable>();
48 // not initialized
49 myStarted = false;
50 myStopped = false;
51 myUpdateUnversionedRequested = false;
54 public void initialized() {
55 LOG.debug("Initialized for project: " + myProject.getName());
56 myStarted = true;
59 public boolean isStopped() {
60 return myStopped;
63 public void schedule(final boolean updateUnversionedFiles) {
64 synchronized (myLock) {
65 if (! myStarted && ApplicationManager.getApplication().isUnitTestMode()) return;
67 if (! myStopped) {
68 if (! myRequestSubmitted) {
69 final MyRunnable runnable = new MyRunnable();
70 myRequestSubmitted = true;
71 mySharedExecutor.addRequest(runnable, 300);
72 LOG.debug("Scheduled for project: " + myProject.getName() + ", runnable: " + runnable.hashCode());
73 myUpdateUnversionedRequested |= updateUnversionedFiles;
74 } else if (updateUnversionedFiles && (! myUpdateUnversionedRequested)) {
75 myUpdateUnversionedRequested = true;
81 public void stop() {
82 LOG.debug("Calling stop for project: " + myProject.getName());
83 final List<Runnable> waiters = new ArrayList<Runnable>(myWaitingUpdateCompletionQueue.size());
84 synchronized (myLock) {
85 myStopped = true;
86 waiters.addAll(myWaitingUpdateCompletionQueue);
87 myWaitingUpdateCompletionQueue.clear();
89 LOG.debug("Calling runnables in stop for project: " + myProject.getName());
90 // do not run under lock
91 for (Runnable runnable : waiters) {
92 runnable.run();
94 LOG.debug("Stop finished for project: " + myProject.getName());
97 public void invokeAfterUpdate(final Runnable afterUpdate, final InvokeAfterUpdateMode mode, final String title,
98 final Consumer<VcsDirtyScopeManager> dirtyScopeManagerFiller, final ModalityState state) {
99 LOG.debug("invokeAfterUpdate for project: " + myProject.getName());
100 final CallbackData data = CallbackData.create(afterUpdate, title, state, mode, myProject);
102 VcsDirtyScopeManagerProxy managerProxy = null;
103 if (dirtyScopeManagerFiller != null) {
104 managerProxy = new VcsDirtyScopeManagerProxy();
105 dirtyScopeManagerFiller.consume(managerProxy);
108 synchronized (myLock) {
109 if (! myStopped) {
110 if (managerProxy != null) {
111 managerProxy.callRealManager(VcsDirtyScopeManager.getInstance(myProject));
114 myWaitingUpdateCompletionQueue.add(data.getCallback());
115 schedule(true);
118 // do not run under lock; stopped cannot be switched into not stopped - can check without lock
119 if (myStopped) {
120 LOG.debug("invokeAfterUpdate: stopped, invoke right now for project: " + myProject.getName());
121 SwingUtilities.invokeLater(new Runnable() {
122 public void run() {
123 afterUpdate.run();
126 return;
127 } else {
128 // invoke progress if needed
129 if (data.getWrapperStarter() != null) {
130 data.getWrapperStarter().run();
133 LOG.debug("invokeAfterUpdate: exit for project: " + myProject.getName());
136 private class MyRunnable implements Runnable {
137 public void run() {
138 boolean updateUnversioned;
139 final List<Runnable> copy = new ArrayList<Runnable>(myWaitingUpdateCompletionQueue.size());
141 try {
142 synchronized (myLock) {
143 if ((! myStopped) && ((! myStarted) || myPlVcsManager.isBackgroundVcsOperationRunning()) ||
144 (! ((StartupManagerImpl) myStartupManager).startupActivityPassed())) {
145 LOG.debug("MyRunnable: not started, not stopped, reschedule, project: " + myProject.getName() + ", runnable: " + hashCode());
146 myRequestSubmitted = false;
147 // try again after time
148 schedule(myUpdateUnversionedRequested);
149 return;
152 copy.addAll(myWaitingUpdateCompletionQueue);
153 myRequestSubmitted = false;
155 if (myStopped) {
156 LOG.debug("MyRunnable: STOPPED, project: " + myProject.getName() + ", runnable: " + hashCode());
157 return;
160 // take it under lock
161 updateUnversioned = myUpdateUnversionedRequested;
162 // for concurrent schedules to tigger flag correctly
163 myUpdateUnversionedRequested = false;
166 LOG.debug("MyRunnable: INVOKE, project: " + myProject.getName() + ", runnable: " + hashCode());
167 myDelegate.execute(updateUnversioned, mySharedExecutor);
168 LOG.debug("MyRunnable: invokeD, project: " + myProject.getName() + ", runnable: " + hashCode());
169 } finally {
170 synchronized (myLock) {
171 LOG.debug("MyRunnable: delete executed, project: " + myProject.getName() + ", runnable: " + hashCode());
172 if (! copy.isEmpty()) {
173 myWaitingUpdateCompletionQueue.removeAll(copy);
176 if ((! myWaitingUpdateCompletionQueue.isEmpty()) && (! myRequestSubmitted)) {
177 LOG.error("No update task to handle request(s)");
180 // do not run under lock
181 for (Runnable runnable : copy) {
182 runnable.run();
184 LOG.debug("MyRunnable: Runnables executed, project: " + myProject.getName() + ", runnable: " + hashCode());