IDEA-27223 (SVN lockout)
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / RemoteRevisionsStateCache.java
blobb920a082832f63561a0dbe5c105b792365846688
1 /*
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;
26 import java.io.File;
27 import java.util.*;
29 public class RemoteRevisionsStateCache implements ChangesOnServerTracker {
30 private final static long DISCRETE = 3600000;
31 // true -> changed
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);
57 @Nullable
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;
71 return true;
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() {
92 // todo will work?
93 synchronized (myLock) {
94 myChanged.clear();
95 myTs.clear();
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);
111 myQueries.clear();
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 // todo - actually it means nothing since the only known VCS to use this scheme is Git and now it always allow
136 // todo - background operations. when it changes, develop more flexible behavior here
137 if (! vcsRoot.vcs.isVcsBackgroundOperationsAllowed(vcsRoot.path)) continue;
138 final TreeDiffProvider provider = vcsRoot.vcs.getTreeDiffProvider();
139 if (provider == null) continue;
141 final Collection<String> paths = dirty.get(vcsRoot);
142 final Collection<String> remotelyChanged = provider.getRemotelyChanged(vcsRoot.path, paths);
143 for (String path : paths) {
144 results.put(path, new Pair<Boolean, VcsRoot>(remotelyChanged.contains(path), vcsRoot));
148 final long curTime = System.currentTimeMillis();
149 synchronized (myLock) {
150 myChanged.putAll(results);
151 for (VcsRoot vcsRoot : dirty.keySet()) {
152 myTs.put(vcsRoot, curTime);
156 return true;