Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2002-04-18 17:23:08 -0400
committerMichael Valenta2002-04-18 17:23:08 -0400
commite9656cb090dcc33bbcdf72662ab2cc6fc889c42f (patch)
tree6ca87dc387aa6f18d0a9e912514077c99cdb8392
parent1f18c75f2b546958aa5bf8bfbf7d350cd5802461 (diff)
downloadeclipse.platform.team-e9656cb090dcc33bbcdf72662ab2cc6fc889c42f.tar.gz
eclipse.platform.team-e9656cb090dcc33bbcdf72662ab2cc6fc889c42f.tar.xz
eclipse.platform.team-e9656cb090dcc33bbcdf72662ab2cc6fc889c42f.zip
13854: OutOfMemoryError when checkout files > 8.125 MB
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java49
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties3
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java115
3 files changed, 156 insertions, 11 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
index 22e3bf387..7435b729b 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
@@ -10,6 +10,8 @@
******************************************************************************/
package org.eclipse.team.internal.ccvs.core;
+import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -22,11 +24,13 @@ import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.client.Command;
@@ -60,6 +64,9 @@ public class CVSProviderPlugin extends Plugin {
public static final String PT_AUTHENTICATOR = "authenticator"; //$NON-NLS-1$
public static final String PT_CONNECTIONMETHODS = "connectionmethods"; //$NON-NLS-1$
+ // Directory to cache file contents
+ private static final String CACHE_DIRECTORY = ".cache"; //$NON-NLS-1$
+
private QuietOption quietness;
private int compressionLevel = DEFAULT_COMPRESSION_LEVEL;
private KSubstOption defaultTextKSubstOption = DEFAULT_TEXT_KSUBST_OPTION;
@@ -244,6 +251,8 @@ public class CVSProviderPlugin extends Plugin {
workspace.addResourceChangeListener(metaFileSyncListener, IResourceChangeEvent.PRE_AUTO_BUILD);
workspace.addResourceChangeListener(addDeleteMoveListener, IResourceChangeEvent.POST_AUTO_BUILD);
CVSProviderPlugin.getPlugin().addResourceStateChangeListener(addDeleteMoveListener);
+
+ createCacheDirectory();
}
/**
@@ -258,6 +267,8 @@ public class CVSProviderPlugin extends Plugin {
workspace.removeResourceChangeListener(projectDescriptionListener);
workspace.removeResourceChangeListener(metaFileSyncListener);
workspace.removeResourceChangeListener(addDeleteMoveListener);
+
+ deleteCacheDirectory();
}
/*
@@ -463,5 +474,43 @@ public class CVSProviderPlugin extends Plugin {
this.replaceUnmanaged = replaceUnmanaged;
}
+ private void createCacheDirectory() {
+ try {
+ IPath cacheLocation = getStateLocation().append(CACHE_DIRECTORY);
+ File file = cacheLocation.toFile();
+ if (file.exists()) {
+ deleteFile(file);
+ }
+ file.mkdir();
+ } catch (IOException e) {
+ log(new Status(IStatus.ERROR, ID, 0, Policy.bind("CVSProviderPlugin.errorCreatingCache", e.getMessage()), e)); //$NON-NLS-1$
+ }
+ }
+
+ private void deleteCacheDirectory() {
+ try {
+ IPath cacheLocation = getStateLocation().append(CACHE_DIRECTORY);
+ File file = cacheLocation.toFile();
+ if (file.exists()) {
+ deleteFile(file);
+ }
+ } catch (IOException e) {
+ log(new Status(IStatus.ERROR, ID, 0, Policy.bind("CVSProviderPlugin.errorDeletingCache", e.getMessage()), e)); //$NON-NLS-1$
+ }
+ }
+
+ private void deleteFile(File file) throws IOException {
+ if (file.isDirectory()) {
+ File[] children = file.listFiles();
+ for (int i = 0; i < children.length; i++) {
+ deleteFile(children[i]);
+ }
+ }
+ file.delete();
+ }
+
+ public File getCacheFileFor(String path) throws IOException {
+ return new File(getStateLocation().append(CACHE_DIRECTORY).toFile(), path);
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties
index b2f93a483..3860978ab 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties
@@ -49,6 +49,8 @@ PServerConnection.noResponse=No response from server
PServerConnection.authenticating=Authenticating using pserver
CVSProviderPlugin.cannotUpdateDescription=Error updating project description
+CVSProviderPlugin.errorDeletingCache=Error occured deleting cache: {0}
+CVSProviderPlugin.errorCreatingCache=Error occured creating cache: {0}
CVSProvider.exception=Internal error occured.
CVSProvider.invalidResource=Resource {0} is not a CVS resource
@@ -107,6 +109,7 @@ RemoteFolder.errorFetchingRevisions=Error fetching file revisions
RemoteFolder.doesNotExist=Folder {0} does not exist remotely
RemoteFile.noContentsReceived=No contents received from server for {0}
+RemoteFile.errorRetrievingFromCache=Error occured retrieving cached contents: {0}
RemoteFolderTreeBuilder.buildingBase=Collecting local synchronization information
RemoteFolderTreeBuilder.receivingDelta=Receiving delta for {0}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
index 876807459..03b791bb7 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
@@ -5,8 +5,13 @@ package org.eclipse.team.internal.ccvs.core.resources;
* All Rights Reserved.
*/
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -14,9 +19,9 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.sync.IRemoteResource;
@@ -48,6 +53,9 @@ import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
*/
public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
+ // Contents will be cahced to disk when this thrshold is exceeded
+ private static final int CACHING_THRESHOLD = 32768;
+
// cache for file contents received from the server
private byte[] contents;
// cach the log entry for the remote file
@@ -162,8 +170,26 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
/**
* @see ICVSRemoteFile#getContents()
*/
- public InputStream getContents(IProgressMonitor monitor) {
+ public InputStream getContents(IProgressMonitor monitor) throws CVSException {
if (contents == null) {
+ // First, check to see if there's a cached contents for the file
+ try {
+ try {
+ File ioFile = CVSProviderPlugin.getPlugin().getCacheFileFor(getCacheRelativePath());
+ if (ioFile.exists()) {
+ return new BufferedInputStream(new FileInputStream(ioFile));
+ }
+ } catch (IOException e) {
+ // Try to purge the cache and continue
+ File ioFile = CVSProviderPlugin.getPlugin().getCacheFileFor(getCacheRelativePath());
+ if (ioFile.exists()) {
+ ioFile.delete();
+ }
+ }
+ } catch (IOException e) {
+ // We will end up here if we couldn't read or delete the cache file
+ throw new CVSException(new CVSStatus(IStatus.ERROR, 0, Policy.bind("RemoteFile.errorRetrievingFromCache", e.getMessage()), e));//$NON-NLS-1$
+ }
monitor = Policy.monitorFor(monitor);
monitor.beginTask(Policy.bind("RemoteFile.getContents"), 100); //$NON-NLS-1$
try {
@@ -194,10 +220,19 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
// If the update succeeded but no contents were retreived from the server
// than we can assume that the remote file has no contents.
if (contents == null) {
- contents = new byte[0];
+ // The above is true unless there is a cache file
+ try {
+ File ioFile = CVSProviderPlugin.getPlugin().getCacheFileFor(getCacheRelativePath());
+ if (ioFile.exists()) {
+ return new BufferedInputStream(new FileInputStream(ioFile));
+ } else {
+ contents = new byte[0];
+ }
+ } catch (IOException e) {
+ // Something is wrong with the cached file so signal an error.
+ throw new CVSException(new CVSStatus(IStatus.ERROR, 0, Policy.bind("RemoteFile.errorRetrievingFromCache", e.getMessage()), e));//$NON-NLS-1$
+ }
}
- } catch(CVSException e) {
- return null;
} finally {
monitor.done();
}
@@ -374,6 +409,17 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
}
public InputStream getContents() throws CVSException {
+ if (contents == null) {
+ // Check for cached contents for the file
+ try {
+ File ioFile = CVSProviderPlugin.getPlugin().getCacheFileFor(getCacheRelativePath());
+ if (ioFile.exists()) {
+ return new BufferedInputStream(new FileInputStream(ioFile));
+ }
+ } catch (IOException e) {
+ throw new CVSException(new CVSStatus(IStatus.ERROR, 0, Policy.bind("RemoteFile.errorRetrievingFromCache", e.getMessage()), e));//$NON-NLS-1$
+ }
+ }
return new ByteArrayInputStream(contents == null ? new byte[0] : contents);
}
@@ -381,14 +427,48 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
try {
try {
byte[] buffer = new byte[1024];
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ OutputStream out = byteStream;
int read;
- while ((read = stream.read(buffer)) >= 0) {
- Policy.checkCanceled(monitor);
- out.write(buffer, 0, read);
+ try {
+ try {
+ while ((read = stream.read(buffer)) >= 0) {
+ Policy.checkCanceled(monitor);
+ out.write(buffer, 0, read);
+ // Detect when the file is getting too big to keep in memory
+ // and switch to a caching strategy for the contents of the file
+ if (out == byteStream && byteStream.size() > CACHING_THRESHOLD) {
+ // Get the cache file to write to
+ File ioFile = CVSProviderPlugin.getPlugin().getCacheFileFor(getCacheRelativePath());
+ if ( ! ioFile.getParentFile().exists()) {
+ ioFile.getParentFile().mkdirs();
+ }
+ // Switch streams
+ byteStream.close();
+ out = new BufferedOutputStream(new FileOutputStream(ioFile));
+ // Write what we've read so far
+ out.write(byteStream.toByteArray());
+ // Continue looping until the whole file is read
+ }
+ }
+ } finally {
+ out.close();
+ }
+ } catch (IOException e) {
+ // Make sure we don't leave the cache file around as it may not have the right contents
+ if (byteStream != out) {
+ File ioFile = CVSProviderPlugin.getPlugin().getCacheFileFor(getCacheRelativePath());
+ if (ioFile.exists()) {
+ ioFile.delete();
+ }
+ }
+ throw e;
+ }
+
+ // Set the contents if we didn't cahce them
+ if (out == byteStream) {
+ contents = byteStream.toByteArray();
}
- out.close();
- contents = out.toByteArray();
} finally {
stream.close();
}
@@ -476,4 +556,17 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
RemoteFile remote = (RemoteFile) target;
return super.equals(target) && remote.getRevision().equals(getRevision());
}
+
+ /*
+ * Return the cache relative path for the receiver as
+ * host/cvs/root/module/path/.#filename revision
+ */
+ private String getCacheRelativePath() {
+ ICVSRepositoryLocation location = getRepository();
+ IPath path = new Path(location.getHost());
+ path = path.append(location.getRootDirectory());
+ path = path.append(parent.getRepositoryRelativePath());
+ path = path.append(getName() + ' ' + getRevision());
+ return path.toString();
+ }
} \ No newline at end of file

Back to the top