diff options
| author | Sergey Prigogin | 2014-06-21 01:19:45 +0000 |
|---|---|---|
| committer | Szymon Ptaszkiewicz | 2014-08-25 14:31:00 +0000 |
| commit | 6d731e6a228429caed8a0077302e31bd4f8d8185 (patch) | |
| tree | 5d54a7987e21f4ac8d1d847c6167ab3e02ab9d46 | |
| parent | 300b8dada6479bfc2cac77b38b004f5ed86f7630 (diff) | |
| download | eclipse.platform.resources-6d731e6a228429caed8a0077302e31bd4f8d8185.tar.gz eclipse.platform.resources-6d731e6a228429caed8a0077302e31bd4f8d8185.tar.xz eclipse.platform.resources-6d731e6a228429caed8a0077302e31bd4f8d8185.zip | |
Bug 437005 - Out-of-date .snap file prevents Eclipse from runningR4_4_2R4_4_1M20150204-1700M20150204-0900M20150128-1000M20150122-0430M20150122-0330M20150121-0900M20150114-1500M20150114-1100M20150114-1015M20150114-1000M20150114-0900M20150107-0900M20141231-0900M20141224-0900M20141217-0900M20141210-0900M20141205-1400M20141205-1000M20141203-0800M20141126-0800M20141119-0800M20141112-0800M20141105-0800M20141029-0900M20141022-0800M20141015-0900M20141015-0800M20140925-0400M20140910-2310M20140910-0900M20140903-1600M20140903-0800M20140902-1430M20140829-0500M20140827-1200M20140827-0800R4_4_maintenance
The fix changes the name of the tree snapshot file from .snap to
<sequence_number>.snap, where the sequence number matches the sequence
number of the tree file. With this change a failure to delete a snapshot
file after creating a new tree file is no longer fatal since the
leftover snapshot file would not match the sequence number of the tree
file and will be ignored while restoring the workspace.
Backward compatibility is achieved by checking for the .snap file if the
<sequence_number>.snap file is not found. The .snap file is accepted
only if its last modification time is not lower than the last
modification time of the tree file.
Change-Id: I2a8ca8ad79b788089e4d42d1c310f642f152700a
Signed-off-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
2 files changed, 97 insertions, 42 deletions
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/LocalMetaArea.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/LocalMetaArea.java index 6e6d94ccc..6c03bd548 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/LocalMetaArea.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/LocalMetaArea.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,8 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Francis Lynch (Wind River) - [301563] Save and load tree snapshots - * Broadcom Corporation - ongoing development + * Francis Lynch (Wind River) - [301563] Save and load tree snapshots + * Broadcom Corporation - ongoing development + * Sergey Prigogin (Google) - [437005] Out-of-date .snap file prevents Eclipse from running *******************************************************************************/ package org.eclipse.core.internal.resources; @@ -176,7 +177,28 @@ public class LocalMetaArea implements ICoreConstants { return prefix.append(pluginId + "." + saveNumber); //$NON-NLS-1$ } + /** + * Returns the path of the snapshot file. The name of the file is composed from a sequence + * number corresponding to the sequence number of tree file and ".snap" extension. Should + * only be called for the workspace root. + */ public IPath getSnapshotLocationFor(IResource resource) { + Assert.isNotNull(resource); + Assert.isLegal(resource.getType() == IResource.ROOT); + IPath key = resource.getFullPath().append(F_TREE); + String sequenceNumber = getWorkspace().getSaveManager().getMasterTable().getProperty(key.toString()); + if (sequenceNumber == null) + sequenceNumber = "0"; //$NON-NLS-1$ + return metaAreaLocation.append(sequenceNumber + F_SNAP); + } + + /** + * Returns the legacy, pre-4.4.1, path of the snapshot file. The name of the legacy snapshot + * file is ".snap". Should only be called for the workspace root. + */ + public IPath getLegacySnapshotLocationFor(IResource resource) { + Assert.isNotNull(resource); + Assert.isLegal(resource.getType() == IResource.ROOT); return metaAreaLocation.append(F_SNAP); } diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java index 88b3ddd2f..8ab488cc1 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java @@ -11,10 +11,12 @@ * Francis Lynch (Wind River) - [305718] Allow reading snapshot into renamed project * Baltasar Belyavsky (Texas Instruments) - [361675] Order mismatch when saving/restoring workspace trees * Broadcom Corporation - ongoing development + * Sergey Prigogin (Google) - [437005] Out-of-date .snap file prevents Eclipse from running *******************************************************************************/ package org.eclipse.core.internal.resources; import java.io.*; +import java.io.File; import java.net.URI; import java.util.*; import java.util.zip.*; @@ -264,7 +266,7 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool */ protected void collapseTrees(Map<String, SaveContext> contexts) throws CoreException { //collect trees we're interested in - + //forget saved trees, if they are not used by registered participants synchronized (savedStates) { for (Iterator<SaveContext> i = contexts.values().iterator(); i.hasNext();) { @@ -484,24 +486,33 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool /** * Initializes the snapshot mechanism for this workspace. */ - protected void initSnap(IProgressMonitor monitor) throws CoreException { - //discard any pending snapshot request + protected void initSnap(IProgressMonitor monitor) { + // Discard any pending snapshot request. snapshotJob.cancel(); - //the "lastSnap" tree must be frozen as the exact tree obtained from startup, - // otherwise ensuing snapshot deltas may be based on an incorrect tree (see bug 12575) + // The "lastSnap" tree must be frozen as the exact tree obtained from startup, + // otherwise ensuing snapshot deltas may be based on an incorrect tree (see bug 12575). lastSnap = workspace.getElementTree(); lastSnap.immutable(); workspace.newWorkingTree(); operationCount = 0; - // delete the snapshot file, if any - IPath snapPath = workspace.getMetaArea().getSnapshotLocationFor(workspace.getRoot()); - java.io.File file = snapPath.toFile(); - if (file.exists()) - file.delete(); - if (file.exists()) { - String message = Messages.resources_snapInit; - throw new ResourceException(IResourceStatus.FAILED_DELETE_METADATA, null, message, null); - } + // Delete the snapshot files, if any. + IPath location = workspace.getMetaArea().getSnapshotLocationFor(workspace.getRoot()); + java.io.File target = location.toFile().getParentFile(); + FilenameFilter filter = new FilenameFilter() { + public boolean accept(java.io.File dir, String name) { + if (!name.endsWith(LocalMetaArea.F_SNAP)) + return false; + for (int i = 0; i < name.length() - LocalMetaArea.F_SNAP.length(); i++) { + char c = name.charAt(i); + if (c < '0' || c > '9') + return false; + } + return true; + } + }; + String[] candidates = target.list(filter); + if (candidates != null) + removeFiles(target, candidates, Collections.<String> emptyList()); } protected boolean isDeltaCleared(String pluginId) { @@ -757,8 +768,7 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool * and <code>false</code> 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 { + protected boolean restoreFromRefreshSnapshot(Project project, IProgressMonitor monitor) throws CoreException { boolean status = true; IPath snapshotPath = workspace.getMetaArea().getRefreshLocationFor(project); java.io.File snapshotFile = snapshotPath.toFile(); @@ -770,8 +780,7 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool monitor = Policy.monitorFor(monitor); try { monitor.beginTask("", 40); //$NON-NLS-1$ - status = restoreTreeFromRefreshSnapshot(project, - snapshotFile, Policy.subMonitorFor(monitor, 40)); + status = restoreTreeFromRefreshSnapshot(project, snapshotFile, Policy.subMonitorFor(monitor, 40)); if (status) { // load the project description and set internal description ProjectDescription description = workspace.getFileSystemManager().read(project, true); @@ -917,11 +926,18 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool IPath snapLocation = workspace.getMetaArea().getSnapshotLocationFor(workspace.getRoot()); java.io.File localFile = snapLocation.toFile(); - // If the snapshot file doesn't exist, there was no crash. - // Just initialize the snapshot file and return. if (!localFile.exists()) { - initSnap(Policy.subMonitorFor(monitor, Policy.totalWork / 2)); - return; + // The snapshot corresponding to the current tree version doesn't exist. + // Try the legacy non-versioned snapshot, but ignore it if it is older than + // the tree. + snapLocation = workspace.getMetaArea().getLegacySnapshotLocationFor(workspace.getRoot()); + localFile = snapLocation.toFile(); + if (!localFile.exists() || isSnapshotOlderThanTree(localFile)) { + // If the snapshot file doesn't exist, there was no crash. + // Just initialize the snapshot file and return. + initSnap(Policy.subMonitorFor(monitor, Policy.totalWork / 2)); + return; + } } // If we have a snapshot file, the workspace was shutdown without being saved or crashed. workspace.setCrashed(true); @@ -954,6 +970,25 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool } /** + * Checks if the given snapshot file is older than the tree file. + * + * @param snapshot the snapshot file to check + * @return {@code true} if the snapshot file is older than the tree file or the tree file + * does not exist + */ + private boolean isSnapshotOlderThanTree(File snapshot) { + IPath treeLocation = workspace.getMetaArea().getTreeLocationFor(workspace.getRoot(), false); + File tree = treeLocation.toFile(); + if (!tree.exists()) { + treeLocation = workspace.getMetaArea().getBackupLocationFor(treeLocation); + tree = treeLocation.toFile(); + if (!tree.exists()) + return false; + } + return snapshot.lastModified() < tree.lastModified(); + } + + /** * Reads the sync info which was originally saved * for the tree rooted by the given resource. */ @@ -1048,14 +1083,13 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool } return true; } - + /** * Restores a tree saved as a refresh snapshot to a specified URI. * @return <code>true</code> if the snapshot exists, <code>false</code> otherwise. * @exception CoreException if the project could not be restored. */ - protected boolean restoreTreeFromRefreshSnapshot(Project project, - java.io.File snapshotFile, IProgressMonitor monitor) throws CoreException { + protected boolean restoreTreeFromRefreshSnapshot(Project project, java.io.File snapshotFile, IProgressMonitor monitor) throws CoreException { long start = System.currentTimeMillis(); monitor = Policy.monitorFor(monitor); String message; @@ -1089,18 +1123,18 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool } return true; } - - class InternalMonitorWrapper extends ProgressMonitorWrapper{ + + class InternalMonitorWrapper extends ProgressMonitorWrapper { private boolean ignoreCancel; - - public InternalMonitorWrapper(IProgressMonitor monitor){ + + public InternalMonitorWrapper(IProgressMonitor monitor) { super(Policy.monitorFor(monitor)); } public void ignoreCancelState(boolean ignore) { this.ignoreCancel = ignore; } - + public boolean isCanceled() { return ignoreCancel ? false : super.isCanceled(); } @@ -1156,7 +1190,7 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool monitor.ignoreCancelState(false); workspace.getFileSystemManager().getHistoryStore().clean(Policy.subMonitorFor(monitor, 1)); monitor.ignoreCancelState(keepConsistencyWhenCanceled); - + // write out all metainfo (e.g., workspace/project descriptions) saveMetaInfo(warnings, Policy.subMonitorFor(monitor, 1)); break; @@ -1291,16 +1325,14 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool * @param monitor progress monitor * @exception CoreException if there is a problem writing the snapshot. */ - public void saveRefreshSnapshot(Project project, URI snapshotLocation, - IProgressMonitor monitor) throws CoreException { + public void saveRefreshSnapshot(Project project, URI snapshotLocation, IProgressMonitor monitor) throws CoreException { IFileStore store = EFS.getStore(snapshotLocation); IPath snapshotPath = new Path(snapshotLocation.getPath()); java.io.File tmpTree = null; try { - tmpTree = java.io.File.createTempFile("tmp", ".tree"); //$NON-NLS-1$//$NON-NLS-2$ + tmpTree = java.io.File.createTempFile("tmp", ".tree"); //$NON-NLS-1$//$NON-NLS-2$ } catch (IOException e) { - throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, - snapshotPath, Messages.resources_copyProblem, e); + throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, snapshotPath, Messages.resources_copyProblem, e); } ZipOutputStream out = null; try { @@ -1335,10 +1367,11 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, snapshotPath, Messages.resources_copyProblem, e); } finally { FileUtil.safeClose(out); - if (tmpTree!=null) tmpTree.delete(); + if (tmpTree != null) + tmpTree.delete(); } } - + /** * Writes the current state of the entire workspace tree to disk. * This is used during workspace save. saveTree(Project) @@ -1946,7 +1979,7 @@ public class SaveManager implements IElementInfoFlattener, IManager, IStringPool // Builder infos of non-active configurations are persisted after the active // configuration's builder infos. So, their trees have to follow the same order. trees.addAll(additionalTrees); - + // add the current tree in the list as the last tree in the chain trees.add(current); |
