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
.lifecycle
.AtomicSectionsAware
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.openapi
.util
.Pair
;
21 import com
.intellij
.openapi
.vcs
.*;
22 import com
.intellij
.openapi
.vfs
.VirtualFile
;
23 import com
.intellij
.util
.containers
.MultiMap
;
24 import org
.jetbrains
.annotations
.Nullable
;
29 public class RemoteRevisionsStateCache
implements ChangesOnServerTracker
{
30 private final static long DISCRETE
= 3600000;
32 private final Map
<String
, Pair
<Boolean
, VcsRoot
>> myChanged
;
34 private final MultiMap
<VcsRoot
, String
> myQueries
;
35 private final Map
<VcsRoot
, Long
> myTs
;
36 private final Object myLock
;
37 private ProjectLevelVcsManager myVcsManager
;
38 private final VcsConfiguration myVcsConfiguration
;
40 RemoteRevisionsStateCache(final Project project
) {
41 myVcsManager
= ProjectLevelVcsManager
.getInstance(project
);
42 myChanged
= new HashMap
<String
, Pair
<Boolean
, VcsRoot
>>();
43 myQueries
= new MultiMap
<VcsRoot
, String
>();
44 myTs
= new HashMap
<VcsRoot
, Long
>();
45 myLock
= new Object();
46 myVcsConfiguration
= VcsConfiguration
.getInstance(project
);
49 public void invalidate(final Collection
<String
> paths
) {
50 synchronized (myLock
) {
51 for (String path
: paths
) {
52 myChanged
.remove(path
);
58 private VirtualFile
getRootForPath(final String s
) {
59 return myVcsManager
.getVcsRootFor(new FilePathImpl(new File(s
), false));
62 public boolean isUpToDate(final Change change
) {
63 final List
<File
> files
= ChangesUtil
.getIoFilesFromChanges(Collections
.singletonList(change
));
64 synchronized (myLock
) {
65 for (File file
: files
) {
66 final String path
= file
.getAbsolutePath();
67 final Pair
<Boolean
, VcsRoot
> data
= myChanged
.get(path
);
68 if (data
!= null && Boolean
.TRUE
.equals(data
.getFirst())) return false;
74 public void plus(final Pair
<String
, AbstractVcs
> pair
) {
75 final VirtualFile root
= getRootForPath(pair
.getFirst());
76 if (root
== null) return;
77 synchronized (myLock
) {
78 myQueries
.putValue(new VcsRoot(pair
.getSecond(), root
), pair
.getFirst());
82 public void minus(Pair
<String
, AbstractVcs
> pair
) {
83 final VirtualFile root
= getRootForPath(pair
.getFirst());
84 if (root
== null) return;
85 synchronized (myLock
) {
86 myQueries
.removeValue(new VcsRoot(pair
.getSecond(), root
), pair
.getFirst());
87 myChanged
.remove(pair
.getFirst());
91 public void directoryMappingChanged() {
93 synchronized (myLock
) {
99 public boolean updateStep(final AtomicSectionsAware atomicSectionsAware
) {
100 final MultiMap
<VcsRoot
, String
> dirty
= new MultiMap
<VcsRoot
, String
>();
101 final long oldPoint
= System
.currentTimeMillis() - (myVcsConfiguration
.CHANGED_ON_SERVER_INTERVAL
> 0 ?
102 myVcsConfiguration
.CHANGED_ON_SERVER_INTERVAL
* 60000 : DISCRETE
);
104 synchronized (myLock
) {
105 for (VcsRoot root
: myQueries
.keySet()) {
106 final Collection
<String
> collection
= myQueries
.get(root
);
107 for (String s
: collection
) {
108 dirty
.putValue(root
, s
);
113 final Set
<VcsRoot
> roots
= new HashSet
<VcsRoot
>();
114 for (Map
.Entry
<VcsRoot
, Long
> entry
: myTs
.entrySet()) {
115 if (! dirty
.get(entry
.getKey()).isEmpty()) continue;
117 final Long ts
= entry
.getValue();
118 if ((ts
== null) || (oldPoint
> ts
)) {
119 roots
.add(entry
.getKey());
122 for (Map
.Entry
<String
, Pair
<Boolean
, VcsRoot
>> entry
: myChanged
.entrySet()) {
123 final VcsRoot vcsRoot
= entry
.getValue().getSecond();
124 if ((! dirty
.get(vcsRoot
).isEmpty()) || roots
.contains(vcsRoot
)) {
125 dirty
.putValue(vcsRoot
, entry
.getKey());
130 if (dirty
.isEmpty()) return false;
132 final Map
<String
, Pair
<Boolean
, VcsRoot
>> results
= new HashMap
<String
, Pair
<Boolean
, VcsRoot
>>();
133 for (VcsRoot vcsRoot
: dirty
.keySet()) {
134 atomicSectionsAware
.checkShouldExit();
135 final TreeDiffProvider provider
= vcsRoot
.vcs
.getTreeDiffProvider();
136 if (provider
== null) continue;
138 final Collection
<String
> paths
= dirty
.get(vcsRoot
);
139 final Collection
<String
> remotelyChanged
= provider
.getRemotelyChanged(vcsRoot
.path
, paths
);
140 for (String path
: paths
) {
141 results
.put(path
, new Pair
<Boolean
, VcsRoot
>(remotelyChanged
.contains(path
), vcsRoot
));
145 final long curTime
= System
.currentTimeMillis();
146 synchronized (myLock
) {
147 myChanged
.putAll(results
);
148 for (VcsRoot vcsRoot
: dirty
.keySet()) {
149 myTs
.put(vcsRoot
, curTime
);