2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.vcs
.changes
;
18 import com
.intellij
.ide
.startup
.impl
.StartupManagerImpl
;
19 import com
.intellij
.lifecycle
.ControlledAlarmFactory
;
20 import com
.intellij
.lifecycle
.ScheduledSlowlyClosingAlarm
;
21 import com
.intellij
.openapi
.application
.ApplicationManager
;
22 import com
.intellij
.openapi
.application
.ModalityState
;
23 import com
.intellij
.openapi
.diagnostic
.Logger
;
24 import com
.intellij
.openapi
.progress
.SomeQueue
;
25 import com
.intellij
.openapi
.project
.Project
;
26 import com
.intellij
.openapi
.startup
.StartupManager
;
27 import com
.intellij
.openapi
.vcs
.ProjectLevelVcsManager
;
28 import com
.intellij
.util
.Consumer
;
31 import java
.util
.ArrayList
;
32 import java
.util
.List
;
33 import java
.util
.concurrent
.ScheduledExecutorService
;
36 * ChangeListManager updates scheduler.
37 * Tries to zip several update requests into one (if starts and see several requests in the queue)
38 * own inner synchronization
41 public class UpdateRequestsQueue
{
42 private final Logger LOG
= Logger
.getInstance("#com.intellij.openapi.vcs.changes.UpdateRequestsQueue");
43 private final Project myProject
;
44 private final LocalChangesUpdater myDelegate
;
45 private final Object myLock
;
46 private volatile boolean myStarted
;
47 private volatile boolean myStopped
;
49 private boolean myRequestSubmitted
;
50 private final List
<Runnable
> myWaitingUpdateCompletionQueue
;
51 private final ProjectLevelVcsManager myPlVcsManager
;
52 private boolean myUpdateUnversionedRequested
;
53 private final ScheduledSlowlyClosingAlarm mySharedExecutor
;
54 private final StartupManager myStartupManager
;
56 public UpdateRequestsQueue(final Project project
, final ScheduledExecutorService executor
, final LocalChangesUpdater delegate
) {
57 mySharedExecutor
= ControlledAlarmFactory
.createScheduledOnSharedThread(project
, "Local changes update", executor
);
59 myDelegate
= delegate
;
61 myPlVcsManager
= ProjectLevelVcsManager
.getInstance(myProject
);
62 myStartupManager
= StartupManager
.getInstance(myProject
);
63 myLock
= new Object();
64 myWaitingUpdateCompletionQueue
= new ArrayList
<Runnable
>();
68 myUpdateUnversionedRequested
= false;
71 public void initialized() {
72 LOG
.debug("Initialized for project: " + myProject
.getName());
76 public boolean isStopped() {
80 public void schedule(final boolean updateUnversionedFiles
) {
81 synchronized (myLock
) {
82 if (! myStarted
&& ApplicationManager
.getApplication().isUnitTestMode()) return;
85 if (! myRequestSubmitted
) {
86 final MyRunnable runnable
= new MyRunnable();
87 myRequestSubmitted
= true;
88 mySharedExecutor
.addRequest(runnable
, 300);
89 LOG
.debug("Scheduled for project: " + myProject
.getName() + ", runnable: " + runnable
.hashCode());
90 myUpdateUnversionedRequested
|= updateUnversionedFiles
;
91 } else if (updateUnversionedFiles
&& (! myUpdateUnversionedRequested
)) {
92 myUpdateUnversionedRequested
= true;
99 LOG
.debug("Calling stop for project: " + myProject
.getName());
100 final List
<Runnable
> waiters
= new ArrayList
<Runnable
>(myWaitingUpdateCompletionQueue
.size());
101 synchronized (myLock
) {
103 waiters
.addAll(myWaitingUpdateCompletionQueue
);
104 myWaitingUpdateCompletionQueue
.clear();
106 LOG
.debug("Calling runnables in stop for project: " + myProject
.getName());
107 // do not run under lock
108 for (Runnable runnable
: waiters
) {
111 LOG
.debug("Stop finished for project: " + myProject
.getName());
114 public void invokeAfterUpdate(final Runnable afterUpdate
, final InvokeAfterUpdateMode mode
, final String title
,
115 final Consumer
<VcsDirtyScopeManager
> dirtyScopeManagerFiller
, final ModalityState state
) {
116 LOG
.debug("invokeAfterUpdate for project: " + myProject
.getName());
117 final CallbackData data
= CallbackData
.create(afterUpdate
, title
, state
, mode
, myProject
);
119 VcsDirtyScopeManagerProxy managerProxy
= null;
120 if (dirtyScopeManagerFiller
!= null) {
121 managerProxy
= new VcsDirtyScopeManagerProxy();
122 dirtyScopeManagerFiller
.consume(managerProxy
);
125 synchronized (myLock
) {
127 if (managerProxy
!= null) {
128 managerProxy
.callRealManager(VcsDirtyScopeManager
.getInstance(myProject
));
131 myWaitingUpdateCompletionQueue
.add(data
.getCallback());
135 // do not run under lock; stopped cannot be switched into not stopped - can check without lock
137 LOG
.debug("invokeAfterUpdate: stopped, invoke right now for project: " + myProject
.getName());
138 SwingUtilities
.invokeLater(new Runnable() {
145 // invoke progress if needed
146 if (data
.getWrapperStarter() != null) {
147 data
.getWrapperStarter().run();
150 LOG
.debug("invokeAfterUpdate: exit for project: " + myProject
.getName());
153 private class MyRunnable
implements Runnable
{
155 boolean updateUnversioned
;
156 final List
<Runnable
> copy
= new ArrayList
<Runnable
>(myWaitingUpdateCompletionQueue
.size());
159 synchronized (myLock
) {
160 if ((! myStopped
) && ((! myStarted
) || myPlVcsManager
.isBackgroundVcsOperationRunning()) ||
161 (! ((StartupManagerImpl
) myStartupManager
).startupActivityPassed())) {
162 LOG
.debug("MyRunnable: not started, not stopped, reschedule, project: " + myProject
.getName() + ", runnable: " + hashCode());
163 myRequestSubmitted
= false;
164 // try again after time
165 schedule(myUpdateUnversionedRequested
);
169 copy
.addAll(myWaitingUpdateCompletionQueue
);
170 myRequestSubmitted
= false;
173 LOG
.debug("MyRunnable: STOPPED, project: " + myProject
.getName() + ", runnable: " + hashCode());
177 // take it under lock
178 updateUnversioned
= myUpdateUnversionedRequested
;
179 // for concurrent schedules to tigger flag correctly
180 myUpdateUnversionedRequested
= false;
183 LOG
.debug("MyRunnable: INVOKE, project: " + myProject
.getName() + ", runnable: " + hashCode());
184 myDelegate
.execute(updateUnversioned
, mySharedExecutor
);
185 LOG
.debug("MyRunnable: invokeD, project: " + myProject
.getName() + ", runnable: " + hashCode());
187 synchronized (myLock
) {
188 LOG
.debug("MyRunnable: delete executed, project: " + myProject
.getName() + ", runnable: " + hashCode());
189 if (! copy
.isEmpty()) {
190 myWaitingUpdateCompletionQueue
.removeAll(copy
);
193 if ((! myWaitingUpdateCompletionQueue
.isEmpty()) && (! myRequestSubmitted
)) {
194 LOG
.error("No update task to handle request(s)");
197 // do not run under lock
198 for (Runnable runnable
: copy
) {
201 LOG
.debug("MyRunnable: Runnables executed, project: " + myProject
.getName() + ", runnable: " + hashCode());