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
;
15 import java
.util
.ArrayList
;
16 import java
.util
.List
;
17 import java
.util
.concurrent
.ScheduledExecutorService
;
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
;
44 myPlVcsManager
= ProjectLevelVcsManager
.getInstance(myProject
);
45 myStartupManager
= StartupManagerImpl
.getInstance(myProject
);
46 myLock
= new Object();
47 myWaitingUpdateCompletionQueue
= new ArrayList
<Runnable
>();
51 myUpdateUnversionedRequested
= false;
54 public void initialized() {
55 LOG
.debug("Initialized for project: " + myProject
.getName());
59 public boolean isStopped() {
63 public void schedule(final boolean updateUnversionedFiles
) {
64 synchronized (myLock
) {
65 if (! myStarted
&& ApplicationManager
.getApplication().isUnitTestMode()) return;
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;
82 LOG
.debug("Calling stop for project: " + myProject
.getName());
83 final List
<Runnable
> waiters
= new ArrayList
<Runnable
>(myWaitingUpdateCompletionQueue
.size());
84 synchronized (myLock
) {
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
) {
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
) {
110 if (managerProxy
!= null) {
111 managerProxy
.callRealManager(VcsDirtyScopeManager
.getInstance(myProject
));
114 myWaitingUpdateCompletionQueue
.add(data
.getCallback());
118 // do not run under lock; stopped cannot be switched into not stopped - can check without lock
120 LOG
.debug("invokeAfterUpdate: stopped, invoke right now for project: " + myProject
.getName());
121 SwingUtilities
.invokeLater(new Runnable() {
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
{
138 boolean updateUnversioned
;
139 final List
<Runnable
> copy
= new ArrayList
<Runnable
>(myWaitingUpdateCompletionQueue
.size());
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
);
152 copy
.addAll(myWaitingUpdateCompletionQueue
);
153 myRequestSubmitted
= false;
156 LOG
.debug("MyRunnable: STOPPED, project: " + myProject
.getName() + ", runnable: " + hashCode());
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());
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
) {
184 LOG
.debug("MyRunnable: Runnables executed, project: " + myProject
.getName() + ", runnable: " + hashCode());