Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2003-09-19 19:50:33 +0000
committerMichael Valenta2003-09-19 19:50:33 +0000
commit14d9674e9df3f9ffbdef77af247d8930f5659685 (patch)
tree195601bbebe848b01b4477ec72316df6b31d4aee
parentf3991bda215c1449fd538550cf5c1b0802322708 (diff)
downloadeclipse.platform.team-14d9674e9df3f9ffbdef77af247d8930f5659685.tar.gz
eclipse.platform.team-14d9674e9df3f9ffbdef77af247d8930f5659685.tar.xz
eclipse.platform.team-14d9674e9df3f9ffbdef77af247d8930f5659685.zip
Fix to properly handle intermitant deltas during a CVS operation
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSWorkspaceRoot.java2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java49
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java155
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java42
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java4
7 files changed, 195 insertions, 61 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
index a4d2615c3..4bebfc688 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
@@ -1383,7 +1383,7 @@ public class CVSTeamProvider extends RepositoryProvider {
}
};
try {
- ResourcesPlugin.getWorkspace().run(workspaceRunnable, Policy.monitorFor(monitor));
+ ResourcesPlugin.getWorkspace().run(workspaceRunnable, getProject(), Policy.monitorFor(monitor));
} catch (CoreException e) {
if (exception[0] == null) {
throw CVSException.wrapException(e);
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSWorkspaceRoot.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSWorkspaceRoot.java
index c67155253..0243cc603 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSWorkspaceRoot.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSWorkspaceRoot.java
@@ -291,7 +291,7 @@ public class CVSWorkspaceRoot {
exception[0] = e;
}
}
- }, monitor);
+ }, project, monitor);
if (exception[0] != null)
throw exception[0];
} catch (CoreException e) {
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
index 5453d7e3e..5ec323636 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
@@ -300,7 +300,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder {
error[0] = e;
}
}
- }, monitor);
+ }, getIResource(), monitor);
} catch(CoreException e) {
throw CVSException.wrapException(e);
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
index 93f0364cd..cb0a71e3c 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
@@ -516,7 +516,7 @@ public class EclipseSynchronizer implements IFlushOperation {
}
/**
- * Flush the sync information from the in-memery cache to disk and purge
+ * Flush the sync information from the in-memory cache to disk and purge
* the entries from the cache.
* <p>
* Recursively flushes the sync information for all resources
@@ -586,7 +586,7 @@ public class EclipseSynchronizer implements IFlushOperation {
try {
for (int i = 0; i < roots.length; i++) {
IContainer root = roots[i];
- flush(root, false /*don't flush children*/, null);
+ sessionPropertyCache.purgeCache(root, false /*don't flush children*/);
List changedPeers = new ArrayList();
changedPeers.add(root);
changedPeers.addAll(Arrays.asList(root.members()));
@@ -891,6 +891,11 @@ public class EclipseSynchronizer implements IFlushOperation {
allChanges.addAll(Arrays.asList(changedResources));
allChanges.addAll(Arrays.asList(changedFolders));
allChanges.addAll(dirtyParents);
+ try {
+ allChanges.addAll(Arrays.asList(getResourcesAffectedByChangedIgnoreFiles(threadInfo.getChangedIgnoreFiles())));
+ } catch (CVSException e) {
+ errors.add(e.getStatus());
+ }
IResource[] resources = (IResource[]) allChanges.toArray(
new IResource[allChanges.size()]);
broadcastResourceStateChanges(resources);
@@ -909,7 +914,7 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor.done();
}
}
-
+
/**
* Broadcasts the resource state changes for the given resources to CVS Provider Plugin
*/
@@ -1437,4 +1442,42 @@ public class EclipseSynchronizer implements IFlushOperation {
return ICVSFile.UNKNOWN;
}
}
+
+ /**
+ * Return true if the given resource is contained by the scheduling rule
+ * that is being used by the current thread.
+ * @param resource
+ * @return
+ */
+ public boolean isWithinOperationScope(IResource resource) {
+ return resourceLock.isWithinActiveThread(resource);
+ }
+
+ /**
+ * Record the changed ignore file so it can be handled at the
+ * end of the operation associated with the current thread.
+ * @param resource
+ */
+ public void handleIgnoreFileChange(IResource resource) {
+ Assert.isTrue(resource.getType() == IResource.FILE);
+ resourceLock.recordIgnoreFileChange((IFile)resource);
+ }
+
+ private IResource[] getResourcesAffectedByChangedIgnoreFiles(IFile[] files) throws CVSException {
+ try {
+ Set changedPeers = new HashSet();
+ for (int i = 0; i < files.length; i++) {
+ IContainer parent = files[i].getParent();
+ if (parent.exists()) {
+ // Include the parent
+ changedPeers.add(parent);
+ // Include all siblings
+ changedPeers.addAll(Arrays.asList(parent.members(false)));
+ }
+ }
+ return (IResource[]) changedPeers.toArray(new IResource[changedPeers.size()]);
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ }
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java
index c14556e69..7ec287588 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java
@@ -13,11 +13,13 @@ package org.eclipse.team.internal.ccvs.core.syncinfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@@ -47,7 +49,7 @@ public class ReentrantLock {
private final static boolean DEBUG = Policy.DEBUG_THREADING;
// This is a placeholder rule used to indicate that no scheduling rule is needed
- private static final ISchedulingRule NULL_SCHEDULING_RULE= new ISchedulingRule() {
+ /* internal use only */ static final ISchedulingRule NULL_SCHEDULING_RULE= new ISchedulingRule() {
public boolean contains(ISchedulingRule rule) {
return false;
}
@@ -57,23 +59,61 @@ public class ReentrantLock {
};
public class ThreadInfo {
- private int nestingCount = 0;
private Set changedResources = new HashSet();
private Set changedFolders = new HashSet();
+ private Set changedIgnoreFiles = new HashSet();
private IFlushOperation operation;
private List rules = new ArrayList();
public ThreadInfo(IFlushOperation operation) {
this.operation = operation;
}
- public void increment() {
- nestingCount++;
+ /**
+ * Push a scheduling rule onto the stack for this thread and
+ * acquire the rule if it is not the workspace root.
+ * @param resource
+ */
+ public void pushRule(IResource resource) {
+ // The scheduling rule is either the project or the resource's parent
+ ISchedulingRule rule;
+ if (resource.getType() == IResource.ROOT) {
+ // Never lock the whole workspace
+ rule = NULL_SCHEDULING_RULE;
+ } else if (resource.getType() == IResource.PROJECT) {
+ rule = resource;
+ } else {
+ rule = resource.getParent();
+ }
+ if (rule != NULL_SCHEDULING_RULE) {
+ Platform.getJobManager().beginRule(rule);
+ }
+ addRule(rule);
}
- public int decrement() {
- nestingCount--;
- return nestingCount;
+ /**
+ * Pop the scheduling rule from the stack and release it if it
+ * is not the workspace root. Flush any changed sync info to
+ * disk if necessary. A flush is necessary if the stack is empty
+ * or if the top-most non-null scheduling rule was popped as a result
+ * of this operation.
+ * @param monitor
+ * @throws CVSException
+ */
+ public void popRule(IProgressMonitor monitor) throws CVSException {
+ ISchedulingRule rule = removeRule();
+ if (isFlushRequired()) {
+ flush(monitor);
+ }
+ if (rule != NULL_SCHEDULING_RULE) {
+ Platform.getJobManager().endRule(rule);
+ }
}
- public int getNestingCount() {
- return nestingCount;
+ /**
+ * Return <code>true</code> if we are still nested in
+ * an acquire for this thread.
+ *
+ * @return
+ */
+ public boolean isNested() {
+ return !rules.isEmpty();
}
public void addChangedResource(IResource resource) {
changedResources.add(resource);
@@ -81,8 +121,11 @@ public class ReentrantLock {
public void addChangedFolder(IContainer container) {
changedFolders.add(container);
}
+ public void addChangedIgnoreFile(IFile resource) {
+ changedIgnoreFiles.add(resource);
+ }
public boolean isEmpty() {
- return changedFolders.isEmpty() && changedResources.isEmpty();
+ return changedFolders.isEmpty() && changedResources.isEmpty() && changedIgnoreFiles.isEmpty();
}
public IResource[] getChangedResources() {
return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]);
@@ -90,6 +133,9 @@ public class ReentrantLock {
public IContainer[] getChangedFolders() {
return (IContainer[]) changedFolders.toArray(new IContainer[changedFolders.size()]);
}
+ public IFile[] getChangedIgnoreFiles() {
+ return (IFile[]) changedIgnoreFiles.toArray(new IFile[changedIgnoreFiles.size()]);
+ }
public void flush(IProgressMonitor monitor) throws CVSException {
try {
operation.flush(this, monitor);
@@ -105,15 +151,36 @@ public class ReentrantLock {
changedResources.clear();
changedFolders.clear();
}
+ private boolean isFlushRequired() {
+ return !isNested() || !isNoneNullRules();
+ }
+ private boolean isNoneNullRules() {
+ for (Iterator iter = rules.iterator(); iter.hasNext();) {
+ ISchedulingRule rule = (ISchedulingRule) iter.next();
+ if (rule != NULL_SCHEDULING_RULE) {
+ return true;
+ }
+ }
+ return false;
+ }
private void handleAbortedFlush(Throwable t) {
CVSProviderPlugin.log(new CVSStatus(IStatus.ERROR, Policy.bind("ReentrantLock.9"), t)); //$NON-NLS-1$
}
- public void addRule(ISchedulingRule rule) {
+ private void addRule(ISchedulingRule rule) {
rules.add(rule);
}
- public ISchedulingRule removeRule() {
+ private ISchedulingRule removeRule() {
return (ISchedulingRule)rules.remove(rules.size() - 1);
}
+ public boolean ruleContains(IResource resource) {
+ for (Iterator iter = rules.iterator(); iter.hasNext();) {
+ ISchedulingRule rule = (ISchedulingRule) iter.next();
+ if (rule != NULL_SCHEDULING_RULE) {
+ return rule.contains(resource);
+ }
+ }
+ return false;
+ }
}
public interface IFlushOperation {
@@ -122,10 +189,6 @@ public class ReentrantLock {
private Map infos = new HashMap();
-
- public ReentrantLock() {
- }
-
private ThreadInfo getThreadInfo() {
Thread thisThread = Thread.currentThread();
ThreadInfo info = (ThreadInfo)infos.get(thisThread);
@@ -133,11 +196,6 @@ public class ReentrantLock {
}
public synchronized void acquire(IResource resource, IFlushOperation operation) {
- ISchedulingRule ruleUsed = lock(resource);
- incrementNestingCount(resource, ruleUsed, operation);
- }
-
- private void incrementNestingCount(IResource resource, ISchedulingRule rule, IFlushOperation operation) {
ThreadInfo info = getThreadInfo();
if (info == null) {
info = new ThreadInfo(operation);
@@ -145,31 +203,7 @@ public class ReentrantLock {
infos.put(thisThread, info);
if(DEBUG) System.out.println("[" + thisThread.getName() + "] acquired CVS lock on " + resource.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
}
- info.addRule(rule);
- info.increment();
- }
-
- private ISchedulingRule lock(IResource resource) {
- // The scheduling rule is either the project or the resource's parent
- ISchedulingRule rule;
- if (resource.getType() == IResource.ROOT) {
- // Never lock the whole workspace
- rule = NULL_SCHEDULING_RULE;
- } else if (resource.getType() == IResource.PROJECT) {
- rule = resource;
- } else {
- rule = resource.getParent();
- }
- if (rule != NULL_SCHEDULING_RULE) {
- Platform.getJobManager().beginRule(rule);
- }
- return rule;
- }
-
- private void unlock(ISchedulingRule rule) {
- if (rule != NULL_SCHEDULING_RULE) {
- Platform.getJobManager().endRule(rule);
- }
+ info.pushRule(resource);
}
/**
@@ -181,14 +215,13 @@ public class ReentrantLock {
public synchronized void release(IProgressMonitor monitor) throws CVSException {
ThreadInfo info = getThreadInfo();
Assert.isNotNull(info, "Unmatched acquire/release."); //$NON-NLS-1$
- Assert.isTrue(info.getNestingCount() > 0, "Unmatched acquire/release."); //$NON-NLS-1$
- if (info.decrement() == 0) {
+ Assert.isTrue(info.isNested(), "Unmatched acquire/release."); //$NON-NLS-1$
+ info.popRule(monitor);
+ if (!info.isNested()) {
Thread thisThread = Thread.currentThread();
if(DEBUG) System.out.println("[" + thisThread.getName() + "] released CVS lock"); //$NON-NLS-1$ //$NON-NLS-2$
infos.remove(thisThread);
- info.flush(monitor);
}
- unlock(info.removeRule());
}
public void folderChanged(IContainer folder) {
@@ -211,4 +244,26 @@ public class ReentrantLock {
Assert.isNotNull(info, "Flush requested outside of resource lock"); //$NON-NLS-1$
info.flush(monitor);
}
+
+ /**
+ * Return <code>true</code> if the current thread is part of a CVS operation
+ * and the given resource is contained the scheduling rule held by that operation.
+ * @param resource
+ * @return
+ */
+ public synchronized boolean isWithinActiveThread(IResource resource) {
+ ThreadInfo info = getThreadInfo();
+ if (info == null) return false;
+ return info.ruleContains(resource);
+ }
+
+ /**
+ * Record the ignore file change as part of the current operation.
+ * @param resource
+ */
+ public synchronized void recordIgnoreFileChange(IFile resource) {
+ ThreadInfo info = getThreadInfo();
+ Assert.isNotNull(info);
+ info.addChangedIgnoreFile(resource);
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java
index 5c13b73da..cc7bf8927 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java
@@ -120,10 +120,26 @@ public class SyncFileChangeListener implements IResourceChangeListener {
// }
// }
}
-
- if(isMetaFile(resource)) {
+
+ if(isChangedByActiveCVSOperation(resource)) {
+ // This resource is modified by an active CVS operation
+ // (i.e. this is an intermitant delta)
+ // Notification is not required (or possible) in this case
+ // as the operation will peform the necessary notifications
+ // when it completes
+ if (resource.isTeamPrivateMember()) {
+ // No need to look at meta-files in this case
+ return false;
+ } else if (isIgnoreFile(resource)) {
+ // Add the ignore file to the current operation
+ // so it is handled when the operation completes
+ addIgnoreFileChangeToCVSOperation(resource);
+ }
+ // Must visit children in case there is an ignore file changed
+ return true;
+ } if(isMetaFile(resource)) {
toBeNotified = handleChangedMetaFile(resource, kind);
- } else if(name.equals(SyncFileWriter.IGNORE_FILE)) {
+ } else if(isIgnoreFile(resource)) {
toBeNotified = handleChangedIgnoreFile(resource, kind);
} else if (isExternalDeletion(resource, kind)) {
toBeNotified = handleExternalDeletion(resource);
@@ -153,6 +169,21 @@ public class SyncFileChangeListener implements IResourceChangeListener {
/**
* @param resource
+ */
+ protected void addIgnoreFileChangeToCVSOperation(IResource resource) {
+ EclipseSynchronizer.getInstance().handleIgnoreFileChange(resource);
+ }
+
+ /**
+ * @param resource
+ * @return
+ */
+ protected boolean isChangedByActiveCVSOperation(IResource resource) {
+ return EclipseSynchronizer.getInstance().isWithinOperationScope(resource);
+ }
+
+ /**
+ * @param resource
* @return
*/
protected IContainer[] handleExternalDeletion(IResource resource) {
@@ -232,6 +263,11 @@ public class SyncFileChangeListener implements IResourceChangeListener {
}
}
+ protected boolean isIgnoreFile(IResource resource) {
+ return resource.getType() == IResource.FILE &&
+ resource.getName().equals(SyncFileWriter.IGNORE_FILE);
+ }
+
/*
* It's a meta file if it's parent is a team-private CVS folder.
*/
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
index b305a97a0..774c30761 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
@@ -380,7 +380,7 @@ public class SyncFileWriter {
cvsSubDir.create(false /*don't force*/, true /*make local*/, null);
cvsSubDir.setTeamPrivateMember(true);
}
- }, null);
+ }, folder, null);
}
return cvsSubDir;
} catch (CoreException e) {
@@ -484,7 +484,7 @@ public class SyncFileWriter {
throw new CoreException(e.getStatus());
}
}
- }, null);
+ }, file, null);
} catch (CoreException e) {
throw CVSException.wrapException(e);
}

Back to the top