### Eclipse Workspace Patch 1.0 #P org.eclipse.core.resources Index: src/org/eclipse/core/internal/resources/Project.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java,v retrieving revision 1.165 diff -u -r1.165 Project.java --- src/org/eclipse/core/internal/resources/Project.java 25 Jan 2010 14:08:43 -0000 1.165 +++ src/org/eclipse/core/internal/resources/Project.java 15 Feb 2010 22:05:39 -0000 @@ -921,14 +921,22 @@ } startup(); //request a refresh if the project is new and has unknown members on disk - // or restore of the project is not fully succesfull + // or restore of the project is not fully successful if ((!used && unknownChildren) || !minorIssuesDuringRestore) { - //refresh either in background or foreground - if ((updateFlags & IResource.BACKGROUND_REFRESH) != 0) { - workspace.refreshManager.refresh(this); - monitor.worked(Policy.opWork * 80 / 100); - } else { - refreshLocal(IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, Policy.opWork * 80 / 100)); + boolean refreshed = false; + if (!used) { + // if a new project and refresh snapshot is present, load it and skip the refresh + refreshed = workspace.getSaveManager().restoreFromRefreshSnapshot( + this, Policy.subMonitorFor(monitor, Policy.opWork * 80 / 100)); + } + if (!refreshed) { + //refresh either in background or foreground + if ((updateFlags & IResource.BACKGROUND_REFRESH) != 0) { + workspace.refreshManager.refresh(this); + monitor.worked(Policy.opWork * 80 / 100); + } else { + refreshLocal(IResource.DEPTH_INFINITE, Policy.subMonitorFor(monitor, Policy.opWork * 80 / 100)); + } } } //creation of this project may affect overlapping resources @@ -1199,6 +1207,26 @@ } } + /** + * Writes a snapshot of the project's refresh information to disk. + */ + public void writeRefreshSnapshot(IProgressMonitor monitor) throws CoreException { + monitor = Policy.monitorFor(monitor); + try { + String msg = NLS.bind(Messages.resources_copying, getName()); + monitor.beginTask(msg, Policy.totalWork); + try { + IProgressMonitor sub = Policy.subMonitorFor(monitor, Policy.opWork / 2, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL); + workspace.getSaveManager().writeRefreshSnapshot(this, sub); + monitor.worked(Policy.opWork / 2); + } catch (OperationCanceledException e) { + workspace.getWorkManager().operationCanceled(); + throw e; + } + } finally { + monitor.done(); + } + } /* * (non-Javadoc) * Index: src/org/eclipse/core/internal/resources/SaveManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java,v retrieving revision 1.102 diff -u -r1.102 SaveManager.java --- src/org/eclipse/core/internal/resources/SaveManager.java 2 Nov 2009 10:12:59 -0000 1.102 +++ src/org/eclipse/core/internal/resources/SaveManager.java 15 Feb 2010 22:05:41 -0000 @@ -12,6 +12,7 @@ import java.io.*; import java.util.*; +import java.util.zip.*; import org.eclipse.core.internal.events.*; import org.eclipse.core.internal.localstore.*; import org.eclipse.core.internal.utils.*; @@ -708,6 +709,35 @@ } /** + * Restores the contents of this project from a refresh snapshot. Throw an exception + * if the snapshot is found but an error occurs when reading the file. + * @return true if the project data was restored successfully, + * and false if the refresh snapshot was not found or could not be opened. + * @exception CoreException if an error occurred reading the snapshot file. + */ + protected boolean restoreFromRefreshSnapshot(Project project, IProgressMonitor monitor) throws CoreException { + boolean status = true; + if (Policy.DEBUG_RESTORE) + System.out.println("Restore project " + project.getFullPath() + ": starting..."); //$NON-NLS-1$ //$NON-NLS-2$ + long start = System.currentTimeMillis(); + monitor = Policy.monitorFor(monitor); + try { + monitor.beginTask("", 40); //$NON-NLS-1$ + status = restoreTreeFromRefreshSnapshot(project, Policy.subMonitorFor(monitor, 40)); + if (status) { + // load the project description and set internal description + ProjectDescription description = workspace.getFileSystemManager().read(project, true); + project.internalSetDescription(description, false); + } + } finally { + monitor.done(); + } + if (Policy.DEBUG_RESTORE) + System.out.println("Restore project " + project.getFullPath() + ": " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return status; + } + + /** * Reads the markers which were originally saved * for the tree rooted by the given resource. */ @@ -970,6 +1000,53 @@ return true; } + /** + * Restores a tree saved as a refresh snapshot to a local file. + * @return true if the snapshot exists, false otherwise. + * @exception CoreException if the project could not be restored. + */ + protected boolean restoreTreeFromRefreshSnapshot(Project project, IProgressMonitor monitor) throws CoreException { + long start = System.currentTimeMillis(); + monitor = Policy.monitorFor(monitor); + String message; + try { + monitor.beginTask("", Policy.totalWork); //$NON-NLS-1$ + IPath projectLocation = project.getLocation(); + if (projectLocation == null){ + //TODO handle case where project is on remote store + return false; + } + IPath snapshotLocation = projectLocation.append(IProject.REFRESH_SNAPSHOT_FILE_LOCATION); + java.io.File zipFile = snapshotLocation.toFile(); + if (!zipFile.exists()) + return false; + ZipFile zip = new ZipFile(zipFile); + ZipEntry treeEntry = zip.getEntry("resource-index.tree"); //$NON-NLS-1$ + if (treeEntry == null) { + zip.close(); + return false; + } + InputStream is = zip.getInputStream(treeEntry); + DataInputStream input = new DataInputStream(is); + try { + WorkspaceTreeReader reader = WorkspaceTreeReader.getReader(workspace, input.readInt()); + reader.readTree(project, input, Policy.subMonitorFor(monitor, Policy.totalWork)); + } finally { + input.close(); + zip.close(); + } + } catch (IOException e) { + message = NLS.bind(Messages.resources_readMeta, project.getFullPath()); + throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, project.getFullPath(), message, e); + } finally { + monitor.done(); + } + if (Policy.DEBUG_RESTORE_TREE) { + System.out.println("Restore Tree for " + project.getFullPath() + ": " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + return true; + } + class InternalMonitorWrapper extends ProgressMonitorWrapper{ private boolean ignoreCancel; @@ -1640,6 +1717,51 @@ info.writeTo(output); } + public void writeRefreshSnapshot(Project project, IProgressMonitor monitor) throws CoreException { + String snapshotPath = IProject.REFRESH_SNAPSHOT_FILE_LOCATION; + IPath snapshotLocation = project.getLocation().append(snapshotPath); + java.io.File tmpTree = null; + try { + tmpTree = java.io.File.createTempFile("tmp", ".tree"); //$NON-NLS-1$//$NON-NLS-2$ + } catch (IOException e) { + throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, snapshotLocation, Messages.resources_copyProblem, e); + } + java.io.File snapshotLocationFile = snapshotLocation.toFile(); + snapshotLocationFile.delete(); + ZipOutputStream out = null; + try { + FileOutputStream fis = new FileOutputStream(tmpTree); + DataOutputStream output = new DataOutputStream(fis); + try { + output.writeInt(ICoreConstants.WORKSPACE_TREE_VERSION_2); + writeTree(project, output, null); + } finally { + output.close(); + } + snapshotLocationFile.getParentFile().mkdirs(); + out = new ZipOutputStream(new FileOutputStream(snapshotLocationFile)); + out.setLevel(Deflater.BEST_COMPRESSION); + ZipEntry e = new ZipEntry("resource-index.tree"); //$NON-NLS-1$ + out.putNextEntry(e); + int read = 0; + byte[] buffer = new byte[4096]; + InputStream in = new FileInputStream(tmpTree); + try { + while ((read = in.read(buffer)) >= 0) { + out.write(buffer, 0, read); + } + out.closeEntry(); + } finally { + in.close(); + } + out.close(); + tmpTree.delete(); + } catch (IOException e) { + throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, snapshotLocation, Messages.resources_copyProblem, e); + } + monitor.worked(1); + } + protected void writeTree(Map statesToSave, DataOutputStream output, IProgressMonitor monitor) throws IOException, CoreException { monitor = Policy.monitorFor(monitor); try { Index: src/org/eclipse/core/resources/IProject.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.core.resources/src/org/eclipse/core/resources/IProject.java,v retrieving revision 1.47 diff -u -r1.47 IProject.java --- src/org/eclipse/core/resources/IProject.java 25 Jan 2010 14:08:44 -0000 1.47 +++ src/org/eclipse/core/resources/IProject.java 15 Feb 2010 22:05:42 -0000 @@ -42,6 +42,12 @@ */ public interface IProject extends IContainer, IAdaptable { /** + * The location of the refresh snapshot used when opening a new + * project to skip the normal refresh of resources. + */ + public static final String REFRESH_SNAPSHOT_FILE_LOCATION = + ".settings/resource-index.zip"; //$NON-NLS-1$ + /** * Invokes the build method of the specified builder * for this project. Does nothing if this project is closed. If this project * has multiple builders on its build spec matching the given name, only @@ -621,13 +627,15 @@ * of its resources from information stored on disk. *

*

- * The BACKGROUND_REFRESH update flag controls how - * this method behaves when a project is opened for the first time on a location - * that has existing resources on disk. If this flag is specified, resources on disk - * will be added to the project in the background after this method returns. - * Child resources of the project may not be available until this background - * refresh completes. If this flag is not specified, resources on disk are added - * to the project in the foreground before this method returns. + * When a project is opened for the first time, initial information about the + * project's existing resources can be obtained in the following ways: + *

*

* This method changes resources; these changes will be reported * in a subsequent resource change event that includes @@ -852,4 +860,18 @@ * @since 3.6 */ public IPathVariableManager getPathVariableManager(); + + /** + * Writes a snapshot of project refresh info for this project. + * + * @param monitor a progress monitor, or null if progress + * reporting is not desired + * @exception CoreException if this method fails. Reasons include: + * + * @exception OperationCanceledException if the operation is canceled. + * @since 3.6 + */ + public void writeRefreshSnapshot(IProgressMonitor monitor) throws CoreException; }