17940: Synchronize outgoing changes opens a connection per file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolderTreeBuilder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolderTreeBuilder.java
index d758cba..d287041 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolderTreeBuilder.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolderTreeBuilder.java
@@ -26,6 +26,7 @@
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteResource;
import org.eclipse.team.internal.ccvs.core.ICVSResource;
+import org.eclipse.team.internal.ccvs.core.ICVSRunnable;
import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.client.Command;
import org.eclipse.team.internal.ccvs.core.client.Session;
@@ -169,22 +170,20 @@
monitor.beginTask(null, 100);
Policy.checkCanceled(monitor);
- Session session = new Session(repository, root, false);
- session.open(Policy.subMonitorFor(monitor, 10));
- try {
- Policy.checkCanceled(monitor);
- fetchDelta(session, Session.CURRENT_LOCAL_FOLDER, Policy.subMonitorFor(monitor, 50));
- if (projectDoesNotExist) {
- // We cannot handle the case where a project (i.e. the top-most CVS folder)
- // has been deleted directly on the sever (i.e. deleted using rm -rf)
- if (root.isCVSFolder() && ! root.isManaged()) {
- throw new CVSException(Policy.bind("RemoteFolderTreeBuild.folderDeletedFromServer", root.getFolderSyncInfo().getRepository())); //$NON-NLS-1$
- } else {
- return null;
- }
+ Session.run(repository, root, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ Policy.checkCanceled(monitor);
+ fetchDelta(new ICVSResource[] { root }, monitor);
}
- } finally {
- session.close();
+ }, Policy.subMonitorFor(monitor, 50));
+ if (projectDoesNotExist) {
+ // We cannot handle the case where a project (i.e. the top-most CVS folder)
+ // has been deleted directly on the sever (i.e. deleted using rm -rf)
+ if (root.isCVSFolder() && ! root.isManaged()) {
+ throw new CVSException(Policy.bind("RemoteFolderTreeBuild.folderDeletedFromServer", root.getFolderSyncInfo().getRepository())); //$NON-NLS-1$
+ } else {
+ return null;
+ }
}
// We need a second session because of the use of a different handle on the same remote resource
// Perhaps we could support the changing of a sessions root as long as
@@ -193,40 +192,36 @@
new RemoteFolderTree(null, root.getName(), repository,
new Path(root.getFolderSyncInfo().getRepository()),
tagForRemoteFolder(root, tag));
- session = new Session(repository, remoteRoot, false);
- session.open(Policy.subMonitorFor(monitor, 10));
- try {
- // Set up an infinite progress monitor for the recursive build
- IProgressMonitor subProgress = Policy.infiniteSubMonitorFor(monitor, 30);
- subProgress.beginTask(null, 512);
- // Build the remote tree
- buildRemoteTree(session, root, remoteRoot, Path.EMPTY, subProgress);
- // we can only fecth the status for up to 1024 files in a single connection due to
- // the server which has a limit on the number of "open" files.
- if (!changedFiles.isEmpty() && changedFiles.size() <= MAX_REVISION_FETCHES_PER_CONNECTION) {
- fetchFileRevisions(session, (String[])changedFiles.toArray(new String[changedFiles.size()]), Policy.subMonitorFor(monitor, 20));
+ Session.run(repository, remoteRoot, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ // Set up an infinite progress monitor for the recursive build
+ IProgressMonitor subProgress = Policy.infiniteSubMonitorFor(monitor, 30);
+ subProgress.beginTask(null, 512);
+ // Build the remote tree
+ buildRemoteTree(root, remoteRoot, Path.EMPTY, subProgress);
+ // we can only fetch the status for up to 1024 files in a single connection due to
+ // the server which has a limit on the number of "open" files.
+ if (!changedFiles.isEmpty() && changedFiles.size() <= MAX_REVISION_FETCHES_PER_CONNECTION) {
+ fetchFileRevisions((ICVSResource[])changedFiles.toArray(new ICVSResource[changedFiles.size()]), Policy.subMonitorFor(monitor, 20));
+ }
}
- } finally {
- session.close();
- }
+ }, Policy.infiniteSubMonitorFor(monitor, 30));
// If there were more than 1024 changed files, we need a connection per each 1024
if (!changedFiles.isEmpty() && changedFiles.size() > MAX_REVISION_FETCHES_PER_CONNECTION) {
- String[] allChangedFiles = (String[])changedFiles.toArray(new String[changedFiles.size()]);
+ ICVSResource[] allChangedFiles = (ICVSResource[])changedFiles.toArray(new String[changedFiles.size()]);
int iterations = (allChangedFiles.length / MAX_REVISION_FETCHES_PER_CONNECTION)
+ (allChangedFiles.length % MAX_REVISION_FETCHES_PER_CONNECTION == 0 ? 0 : 1);
for (int i = 0; i < iterations ; i++) {
int length = Math.min(MAX_REVISION_FETCHES_PER_CONNECTION,
allChangedFiles.length - (MAX_REVISION_FETCHES_PER_CONNECTION * i));
- String buffer[] = new String[length];
+ final ICVSResource buffer[] = new ICVSResource[length];
System.arraycopy(allChangedFiles, i * MAX_REVISION_FETCHES_PER_CONNECTION, buffer, 0, length);
- session = new Session(repository, remoteRoot, false);
- session.open(Policy.subMonitorFor(monitor, 1));
- try {
- fetchFileRevisions(session, buffer, Policy.subMonitorFor(monitor, 2));
- } finally {
- session.close();
- }
+ Session.run(repository, remoteRoot, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ fetchFileRevisions(buffer, monitor);
+ }
+ }, Policy.subMonitorFor(monitor, 2));
}
}
@@ -238,7 +233,7 @@
}
}
- private RemoteFile buildTree(ICVSFile file, IProgressMonitor monitor) throws CVSException {
+ private RemoteFile buildTree(final ICVSFile file, IProgressMonitor monitor) throws CVSException {
QuietOption quietness = CVSProviderPlugin.getPlugin().getQuietness();
try {
CVSProviderPlugin.getPlugin().setQuietness(Command.VERBOSE);
@@ -247,22 +242,21 @@
// Query the server to see if there is a delta available
Policy.checkCanceled(monitor);
- Session session = new Session(repository, root, false);
- session.open(Policy.subMonitorFor(monitor, 10));
- try {
- Policy.checkCanceled(monitor);
- fetchDelta(session, file.getName(), Policy.subMonitorFor(monitor, 50));
- if (projectDoesNotExist) {
- return null;
+ Session.run(repository, root, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ Policy.checkCanceled(monitor);
+ fetchDelta(new ICVSResource[] { file }, Policy.subMonitorFor(monitor, 50));
}
- } finally {
- session.close();
+ }, Policy.subMonitorFor(monitor, 50));
+ if (projectDoesNotExist) {
+ return null;
}
// Create a parent for the remote resource
remoteRoot =
new RemoteFolderTree(null, root.getName(), repository,
new Path(root.getFolderSyncInfo().getRepository()),
tagForRemoteFolder(root, tag));
+
// Create the remote resource (using the delta if there is one)
RemoteFile remoteFile;
Map deltas = (Map)fileDeltas.get(Path.EMPTY);
@@ -286,13 +280,11 @@
if (!changedFiles.isEmpty()) {
// Add the remote folder to the remote folder lookup table (used to update file revisions)
remoteFolderTable.put(new Path(remoteRoot.getFolderSyncInfo().getRemoteLocation()), remoteRoot);
- session = new Session(repository, remoteRoot, false);
- session.open(Policy.subMonitorFor(monitor, 10));
- try {
- fetchFileRevisions(session, (String[])changedFiles.toArray(new String[changedFiles.size()]), Policy.subMonitorFor(monitor, 20));
- } finally {
- session.close();
- }
+ Session.run(repository, remoteRoot, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ fetchFileRevisions((ICVSResource[])changedFiles.toArray(new ICVSResource[changedFiles.size()]), monitor);
+ }
+ }, Policy.subMonitorFor(monitor, 20));
}
return remoteFile;
@@ -363,7 +355,7 @@
*
* Does 1 work for each file and folder delta processed
*/
- private void buildRemoteTree(Session session, ICVSFolder local, RemoteFolderTree remote, IPath localPath, IProgressMonitor monitor) throws CVSException {
+ private void buildRemoteTree(ICVSFolder local, RemoteFolderTree remote, IPath localPath, IProgressMonitor monitor) throws CVSException {
Policy.checkCanceled(monitor);
@@ -375,7 +367,7 @@
// If there's no corresponding local resource then we need to fetch its contents in order to populate the deltas
if (local == null) {
- fetchNewDirectory(session, remote, localPath, monitor);
+ fetchNewDirectory(remote, monitor);
}
// Fetch the delta's for the folder
@@ -390,7 +382,7 @@
for (int i=0;i<folders.length;i++) {
ICVSFolder folder = (ICVSFolder)folders[i];
DeltaNode d = (DeltaNode)deltas.get(folder.getName());
- if (folder.isCVSFolder() && ! isOrphanedSubtree(session, folder) && (d==null || d.getRevision() != DELETED)) {
+ if (folder.isCVSFolder() && ! isOrphanedSubtree(folder) && (d==null || d.getRevision() != DELETED)) {
children.put(folders[i].getName(),
new RemoteFolderTree(remote, folders[i].getName(), repository,
new Path(folder.getFolderSyncInfo().getRepository()),
@@ -469,7 +461,7 @@
localFolder = null;
else
localFolder = local.getFolder(name);
- buildRemoteTree(session, localFolder, remoteFolder, localPath.append(name), monitor);
+ buildRemoteTree(localFolder, remoteFolder, localPath.append(name), monitor);
// Record any children that are empty
if (pruneEmptyDirectories() && remoteFolder.getChildren().length == 0) {
// Prune if the local folder is also empty.
@@ -501,11 +493,11 @@
*
* Returns the list of changed files
*/
- private List fetchDelta(Session session, String argument, final IProgressMonitor monitor) throws CVSException {
+ private List fetchDelta(final ICVSResource[] arguments, final IProgressMonitor monitor) throws CVSException {
// Create an listener that will accumulate new and removed files and folders
final List newChildDirectories = new ArrayList();
- IUpdateMessageListener listener = new IUpdateMessageListener() {
+ final IUpdateMessageListener listener = new IUpdateMessageListener() {
public void directoryInformation(ICVSFolder root, IPath path, boolean newDirectory) {
if (newDirectory) {
// Record new directory with parent so it can be retrieved when building the parent
@@ -543,7 +535,11 @@
break;
case Update.STATE_DELETED : // We have a locally removed file that still exists remotely
case Update.STATE_REMOTE_CHANGES : // We have an remote change to an unmodified local file
- changedFiles.add(filename);
+ try {
+ changedFiles.add(root.getFile(filename));
+ } catch (CVSException e) {
+ CVSProviderPlugin.log(e.getStatus());
+ }
recordDelta(new Path(filename), UNKNOWN, type);
monitor.subTask(Policy.bind("RemoteFolderTreeBuilder.receivingDelta", filename)); //$NON-NLS-1$
break;
@@ -558,12 +554,16 @@
// Perform a "cvs -n update -d [-r tag] ." in order to get the
// messages from the server that will indicate what has changed on the
// server.
- IStatus status = Command.UPDATE.execute(session,
- new GlobalOption[] { Command.DO_NOT_CHANGE },
- updateLocalOptions,
- new String[] { argument },
- new UpdateListener(listener),
- monitor);
+ Session.run(repository, root, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ IStatus status = Command.UPDATE.execute(
+ new GlobalOption[] { Command.DO_NOT_CHANGE },
+ updateLocalOptions,
+ arguments,
+ new UpdateListener(listener),
+ monitor);
+ }
+ }, monitor);
return changedFiles;
}
/*
@@ -571,10 +571,10 @@
*
* The fetch may do up to 2 units of work in the provided monitor.
*/
- private void fetchNewDirectory(Session session, RemoteFolderTree newFolder, IPath localPath, final IProgressMonitor monitor) throws CVSException {
+ private void fetchNewDirectory(final RemoteFolderTree newFolder, final IProgressMonitor monitor) throws CVSException {
// Create an listener that will accumulate new files and folders
- IUpdateMessageListener listener = new IUpdateMessageListener() {
+ final IUpdateMessageListener listener = new IUpdateMessageListener() {
public void directoryInformation(ICVSFolder root, IPath path, boolean newDirectory) {
if (newDirectory) {
// Record new directory with parent so it can be retrieved when building the parent
@@ -587,7 +587,11 @@
}
public void fileInformation(int type, ICVSFolder root, String filename) {
// NOTE: Check path prefix
- changedFiles.add(filename);
+ try {
+ changedFiles.add(root.getFile(filename));
+ } catch (CVSException e) {
+ CVSProviderPlugin.log(e.getStatus());
+ }
recordDelta(new Path(filename), ADDED, type);
monitor.subTask(Policy.bind("RemoteFolderTreeBuilder.receivingDelta", filename)); //$NON-NLS-1$
}
@@ -595,42 +599,44 @@
}
};
- // NOTE: Should use the path relative to the remoteRoot
- IPath path = new Path(newFolder.getRepositoryRelativePath());
- IStatus status = Command.UPDATE.execute(session,
- new GlobalOption[] { Command.DO_NOT_CHANGE },
- updateLocalOptions,
- new String[] { localPath.toString() },
- new UpdateListener(listener),
- Policy.subMonitorFor(monitor, 1));
- if (status.getCode() == CVSStatus.SERVER_ERROR) {
- // FIXME: This should be refactored (maybe static methods on CVSException?)
- CVSServerException e = new CVSServerException(status);
- if ( ! e.isNoTagException() && e.containsErrors())
- throw e;
- // we now know that this is an exception caused by a cvs bug.
- // if the folder has no files in it (just subfolders) cvs does not respond with the subfolders...
- // workaround: retry the request with no tag to get the directory names (if any)
- Policy.checkCanceled(monitor);
- status = Command.UPDATE.execute(session,
- new GlobalOption[] { Command.DO_NOT_CHANGE },
- getOptionsWithoutTag(),
- new String[] { localPath.toString() },
- new UpdateListener(listener),
- Policy.subMonitorFor(monitor, 1));
- if (status.getCode() == CVSStatus.SERVER_ERROR) {
- throw new CVSServerException(status);
+ Session.run(repository, remoteRoot, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ IStatus status = Command.UPDATE.execute(
+ new GlobalOption[] { Command.DO_NOT_CHANGE },
+ updateLocalOptions,
+ new ICVSResource[] { newFolder },
+ new UpdateListener(listener),
+ monitor);
+ if (status.getCode() == CVSStatus.SERVER_ERROR) {
+ // FIXME: This should be refactored (maybe static methods on CVSException?)
+ CVSServerException e = new CVSServerException(status);
+ if ( ! e.isNoTagException() && e.containsErrors())
+ throw e;
+ // we now know that this is an exception caused by a cvs bug.
+ // if the folder has no files in it (just subfolders) cvs does not respond with the subfolders...
+ // workaround: retry the request with no tag to get the directory names (if any)
+ Policy.checkCanceled(monitor);
+ status = Command.UPDATE.execute(
+ new GlobalOption[] { Command.DO_NOT_CHANGE },
+ getOptionsWithoutTag(),
+ new ICVSResource[] { newFolder },
+ new UpdateListener(listener),
+ monitor);
+ if (status.getCode() == CVSStatus.SERVER_ERROR) {
+ throw new CVSServerException(status);
+ }
+ }
}
- }
+ }, Policy.subMonitorFor(monitor, 1));
}
// Get the file revisions for the given filenames
- private void fetchFileRevisions(Session session, String[] fileNames, final IProgressMonitor monitor) throws CVSException {
+ private void fetchFileRevisions(final ICVSResource[] files, final IProgressMonitor monitor) throws CVSException {
// Create a listener for receiving the revision info
final Map revisions = new HashMap();
final List exceptions = new ArrayList();
- IStatusListener listener = new IStatusListener() {
+ final IStatusListener listener = new IStatusListener() {
public void fileStatus(ICVSFolder root, IPath path, String remoteRevision) {
try {
updateRevision(path, remoteRevision);
@@ -642,17 +648,22 @@
};
// Perform a "cvs status..." with a custom message handler
- IStatus status = Command.STATUS.execute(session,
- Command.NO_GLOBAL_OPTIONS,
- Command.NO_LOCAL_OPTIONS,
- fileNames,
- new StatusListener(listener),
- monitor);
- if (status.getCode() == CVSStatus.SERVER_ERROR) {
- throw new CVSServerException(status);
- }
+ Session.run(repository, remoteRoot, false, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ IStatus status = Command.STATUS.execute(
+ Command.NO_GLOBAL_OPTIONS,
+ Command.NO_LOCAL_OPTIONS,
+ files,
+ new StatusListener(listener),
+ monitor);
+ if (status.getCode() == CVSStatus.SERVER_ERROR) {
+ throw new CVSServerException(status);
+ }
+ }
+ }, monitor);
+
- // Report any exceptions that occured fecthing the revisions
+ // Report any exceptions that occured fetching the revisions
if ( ! exceptions.isEmpty()) {
if (exceptions.size() == 1) {
throw (CVSException)exceptions.get(0);
@@ -711,8 +722,8 @@
return tag == null ? folder.getFolderSyncInfo().getTag() : tag;
}
- private boolean isOrphanedSubtree(Session session, ICVSFolder mFolder) throws CVSException {
- return mFolder.isCVSFolder() && ! mFolder.isManaged() && ! mFolder.equals(session.getLocalRoot()) && mFolder.getParent().isCVSFolder();
+ private boolean isOrphanedSubtree(ICVSFolder mFolder) throws CVSException {
+ return mFolder.isCVSFolder() && ! mFolder.isManaged() && ! mFolder.equals(remoteRoot) && mFolder.getParent().isCVSFolder();
}
}