IDEA-65111 MembershipMap.putOptimal not optimal

This commit is contained in:
irengrig
2011-02-11 10:16:52 +03:00
parent c24d15db6c
commit fa7fab660b
18 changed files with 530 additions and 135 deletions
@@ -543,5 +543,9 @@ public abstract class AbstractVcs<ComList extends CommittedChangeList> extends S
if (myRollbackEnvironment != null) throw new IllegalStateException("Attempt to redefine rollback environment");
myRollbackEnvironment = rollbackEnvironment;
}
public boolean reportsIgnoredDirectories() {
return true;
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vcs;
import com.intellij.util.Consumer;
import com.intellij.util.PairProcessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -55,6 +56,37 @@ public class AreaMap<Key, Val> {
putImpl(key, val);
}
protected int putIfNoParent(final Key key, final Val val) {
if(myMap.put(key, val) != null) {
return -1;
}
if (myKeys.isEmpty()) {
myKeys.add(key);
return 0;
}
final int idx = Collections.binarySearch(myKeys, key, myComparator);
if (idx < 0) {
// insertion, no copy exist
final int insertionIdx = - idx - 1;
// check parent
for (final ListIterator<Key> listIterator = myKeys.listIterator(insertionIdx); listIterator.hasPrevious();) {
final Key previous = listIterator.previous();
if (myKeysResemblance.process(previous, key)) {
myMap.remove(key);
return -1;
}
}
// insertionIdx not necessarily exist
myKeys.add(insertionIdx, key);
return insertionIdx;
}
assert true;
myMap.remove(key);
return -1;
}
protected int putImpl(final Key key, final Val val) {
myMap.put(key, val);
@@ -115,8 +147,8 @@ public class AreaMap<Key, Val> {
// take item before
final int itemBeforeIdx = insertionIdx - 1;
if (itemBeforeIdx >= 0) {
for (int i = itemBeforeIdx; i >= 0; -- i) {
final Key candidate = myKeys.get(i);
for (ListIterator<Key> iterator = myKeys.listIterator(itemBeforeIdx + 1); iterator.hasPrevious(); ) {
final Key candidate = iterator.previous();
if (! myKeysResemblance.process(candidate, key)) continue;
if (consumer.process(candidate, myMap.get(candidate))) break; // if need only a part of keys
}
@@ -38,28 +38,20 @@ public class MembershipMap<Key, Val> extends AreaMap<Key, Val> {
}
public void putOptimal(final Key key, final Val val) {
final int idx = putImpl(key, val);
final int idx = putIfNoParent(key, val);
if (idx < 0) return;
// go for parents
for (int i = idx - 1; i >= 0; -- i) {
if (myKeysResemblance.process(myKeys.get(i), key)) {
consistentRemove(idx);
return;
if (idx + 1 < myKeys.size()) {
for (final ListIterator<Key> listIterator = myKeys.listIterator(idx + 1); listIterator.hasNext();) {
final Key next = listIterator.next();
if (myKeysResemblance.process(key, next)) {
listIterator.remove();
myMap.remove(next);
} else {
break;
}
}
}
for (int i = idx + 1; i < myKeys.size(); ++ i) {
if (myKeysResemblance.process(key, myKeys.get(i))) {
consistentRemove(i);
-- i;
} else {
break;
}
}
}
private void consistentRemove(final int idx) {
final Key keyToRemove = myKeys.remove(idx);
myMap.remove(keyToRemove);
}
public void optimizeMap(final PairProcessor<Val, Val> valuesAreas) {
@@ -96,4 +88,4 @@ public class MembershipMap<Key, Val> extends AreaMap<Key, Val> {
});
return result.get();
}
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* @author irengrig
* Date: 2/10/11
* Time: 3:59 PM
*/
abstract class AbstractIgnoredFilesHolder implements FileHolder, IgnoredFilesHolder {
protected final Project myProject;
private final ProjectLevelVcsManager myVcsManager;
protected AbstractIgnoredFilesHolder(Project project) {
myProject = project;
myVcsManager = ProjectLevelVcsManager.getInstance(project);
}
protected abstract void removeFile(final VirtualFile file);
protected abstract Collection<VirtualFile> keys();
@Override
public void cleanAndAdjustScope(final VcsModifiableDirtyScope scope) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (myProject.isDisposed()) return;
final Iterator<VirtualFile> iterator = keys().iterator();
while (iterator.hasNext()) {
final VirtualFile file = iterator.next();
if (isFileDirty(scope, file)) {
iterator.remove();
}
}
}
});
}
protected boolean isFileDirty(final VcsDirtyScope scope, final VirtualFile file) {
return fileDropped(file) || scope.belongsTo(new FilePathImpl(file));
}
protected boolean fileDropped(final VirtualFile file) {
return !file.isValid() || myVcsManager.getVcsFor(file) == null;
}
}
@@ -295,7 +295,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
private void filterOutIgnoredFiles(final List<VcsDirtyScope> scopes) {
try {
synchronized (myDataLock) {
final RecursiveFileHolder fileHolder = (RecursiveFileHolder)myComposite.get(FileHolder.HolderType.IGNORED);
final IgnoredFilesHolder fileHolder = (IgnoredFilesHolder)myComposite.get(FileHolder.HolderType.IGNORED);
for (Iterator<VcsDirtyScope> iterator = scopes.iterator(); iterator.hasNext();) {
final VcsModifiableDirtyScope scope = (VcsModifiableDirtyScope) iterator.next();
@@ -337,8 +337,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
}
private void updateImmediately(final AtomicSectionsAware atomicSectionsAware) {
final FileHolderComposite composite;
final ChangeListWorker changeListWorker;
final DataHolder dataHolder;
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
if (! vcsManager.hasActiveVcss()) return;
@@ -371,43 +370,26 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
// mark for "modifier" that update started (it would create duplicates of modification commands done by user during update;
// after update of copies of objects is complete, it would apply the same modifications to copies.)
synchronized (myDataLock) {
changeListWorker = myWorker.copy();
composite = (FileHolderComposite) myComposite.copy();
dataHolder = new DataHolder((FileHolderComposite) myComposite.copy(), myWorker.copy(), wasEverythingDirty);
myModifier.enterUpdate();
if (wasEverythingDirty) {
myUpdateException = null;
composite.cleanAll();
}
if (LOG.isDebugEnabled()) {
LOG.debug("refresh procedure started, everything = " + wasEverythingDirty);
}
}
if (wasEverythingDirty) {
changeListWorker.notifyStartProcessingChanges(null);
}
dataHolder.notifyStart();
myChangesViewManager.scheduleRefresh();
final ChangeListManagerGate gate = changeListWorker.createSelfGate();
final ChangeListManagerGate gate = dataHolder.getChangeListWorker().createSelfGate();
// do actual requests about file statuses
final UpdatingChangeListBuilder builder = new UpdatingChangeListBuilder(changeListWorker, composite, new Getter<Boolean>() {
public Boolean get() {
return myUpdater.isStopped();
}
}, myIgnoredIdeaLevel, gate);
final UpdatingChangeListBuilder builder = new UpdatingChangeListBuilder(dataHolder.getChangeListWorker(),
dataHolder.getComposite(), myUpdater.getIsStoppedGetter(), myIgnoredIdeaLevel, gate);
// todo should also ask self flag
myUpdateChangesProgressIndicator = new EmptyProgressIndicator() {
@Override
public boolean isCanceled() {
return myUpdater.isStopped() || atomicSectionsAware.shouldExitAsap();
}
@Override
public void checkCanceled() {
checkIfDisposed();
atomicSectionsAware.checkShouldExit();
}
};
myUpdateChangesProgressIndicator = createProgressIndicator(atomicSectionsAware);
for (final VcsDirtyScope scope : scopes) {
atomicSectionsAware.checkShouldExit();
@@ -416,18 +398,9 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
final VcsModifiableDirtyScope adjustedScope = vcs.adjustDirtyScope((VcsModifiableDirtyScope) scope);
myChangesViewManager.updateProgressText(VcsBundle.message("changes.update.progress.message", vcs.getDisplayName()), false);
if (! wasEverythingDirty) {
composite.cleanAndAdjustScope(adjustedScope);
changeListWorker.notifyStartProcessingChanges(adjustedScope);
}
dataHolder.notifyStartProcessingChanges(adjustedScope);
try {
actualUpdate(wasEverythingDirty, composite, builder, adjustedScope, vcs, changeListWorker, gate);
}
catch (Throwable t) {
LOG.debug(t);
Rethrow.reThrowRuntime(t);
}
actualUpdate(builder, adjustedScope, vcs, dataHolder, gate);
if (myUpdateException != null) break;
}
@@ -435,29 +408,27 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
final boolean takeChanges = (myUpdateException == null);
if (takeChanges) {
// update IDEA-level ignored files
updateIgnoredFiles(composite);
updateIgnoredFiles(dataHolder.getComposite());
}
synchronized (myDataLock) {
// do same modifications to change lists as was done during update + do delayed notifications
if (wasEverythingDirty) {
changeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher());
}
dataHolder.notifyEnd();
myModifier.exitUpdate();
// should be applied for notifications to be delivered (they were delayed)
myModifier.apply(changeListWorker);
myModifier.apply(dataHolder.getChangeListWorker());
myModifier.clearQueue();
// update member from copy
if (takeChanges) {
myWorker.takeData(changeListWorker);
myWorker.takeData(dataHolder.getChangeListWorker());
}
if (takeChanges) {
if (LOG.isDebugEnabled()) {
LOG.debug("refresh procedure finished, size: " + composite.getVFHolder(FileHolder.HolderType.UNVERSIONED).getSize());
LOG.debug("refresh procedure finished, size: " + dataHolder.getComposite().getVFHolder(FileHolder.HolderType.UNVERSIONED).getSize());
}
final boolean statusChanged = ! myComposite.equals(composite);
myComposite = composite;
final boolean statusChanged = ! myComposite.equals(dataHolder.getComposite());
myComposite = dataHolder.getComposite();
if (statusChanged) {
myDelayedNotificator.getProxyDispatcher().unchangedFileStatusChanged();
}
@@ -489,9 +460,71 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
}
}
private void actualUpdate(final boolean wasEverythingDirty, final FileHolderComposite composite, final UpdatingChangeListBuilder builder,
final VcsDirtyScope scope, final AbstractVcs vcs, final ChangeListWorker changeListWorker,
final ChangeListManagerGate gate) {
private EmptyProgressIndicator createProgressIndicator(final AtomicSectionsAware atomicSectionsAware) {
return new EmptyProgressIndicator() {
@Override
public boolean isCanceled() {
return myUpdater.isStopped() || atomicSectionsAware.shouldExitAsap();
}
@Override
public void checkCanceled() {
checkIfDisposed();
atomicSectionsAware.checkShouldExit();
}
};
}
private class DataHolder {
private final boolean myWasEverythingDirty;
final FileHolderComposite myComposite;
final ChangeListWorker myChangeListWorker;
private DataHolder(FileHolderComposite composite, ChangeListWorker changeListWorker, boolean wasEverythingDirty) {
myComposite = composite;
myChangeListWorker = changeListWorker;
myWasEverythingDirty = wasEverythingDirty;
}
public void notifyStart() {
if (myWasEverythingDirty) {
myComposite.cleanAll();
myChangeListWorker.notifyStartProcessingChanges(null);
}
}
public void notifyStartProcessingChanges(@NotNull final VcsModifiableDirtyScope scope) {
if (! myWasEverythingDirty) {
myComposite.cleanAndAdjustScope(scope);
myChangeListWorker.notifyStartProcessingChanges(scope);
}
myComposite.notifyVcsStarted(scope.getVcs());
myChangeListWorker.notifyVcsStarted(scope.getVcs());
}
public void notifyDoneProcessingChanges() {
if (! myWasEverythingDirty) {
myChangeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher());
}
}
public void notifyEnd() {
if (myWasEverythingDirty) {
myChangeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher());
}
}
public FileHolderComposite getComposite() {
return myComposite;
}
public ChangeListWorker getChangeListWorker() {
return myChangeListWorker;
}
}
private void actualUpdate(final UpdatingChangeListBuilder builder, final VcsDirtyScope scope, final AbstractVcs vcs,
final DataHolder dataHolder, final ChangeListManagerGate gate) {
try {
final ChangeProvider changeProvider = vcs.getChangeProvider();
if (changeProvider != null) {
@@ -507,10 +540,12 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
}
}
}
}
finally {
if ((! myUpdater.isStopped()) && !wasEverythingDirty) {
changeListWorker.notifyDoneProcessingChanges(myDelayedNotificator.getProxyDispatcher());
} catch (Throwable t) {
LOG.debug(t);
Rethrow.reThrowRuntime(t);
} finally {
if (! myUpdater.isStopped()) {
dataHolder.notifyDoneProcessingChanges();
}
}
}
@@ -1035,7 +1070,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
synchronized (myDataLock) {
final VirtualFileHolder unversionedHolder = myComposite.getVFHolder(FileHolder.HolderType.UNVERSIONED);
final RecursiveFileHolder<Object> ignoredHolder = (RecursiveFileHolder) myComposite.get(FileHolder.HolderType.IGNORED);
final IgnoredFilesHolder ignoredHolder = (IgnoredFilesHolder) myComposite.get(FileHolder.HolderType.IGNORED);
scheduler.accept(unversionedHolder.getFiles());
scheduler.accept(ignoredHolder.values());
@@ -531,6 +531,11 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
return myLocallyDeleted.isContainedInLocallyDeleted(filePath);
}
public void notifyVcsStarted(AbstractVcs vcs) {
myLocallyDeleted.notifyVcsStarted(vcs);
mySwitchedHolder.notifyVcsStarted(vcs);
}
private abstract class ExternalVsInternalChangesIntersection {
protected final Collection<Change> myInChanges;
protected final Map<Pair<String, String>, LocalChangeList> myInternalMap;
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePath;
import java.util.ArrayList;
@@ -53,6 +54,10 @@ public class DeletedFilesHolder implements FileHolder {
return HolderType.DELETED;
}
@Override
public void notifyVcsStarted(AbstractVcs scope) {
}
public void addFile(final LocallyDeletedChange change) {
myFiles.put(change.getPresentableUrl(), change);
}
@@ -15,12 +15,16 @@
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.vcs.AbstractVcs;
interface FileHolder {
void cleanAll();
void cleanAndAdjustScope(VcsModifiableDirtyScope scope);
FileHolder copy();
HolderType getType();
void notifyVcsStarted(AbstractVcs scope);
static enum HolderType {
DELETED,
UNVERSIONED,
@@ -16,6 +16,7 @@
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcs;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
@@ -29,7 +30,7 @@ public class FileHolderComposite implements FileHolder {
myHolders.put(FileHolder.HolderType.UNVERSIONED, new VirtualFileHolder(project, FileHolder.HolderType.UNVERSIONED));
myHolders.put(FileHolder.HolderType.ROOT_SWITCH, new SwitchedFileHolder(project, HolderType.ROOT_SWITCH));
myHolders.put(FileHolder.HolderType.MODIFIED_WITHOUT_EDITING, new VirtualFileHolder(project, FileHolder.HolderType.MODIFIED_WITHOUT_EDITING));
myHolders.put(FileHolder.HolderType.IGNORED, new RecursiveFileHolder<Object>(project, FileHolder.HolderType.IGNORED));
myHolders.put(FileHolder.HolderType.IGNORED, new IgnoredFilesCompositeHolder(project));
myHolders.put(FileHolder.HolderType.LOCKED, new VirtualFileHolder(project, FileHolder.HolderType.LOCKED));
myHolders.put(FileHolder.HolderType.LOGICALLY_LOCKED, new LogicallyLockedHolder(project));
}
@@ -99,7 +100,13 @@ public class FileHolderComposite implements FileHolder {
throw new UnsupportedOperationException();
}
public RecursiveFileHolder getIgnoredFileHolder() {
return (RecursiveFileHolder) myHolders.get(HolderType.IGNORED);
public IgnoredFilesHolder getIgnoredFileHolder() {
return (IgnoredFilesHolder) myHolders.get(HolderType.IGNORED);
}
public void notifyVcsStarted(AbstractVcs vcs) {
for (FileHolder fileHolder : myHolders.values()) {
fileHolder.notifyVcsStarted(vcs);
}
}
}
@@ -0,0 +1,99 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* @author irengrig
* Date: 2/10/11
* Time: 3:57 PM
*/
public class IgnoredFilesCompositeHolder implements IgnoredFilesHolder {
private final Map<AbstractVcs, IgnoredFilesHolder> myHolderMap;
private final Project myProject;
private AbstractVcs myCurrentVcs;
private final ProjectLevelVcsManager myVcsManager;
public IgnoredFilesCompositeHolder(final Project project) {
super();
myProject = project;
myHolderMap = new HashMap<AbstractVcs, IgnoredFilesHolder>();
myVcsManager = ProjectLevelVcsManager.getInstance(myProject);
}
@Override
public void cleanAll() {
myHolderMap.clear();
}
@Override
public void cleanAndAdjustScope(VcsModifiableDirtyScope scope) {
myHolderMap.get(scope.getVcs()).cleanAndAdjustScope(scope);
}
@Override
public FileHolder copy() {
final IgnoredFilesCompositeHolder result = new IgnoredFilesCompositeHolder(myProject);
result.myHolderMap.putAll(new HashMap<AbstractVcs, IgnoredFilesHolder>(myHolderMap));
return result;
}
@Override
public HolderType getType() {
return HolderType.IGNORED;
}
@Override
public void addFile(VirtualFile file) {
myHolderMap.get(myCurrentVcs).addFile(file);
}
@Override
public boolean containsFile(VirtualFile file) {
final AbstractVcs vcs = myVcsManager.getVcsFor(file);
if (vcs == null) return false;
final IgnoredFilesHolder ignoredFilesHolder = myHolderMap.get(vcs);
return ignoredFilesHolder == null ? false : ignoredFilesHolder.containsFile(file);
}
@Override
public Collection<VirtualFile> values() {
if (myHolderMap.size() == 1) return myHolderMap.values().iterator().next().values();
final HashSet<VirtualFile> result = new HashSet<VirtualFile>();
for (IgnoredFilesHolder holder : myHolderMap.values()) {
result.addAll(holder.values());
}
return result;
}
@Override
public void notifyVcsStarted(AbstractVcs vcs) {
myCurrentVcs = vcs;
if (! myHolderMap.containsKey(vcs)) {
myHolderMap.put(vcs, vcs.reportsIgnoredDirectories() ? (IgnoredFilesHolder) new RecursiveFileHolder(myProject, HolderType.IGNORED) :
new MapIgnoredFilesHolder(myProject));
}
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.Collection;
/**
* @author irengrig
* Date: 2/10/11
* Time: 4:54 PM
*/
public interface IgnoredFilesHolder extends FileHolder {
void addFile(VirtualFile file);
boolean containsFile(VirtualFile file);
Collection<VirtualFile> values();
void cleanAndAdjustScope(VcsModifiableDirtyScope scope);
}
@@ -16,6 +16,7 @@
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.Collections;
@@ -53,6 +54,10 @@ public class LogicallyLockedHolder implements FileHolder {
return HolderType.LOGICALLY_LOCKED;
}
@Override
public void notifyVcsStarted(AbstractVcs vcs) {
}
public boolean containsKey(final VirtualFile vf) {
return myMap.containsKey(vf);
}
@@ -0,0 +1,90 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.hash.HashSet;
import java.util.Collection;
import java.util.Set;
/**
* @author irengrig
* Date: 2/10/11
* Time: 4:20 PM
*/
public class MapIgnoredFilesHolder extends AbstractIgnoredFilesHolder {
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.MapIgnoredFilesHolder");
private final Set<VirtualFile> mySet;
private final Project myProject;
public MapIgnoredFilesHolder(Project project) {
super(project);
myProject = project;
mySet = new HashSet<VirtualFile>();
}
@Override
protected void removeFile(VirtualFile file) {
mySet.remove(file);
}
@Override
protected Collection<VirtualFile> keys() {
return mySet;
}
@Override
public void addFile(VirtualFile file) {
LOG.assertTrue(! file.isDirectory());
mySet.add(file);
}
@Override
public boolean containsFile(VirtualFile file) {
return mySet.contains(file);
}
@Override
public Collection<VirtualFile> values() {
return mySet;
}
@Override
public void cleanAll() {
mySet.clear();
}
@Override
public FileHolder copy() {
final MapIgnoredFilesHolder result = new MapIgnoredFilesHolder(myProject);
result.mySet.addAll(mySet);
return result;
}
@Override
public HolderType getType() {
return HolderType.IGNORED;
}
@Override
public void notifyVcsStarted(AbstractVcs scope) {
}
}
@@ -7,6 +7,7 @@ package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diff.impl.patch.formove.FilePathComparator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.MembershipMap;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
@@ -14,84 +15,67 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PairProcessor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;
/**
* @author max
*/
public class RecursiveFileHolder<T> implements FileHolder {
public class RecursiveFileHolder<T> extends AbstractIgnoredFilesHolder {
protected final HolderType myHolderType;
protected final MembershipMap<VirtualFile, T> myMap;
protected final Project myProject;
protected final TreeMap<VirtualFile, T> myMap;
public RecursiveFileHolder(final Project project, final HolderType holderType) {
myMap = MembershipMap.createMembershipMap(new PairProcessor<VirtualFile, VirtualFile>() {
@Override
public boolean process(final VirtualFile parent, final VirtualFile child) {
return VfsUtil.isAncestor(parent, child, false);
}
}, FilePathComparator.getInstance());
myProject = project;
super(project);
myMap = new TreeMap<VirtualFile, T>(FilePathComparator.getInstance());
myHolderType = holderType;
}
public synchronized void cleanAll() {
public void cleanAll() {
myMap.clear();
}
public void cleanAndAdjustScope(final VcsModifiableDirtyScope scope) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
// to avoid deadlocks caused by incorrect lock ordering, need to lock on this after taking read action
synchronized(RecursiveFileHolder.this) {
if (myProject.isDisposed()) return;
final List<VirtualFile> currentFiles = new ArrayList<VirtualFile>(myMap.keySet());
for (final VirtualFile file : currentFiles) {
if (isFileDirty(scope, file)) {
myMap.remove(file);
}
}
}
}
});
@Override
protected Collection<VirtualFile> keys() {
return myMap.keySet();
}
protected boolean isFileDirty(final VcsDirtyScope scope, final VirtualFile file) {
return fileDropped(file) || scope.belongsTo(new FilePathImpl(file));
@Override
public void notifyVcsStarted(AbstractVcs scope) {
}
public HolderType getType() {
return myHolderType;
}
protected boolean fileDropped(final VirtualFile file) {
return !file.isValid() || ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file) == null;
public void addFile(final VirtualFile file) {
if (! containsFile(file)) {
myMap.put(file, null);
}
}
public synchronized void addFile(final VirtualFile file) {
myMap.putOptimal(file, null);
}
public synchronized void removeFile(final VirtualFile file) {
public void removeFile(final VirtualFile file) {
myMap.remove(file);
}
public synchronized RecursiveFileHolder copy() {
public RecursiveFileHolder copy() {
final RecursiveFileHolder<T> copyHolder = new RecursiveFileHolder<T>(myProject, myHolderType);
copyHolder.myMap.putAll(myMap);
return copyHolder;
}
public synchronized boolean containsFile(final VirtualFile file) {
return myMap.getMapping(file) != null;
public boolean containsFile(final VirtualFile file) {
final VirtualFile floor = myMap.floorKey(file);
if (floor == null) return false;
final SortedMap<VirtualFile, T> floorMap = myMap.headMap(floor, true);
for (VirtualFile parent : floorMap.keySet()) {
if (VfsUtil.isAncestor(parent, file, false)) {
return true;
}
}
return false;
}
public synchronized Collection<VirtualFile> values() {
public Collection<VirtualFile> values() {
return myMap.keySet();
}
@@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PairProcessor;
import com.intellij.util.containers.MultiMap;
@@ -24,6 +25,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
// true = recursively, branch name
public class SwitchedFileHolder extends RecursiveFileHolder<Pair<Boolean, String>> {
@@ -53,7 +55,7 @@ public class SwitchedFileHolder extends RecursiveFileHolder<Pair<Boolean, String
public Map<VirtualFile, String> getFilesMapCopy() {
final HashMap<VirtualFile, String> result = new HashMap<VirtualFile, String>();
for (final VirtualFile vf : myMap.keySet()) {
result.put(vf, myMap.getExact(vf).getSecond());
result.put(vf, myMap.get(vf).getSecond());
}
return result;
}
@@ -66,33 +68,40 @@ public class SwitchedFileHolder extends RecursiveFileHolder<Pair<Boolean, String
public synchronized MultiMap<String, VirtualFile> getBranchToFileMap() {
final MultiMap<String, VirtualFile> result = new MultiMap<String, VirtualFile>();
for (final VirtualFile vf : myMap.keySet()) {
result.putValue(myMap.getExact(vf).getSecond(), vf);
result.putValue(myMap.get(vf).getSecond(), vf);
}
return result;
}
@Override
public synchronized boolean containsFile(final VirtualFile file) {
final Pair<VirtualFile, Pair<Boolean, String>> mapping = myMap.getMapping(file);
if (mapping != null) {
return mapping.getFirst().equals(file) || mapping.getSecond().getFirst();
final VirtualFile floor = myMap.floorKey(file);
if (floor == null) return false;
final SortedMap<VirtualFile, Pair<Boolean, String>> floorMap = myMap.headMap(floor);
for (VirtualFile parent : floorMap.keySet()) {
if (VfsUtil.isAncestor(parent, file, false)) {
final Pair<Boolean, String> value = floorMap.get(parent);
return parent.equals(file) || value.getFirst();
}
}
return false;
}
@Nullable
public String getBranchForFile(final VirtualFile file) {
final Pair<VirtualFile, Pair<Boolean, String>> mapping = myMap.getMapping(file);
if (mapping != null) {
if (mapping.getFirst().equals(file) || mapping.getSecond().getFirst()) {
return mapping.getSecond().getSecond();
final VirtualFile floor = myMap.floorKey(file);
if (floor == null) return null;
final SortedMap<VirtualFile, Pair<Boolean, String>> floorMap = myMap.headMap(floor);
for (VirtualFile parent : floorMap.keySet()) {
if (VfsUtil.isAncestor(parent, file, false)) {
return floorMap.get(parent).getSecond();
}
}
return null;
}
public void calculateChildren() {
myMap.optimizeMap(MyOptimizeProcessor.getInstance());
//myMap.optimizeMap(MyOptimizeProcessor.getInstance());
}
private static class MyOptimizeProcessor implements PairProcessor<Pair<Boolean, String>, Pair<Boolean, String>> {
@@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.SomeQueue;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.util.Consumer;
import com.intellij.util.io.storage.HeavyProcessLatch;
@@ -58,6 +59,7 @@ public class UpdateRequestsQueue {
private final ExecutorWrapper myExecutorWrapper;
@NonNls public static final String LOCAL_CHANGES_UPDATE = "Local changes update";
private final boolean myTrackHeavyLatch;
private Getter<Boolean> myIsStoppedGetter;
public UpdateRequestsQueue(final Project project, final ScheduledExecutorService executor, final LocalChangesUpdater delegate) {
myProject = project;
@@ -75,6 +77,12 @@ public class UpdateRequestsQueue {
// not initialized
myStarted = false;
myStopped = false;
myIsStoppedGetter = new Getter<Boolean>() {
@Override
public Boolean get() {
return isStopped();
}
};
}
public void initialized() {
@@ -82,6 +90,10 @@ public class UpdateRequestsQueue {
myStarted = true;
}
public Getter<Boolean> getIsStoppedGetter() {
return myIsStoppedGetter;
}
public boolean isStopped() {
return myStopped;
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vfs.VirtualFile;
@@ -42,6 +43,10 @@ public class VirtualFileHolder implements FileHolder {
return myType;
}
@Override
public void notifyVcsStarted(AbstractVcs vcs) {
}
public void cleanAll() {
myFiles.clear();
myNumDirs = 0;
@@ -358,4 +358,9 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> {
return myExecutableValidator;
}
}
@Override
public boolean reportsIgnoredDirectories() {
return false;
}
}