Fixed bug 81793 (in branch) - improving the property store
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/Bucket.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/Bucket.java index 3b19c0e..189f6c5 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/Bucket.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/Bucket.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at @@ -112,20 +112,27 @@ // should stop the traversal public final static int STOP = 1; - /** - * @return either STOP, CONTINUE or RETURN - */ - public abstract int visit(Entry entry); - /** * Called after the bucket has been visited (and saved). */ public void afterSaving(Bucket bucket) throws CoreException { // empty implementation, subclasses to override } + + public void beforeSaving(Bucket bucket) throws CoreException { + // empty implementation, subclasses to override + } + + /** + * @return either STOP, CONTINUE or RETURN + */ + public abstract int visit(Entry entry); } - private static final String BUCKET = "bucket.index"; //$NON-NLS-1$ + /** + * The file extension for bucket index files. + */ + private static final String INDEX_FILE_EXT = ".index"; //$NON-NLS-1$ /** * Map of the history entries in this bucket. Maps (String -> byte[][]), @@ -141,14 +148,12 @@ * Whether the in-memory bucket is dirty and needs saving */ private boolean needSaving = false; - /** - * The root directory of the bucket indexes on disk. + * The project name for the bucket currently loaded. <code>null</code> if this is the root bucket. */ - private File root; + protected String projectName; - public Bucket(File root) { - this.root = root; + public Bucket() { this.entries = new HashMap(); } @@ -189,29 +194,27 @@ } return Visitor.CONTINUE; } finally { + visitor.beforeSaving(this); save(); visitor.afterSaving(this); } } /** + * Tries to delete as many empty levels as possible. + */ + private void cleanUp(File toDelete) { + if (toDelete.delete()) + // if deletion went fine, try deleting the parent dir + cleanUp(toDelete.getParentFile()); + } + + /** * Factory method for creating entries. Subclasses to override. */ protected abstract Entry createEntry(IPath path, Object value); /** - * Tries to delete as many empty levels as possible. - */ - private void delete(File toDelete) { - // don't try to delete beyond the root for bucket indexes - if (toDelete.equals(root)) - return; - if (toDelete.delete()) - // if deletion went fine, try deleting the parent dir - delete(toDelete.getParentFile()); - } - - /** * Returns how many entries there are in this bucket. */ public final int getEntryCount() { @@ -226,6 +229,11 @@ } /** + * Returns the file name to be used to persist instances of this Bucket implementation. + */ + protected abstract String getFileName(); + + /** * Returns the directory where this bucket should be stored. */ public File getLocation() { @@ -240,8 +248,8 @@ /** * Loads the contents from a file under the given directory. */ - public final void load(File baseLocation) throws CoreException { - load(baseLocation, false); + public void load(String newProjectName, File baseLocation) throws CoreException { + load(newProjectName, baseLocation, false); } /** @@ -249,14 +257,17 @@ * <code>false</code>, if this bucket already contains the contents from the current location, * avoids reloading. */ - public final void load(File baseLocation, boolean force) throws CoreException { + public void load(String newProjectName, File baseLocation, boolean force) throws CoreException { try { // avoid reloading - if (!force && this.location != null && baseLocation.equals(this.location.getParentFile())) + if (!force && this.location != null && baseLocation.equals(this.location.getParentFile()) && (projectName == null ? (newProjectName == null) : projectName.equals(newProjectName))) { + this.projectName = newProjectName; return; + } // previously loaded bucket may not have been saved... save before loading new one save(); - this.location = new File(baseLocation, BUCKET); + this.projectName = newProjectName; + this.location = new File(baseLocation, getFileName() + INDEX_FILE_EXT); this.entries.clear(); if (!this.location.isFile()) return; @@ -271,7 +282,7 @@ } int entryCount = source.readInt(); for (int i = 0; i < entryCount; i++) - this.entries.put(source.readUTF(), readEntryValue(source)); + this.entries.put(readEntryKey(source), readEntryValue(source)); } finally { source.close(); } @@ -282,21 +293,27 @@ } } + private String readEntryKey(DataInputStream source) throws IOException { + if (projectName == null) + return source.readUTF(); + return IPath.SEPARATOR + projectName + source.readUTF(); + } + /** * Defines how data for a given entry is to be read from a bucket file. To be implemented by subclasses. */ - protected abstract Object readEntryValue(DataInputStream source) throws IOException; + protected abstract Object readEntryValue(DataInputStream source) throws IOException, CoreException; /** * Saves this bucket's contents back to its location. */ - public final void save() throws CoreException { + public void save() throws CoreException { if (!needSaving) return; try { if (entries.isEmpty()) { needSaving = false; - delete(location); + cleanUp(location); return; } // ensure the parent location exists @@ -307,7 +324,7 @@ destination.writeInt(entries.size()); for (Iterator i = entries.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); - destination.writeUTF((String) entry.getKey()); + writeEntryKey(destination, (String) entry.getKey()); writeEntryValue(destination, entry.getValue()); } } finally { @@ -333,8 +350,20 @@ needSaving = true; } + private void writeEntryKey(DataOutputStream destination, String path) throws IOException { + if (projectName == null) { + destination.writeUTF(path); + return; + } + // omit the project name + int pathLength = path.length(); + int projectLength = projectName.length(); + String key = (pathLength == projectLength + 1) ? "" : path.substring(projectLength + 1); //$NON-NLS-1$ + destination.writeUTF(key); + } + /** * Defines how an entry is to be persisted to the bucket file. */ - protected abstract void writeEntryValue(DataOutputStream destination, Object entryValue) throws IOException; + protected abstract void writeEntryValue(DataOutputStream destination, Object entryValue) throws IOException, CoreException; }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketTree.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketTree.java index 101de6b..88efd2b 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketTree.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketTree.java
@@ -13,12 +13,14 @@ import java.io.*; import org.eclipse.core.internal.localstore.Bucket.Visitor; import org.eclipse.core.internal.resources.ResourceException; +import org.eclipse.core.internal.resources.Workspace; import org.eclipse.core.internal.utils.Policy; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.runtime.*; public class BucketTree { - + private static final String INDEXES_DIR_NAME = ".indexes"; //$NON-NLS-1$ public static final int DEPTH_INFINITE = Integer.MAX_VALUE; public static final int DEPTH_ONE = 1; public static final int DEPTH_ZERO = 0; @@ -26,25 +28,50 @@ private final static int SEGMENT_LENGTH = 2; private final static long SEGMENT_QUOTA = (long) Math.pow(2, 4 * SEGMENT_LENGTH); // 1 char = 2 ^ 4 = 0x10 - public final static String VERSION_FILE = "version"; //$NON-NLS-1$ + private static final String VERSION_FILE_EXT = ".version"; //$NON-NLS-1$ - private Bucket current; + protected Bucket current; - private File rootLocation; + private Workspace workspace; - public BucketTree(File rootLocation, Bucket bucket) { - this.rootLocation = rootLocation; + public BucketTree(Workspace workspace, Bucket bucket) { this.current = bucket; + this.workspace = workspace; } /** * From a starting point in the tree, visit all nodes under it. * @param visitor - * @param root + * @param base * @param depth */ - public void accept(Bucket.Visitor visitor, IPath root, int depth) throws CoreException { - internalAccept(visitor, root, locationFor(root), depth, 0); + public void accept(Bucket.Visitor visitor, IPath base, int depth) throws CoreException { + if (Path.ROOT.equals(base)) { + current.load(null, locationFor(Path.ROOT)); + if (current.accept(visitor, base, DEPTH_ZERO) != Visitor.CONTINUE) + return; + if (depth == DEPTH_ZERO) + return; + boolean keepVisiting = true; + depth--; + IProject[] projects = workspace.getRoot().getProjects(); + for (int i = 0; keepVisiting && i < projects.length; i++) { + IPath projectPath = projects[i].getFullPath(); + keepVisiting = internalAccept(visitor, projectPath, locationFor(projectPath), depth, 1); + } + } else + internalAccept(visitor, base, locationFor(base), depth, 0); + } + + public void cleanUp(File toDelete) { + if (!toDelete.delete()) + // if deletion didn't go well, don't bother trying to delete the parent dir + return; + // don't try to delete beyond the root for bucket indexes + if (toDelete.getName().equals(INDEXES_DIR_NAME)) + return; + // recurse to parent directory + cleanUp(toDelete.getParentFile()); } public void close() throws CoreException { @@ -57,57 +84,58 @@ } public File getVersionFile() { - return new File(this.rootLocation, VERSION_FILE); + return new File(locationFor(Path.ROOT), current.getFileName() + VERSION_FILE_EXT); } /** + * This will never be called for a bucket for the workspace root. + * * @return whether to continue visiting other branches */ - private boolean internalAccept(Bucket.Visitor visitor, IPath root, File bucketDir, int depthRequested, int currentDepth) throws CoreException { - current.load(bucketDir); - int outcome = current.accept(visitor, root, depthRequested); + private boolean internalAccept(Bucket.Visitor visitor, IPath base, File bucketDir, int depthRequested, int currentDepth) throws CoreException { + current.load(base.segment(0), bucketDir); + int outcome = current.accept(visitor, base, depthRequested); if (outcome != Visitor.CONTINUE) return outcome == Visitor.RETURN; - if (depthRequested == currentDepth) + if (depthRequested <= currentDepth) return true; File[] subDirs = bucketDir.listFiles(); if (subDirs == null) return true; for (int i = 0; i < subDirs.length; i++) if (subDirs[i].isDirectory()) - if (!internalAccept(visitor, root, subDirs[i], depthRequested, currentDepth + 1)) + if (!internalAccept(visitor, base, subDirs[i], depthRequested, currentDepth + 1)) return false; return true; } public void loadBucketFor(IPath path) throws CoreException { - current.load(locationFor(path)); + current.load(Path.ROOT.equals(path) ? null : path.segment(0), locationFor(path)); } public File locationFor(IPath resourcePath) { + IPath baseLocation = workspace.getMetaArea().locationFor(resourcePath); int segmentCount = resourcePath.segmentCount(); - // the root - if (segmentCount == 0) - return rootLocation; - // a project - if (segmentCount == 1) - return new File(rootLocation, resourcePath.segment(0)); + baseLocation = baseLocation.append(INDEXES_DIR_NAME); + // the root or a project + if (segmentCount <= 1) + return baseLocation.toFile(); // a folder or file - IPath location = new Path(resourcePath.segment(0)); + IPath location = baseLocation; // the last segment is ignored for (int i = 1; i < segmentCount - 1; i++) // translate all segments except the first one (project name) location = location.append(translateSegment(resourcePath.segment(i))); - return new File(rootLocation, location.toOSString()); + return location.toFile(); } /** * Writes the version tag to a file on disk. */ - private void saveVersion() throws CoreException { - if (!this.rootLocation.isDirectory()) - return; + private void saveVersion() throws CoreException { File versionFile = getVersionFile(); + if (!versionFile.getParentFile().exists()) + versionFile.getParentFile().mkdirs(); FileOutputStream stream = null; boolean failed = false; try { @@ -130,7 +158,7 @@ } } - private String translateSegment(String segment) { + protected String translateSegment(String segment) { // String.hashCode algorithm is API return Long.toHexString(Math.abs(segment.hashCode()) % SEGMENT_QUOTA); }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/CopyVisitor.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/CopyVisitor.java index f162050..ad65408 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/CopyVisitor.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/CopyVisitor.java
@@ -90,7 +90,7 @@ getWorkspace().getAliasManager().updateAliases(destination, destinationLocation, IResource.DEPTH_ZERO, monitor); // update file attributes CoreFileSystemLibrary.copyAttributes(node.getLocalLocation(), destinationLocation.toOSString(), false); - destination.getLocalManager().getHistoryStore().copyHistory(source, destination); + destination.getLocalManager().getHistoryStore().copyHistory(source, destination, false); } catch (CoreException e) { status.add(e.getStatus()); }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryBucket.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryBucket.java index b39ba92..8afdb0a 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryBucket.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryBucket.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at @@ -18,6 +18,7 @@ public class HistoryBucket extends Bucket { + private static final String HISTORY_FILE_NAME = "history"; //$NON-NLS-1$ /** * A entry in the bucket index. Each entry has one path and a collection * of states, which by their turn contain a (UUID, timestamp) pair. @@ -233,8 +234,8 @@ */ public final static byte VERSION = 1; - public HistoryBucket(File root) { - super(root); + public HistoryBucket() { + super(); } public void addBlob(IPath path, UniversalUniqueIdentifier uuid, long lastModified) { @@ -274,6 +275,10 @@ return null; return new HistoryEntry(path, existing); } + + protected String getFileName() { + return HISTORY_FILE_NAME; + } protected byte getVersion() { return VERSION;
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore.java index b44bbeb..5b28a68 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore.java
@@ -283,7 +283,7 @@ * @see IHistoryStore#copyHistory(IPath, IPath) * @since 2.1 */ - public void copyHistory(final IResource sourceResource, final IResource destinationResource) { + public void copyHistory(final IResource sourceResource, final IResource destinationResource, boolean moving) { // Note that if any states in the local history for destination // have the same timestamp as a state for the local history // for source, the local history for destination will appear
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore2.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore2.java index 19ad805..e7704c1 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore2.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStore2.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at @@ -33,17 +33,18 @@ } public void afterSaving(Bucket bucket) throws CoreException { - saveChanges((HistoryBucket) bucket); + saveChanges(); changes.clear(); } - private void saveChanges(HistoryBucket bucket) throws CoreException { + private void saveChanges() throws CoreException { if (changes.isEmpty()) return; // make effective all changes collected Iterator i = changes.iterator(); HistoryEntry entry = (HistoryEntry) i.next(); - bucket.load(tree.locationFor(entry.getPath())); + tree.loadBucketFor(entry.getPath()); + HistoryBucket bucket = (HistoryBucket) tree.getCurrent(); bucket.addBlobs(entry); while (i.hasNext()) bucket.addBlobs((HistoryEntry) i.next()); @@ -60,10 +61,44 @@ } } + class HistoryMoveVisitor extends Bucket.Visitor { + private List changes = new ArrayList(); + private IPath destination; + private IPath source; + + public HistoryMoveVisitor(IPath source, IPath destination) { + this.source = source; + this.destination = destination; + } + + private void applyChanges(HistoryBucket bucket) { + if (changes.isEmpty()) + return; + + for (Iterator i = changes.iterator(); i.hasNext();) + bucket.addBlobs((HistoryEntry) i.next()); + } + + public void beforeSaving(Bucket bucket) { + applyChanges((HistoryBucket) bucket); + changes.clear(); + } + + public int visit(Entry sourceEntry) { + IPath destinationPath = destination.append(sourceEntry.getPath().removeFirstSegments(source.segmentCount())); + HistoryEntry destinationEntry = new HistoryEntry(destinationPath, (HistoryEntry) sourceEntry); + // we may be copying to the same source bucket, collect to make change effective later + // since we cannot make changes to it while iterating + changes.add(destinationEntry); + // delete original entry + sourceEntry.delete(); + return CONTINUE; + } + } + private static final String INDEX_STORE = ".buckets"; //$NON-NLS-1$ private BlobStore blobStore; private Set blobsToRemove = new HashSet(); - private File indexLocation; private BucketTree tree; private Workspace workspace; @@ -71,8 +106,7 @@ this.workspace = workspace; location.toFile().mkdirs(); this.blobStore = new BlobStore(location, limit); - this.indexLocation = location.append(INDEX_STORE).toFile(); - this.tree = new BucketTree(indexLocation, createBucketTable()); + this.tree = new BucketTree(workspace, new HistoryBucket()); } /** @@ -86,9 +120,8 @@ UniversalUniqueIdentifier uuid = null; try { uuid = blobStore.addBlob(localFile, moveContents); - File bucketDir = tree.locationFor(key); + tree.loadBucketFor(key); HistoryBucket currentBucket = (HistoryBucket) tree.getCurrent(); - currentBucket.load(bucketDir); currentBucket.addBlob(key, uuid, lastModified); currentBucket.save(); } catch (CoreException e) { @@ -173,7 +206,7 @@ } } - public void copyHistory(IResource sourceResource, IResource destinationResource) { + public void copyHistory(IResource sourceResource, IResource destinationResource, boolean moving) { // return early if either of the paths are null or if the source and // destination are the same. if (sourceResource == null || destinationResource == null) { @@ -195,6 +228,11 @@ Assert.isLegal(destination.segmentCount() > 0); Assert.isLegal(source.segmentCount() > 1 || destination.segmentCount() == 1); + // special case: we are moving a project + if (moving && sourceResource.getType() == IResource.PROJECT) + // nothing to be done! + return; + try { // copy history by visiting the source tree HistoryCopyVisitor copyVisitor = new HistoryCopyVisitor(source, destination); @@ -206,10 +244,6 @@ } } - HistoryBucket createBucketTable() { - return new HistoryBucket(indexLocation); - } - public boolean exists(IFileState target) { return blobStore.fileFor(((FileState) target).getUUID()).exists(); } @@ -227,10 +261,9 @@ } public IFileState[] getStates(IPath filePath, IProgressMonitor monitor) { - File bucketDir = tree.locationFor(filePath); try { + tree.loadBucketFor(filePath); HistoryBucket currentBucket = (HistoryBucket) tree.getCurrent(); - currentBucket.load(bucketDir); HistoryEntry fileEntry = currentBucket.getEntry(filePath); if (fileEntry == null || fileEntry.isEmpty()) return new IFileState[0];
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStoreConverter.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStoreConverter.java index aafe4e2..7584821 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStoreConverter.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/HistoryStoreConverter.java
@@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.core.internal.localstore; +import java.io.*; +import org.eclipse.core.internal.resources.ResourceStatus; import org.eclipse.core.internal.resources.Workspace; import org.eclipse.core.internal.utils.Policy; import org.eclipse.core.resources.IResourceStatus; @@ -23,11 +25,21 @@ * the conversion happens successfully or an IStatus.ERROR status if an error * happened during the conversion process. */ - public IStatus convertHistory(Workspace workspace, IPath location, int limit, final HistoryStore2 destination, boolean rename) { - IPath indexFile = location.append(HistoryStore.INDEX_FILE); - if (!indexFile.toFile().isFile()) + public IStatus convertHistory(Workspace workspace, IPath location, int limit, final HistoryStore2 destination, boolean rename) { + if (!location.toFile().isDirectory()) // nothing to be converted - return Status.OK_STATUS; + return Status.OK_STATUS; + IPath indexFile = location.append(HistoryStore.INDEX_FILE); + if (!indexFile.toFile().isFile()) { + IPath newIndexDir = location.append(".buckets"); + if (!newIndexDir.toFile().isDirectory()) + // nothing to be converted + return Status.OK_STATUS; + MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IStatus.INFO, Policy.bind("history.conversionTransitional"), null); //$NON-NLS-1$ + convertFromTransitionalFormat(status, newIndexDir.toFile(), destination); + Workspace.clear(newIndexDir.toFile()); + return status; + } // visit all existing entries and add them to the new history store long start = System.currentTimeMillis(); final CoreException[] exception = new CoreException[1]; @@ -74,4 +86,55 @@ // leave a note to the user so this does not happen silently return new Status(IStatus.INFO, ResourcesPlugin.PI_RESOURCES, IStatus.OK, conversionOk, null); } + + /** + * Converts from the format used during the M4 cycle. + * TODO remove this before 3.1 release + * @param destination + */ + private void convertFromTransitionalFormat(MultiStatus status, java.io.File root, HistoryStore2 destination) { + File[] subdirs = root.listFiles(); + if (subdirs == null) + return; + for (int i = 0; i < subdirs.length; i++) + if (subdirs[i].isDirectory()) + convertFromTransitionalFormat(status, subdirs[i], destination); + File bucketFile = new File(root, "bucket.index"); + if (!bucketFile.isFile()) + return; + final BucketTree tree = destination.getTree(); + final HistoryBucket currentBucket = (HistoryBucket) tree.getCurrent(); + DataInputStream source = null; + try { + source = new DataInputStream(new BufferedInputStream(new FileInputStream(bucketFile), 8192)); + // don't do any checking + source.readByte(); + int entryCount = source.readInt(); + for (int i = 0; i < entryCount; i++) { + String path = source.readUTF(); + tree.loadBucketFor(new Path(path)); + int numberOfStates = source.readUnsignedShort(); + byte[][] states = new byte[numberOfStates][HistoryBucket.HistoryEntry.DATA_LENGTH]; + for (int j = 0; j < numberOfStates; j++) + source.read(states[j]); + HistoryBucket.HistoryEntry entry = new HistoryBucket.HistoryEntry(new Path(path), states); + for (int j = 0; j < entry.getOccurrences(); j++) + currentBucket.addBlob(entry.getPath(), entry.getUUID(j), entry.getTimestamp(j)); + } + tree.getCurrent().save(); + } catch (IOException ioe) { + String msg = ioe.getLocalizedMessage(); + Throwable exception = Platform.inDebugMode() ? ioe : null; + status.add(new ResourceStatus(IStatus.WARNING, IResourceStatus.FAILED_READ_METADATA, new Path(bucketFile.getAbsolutePath()), msg, exception)); + } catch (CoreException ce) { + status.add(ce.getStatus()); + } finally { + if (source != null) + try { + source.close(); + } catch (IOException ioe) { + // we are just closing a stream opened for read, no data can be lost... + } + } + } } \ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/IHistoryStore.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/IHistoryStore.java index 07855a7..1dfe2bb 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/IHistoryStore.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/IHistoryStore.java
@@ -100,10 +100,11 @@ * * @param source the resource containing the original copy of the history store information * @param destination the target resource where to copy the history + * @param moving whether the history is being copied due to a resource move * * TODO: should this method take a progress monitor? */ - public void copyHistory(IResource source, IResource destination); + public void copyHistory(IResource source, IResource destination, boolean moving); /** * Verifies existence of specified resource in the history store. Returns
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/IPropertyManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/IPropertyManager.java index 1e6156e..7b21c3e 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/IPropertyManager.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/IPropertyManager.java
@@ -50,7 +50,7 @@ public void setProperty(IResource target, QualifiedName key, String value) throws CoreException; /** - * Returns a map (<propertyKey: Strting -> value: String>) containing + * Returns a map (<propertyKey: QualifiedName -> value: String>) containing * all properties defined for the given resource. In case no properties can * be found, returns an empty map. */
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyBucket.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyBucket.java index c8b1e0b..202fea2 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyBucket.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyBucket.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at @@ -11,22 +11,28 @@ package org.eclipse.core.internal.properties; import java.io.*; -import java.util.Arrays; -import java.util.Comparator; +import java.util.*; import org.eclipse.core.internal.localstore.Bucket; +import org.eclipse.core.internal.resources.ResourceException; +import org.eclipse.core.internal.utils.Policy; +import org.eclipse.core.resources.IResourceStatus; +import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.QualifiedName; public class PropertyBucket extends Bucket { - public static class PropertyEntry extends Entry { private final static Comparator COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { - return ((String[]) o1)[0].compareTo(((String[]) o2)[0]); + int qualifierComparison = ((String[]) o1)[0].compareTo(((String[]) o2)[0]); + return qualifierComparison != 0 ? qualifierComparison : ((String[]) o1)[1].compareTo(((String[]) o2)[1]); } }; private static final String[][] EMPTY_DATA = new String[0][]; + /** + * value is a String[][] of {{propertyKey.qualifier, propertyKey.localName, propertyValue}} + */ private String[][] value; /** @@ -34,10 +40,10 @@ * array if the property to be deleted could not be found. Returns <code>null</code> if the property was found * and the original array had size 1 (instead of a zero-length array). */ - public static String[][] delete(String[][] existing, String propertyName) { + private static String[][] delete(String[][] existing, QualifiedName propertyName) { // a size-1 array is a special case if (existing.length == 1) - return (existing[0][0].equals(propertyName)) ? null : existing; + return (existing[0][0].equals(propertyName.getQualifier()) && existing[0][1].equals(propertyName.getLocalName())) ? null : existing; // find the guy to delete int deletePosition = search(existing, propertyName); if (deletePosition < 0) @@ -53,12 +59,12 @@ return newValue; } - public static String[][] insert(String[][] existing, String propertyName, String propertyValue) { + private static String[][] insert(String[][] existing, QualifiedName propertyName, String propertyValue) { // look for the right spot where to insert the new guy int index = search(existing, propertyName); if (index >= 0) { // found existing occurrence - just replace the value - existing[index][1] = propertyValue; + existing[index][2] = propertyValue; return existing; } // not found - insert @@ -66,7 +72,7 @@ String[][] newValue = new String[existing.length + 1][]; if (insertPosition > 0) System.arraycopy(existing, 0, newValue, 0, insertPosition); - newValue[insertPosition] = new String[] {propertyName, propertyValue}; + newValue[insertPosition] = new String[] {propertyName.getQualifier(), propertyName.getLocalName(), propertyValue}; if (insertPosition < existing.length) System.arraycopy(existing, insertPosition, newValue, insertPosition + 1, existing.length - insertPosition); return newValue; @@ -75,13 +81,13 @@ /** * Merges two entries (are always sorted). Duplicated additions replace existing ones. */ - static Object merge(String[][] base, String[][] additions) { + private static Object merge(String[][] base, String[][] additions) { int additionPointer = 0; int basePointer = 0; int added = 0; String[][] result = new String[base.length + additions.length][]; while (basePointer < base.length && additionPointer < additions.length) { - int comparison = base[basePointer][0].compareTo(additions[additionPointer][0]); + int comparison = COMPARATOR.compare(base[basePointer], additions[additionPointer]); if (comparison == 0) { result[added++] = additions[additionPointer++]; // duplicate, override @@ -106,8 +112,8 @@ return finalResult; } - private static int search(String[][] existing, String propertyName) { - return Arrays.binarySearch(existing, new String[] {propertyName, null}, COMPARATOR); + private static int search(String[][] existing, QualifiedName propertyName) { + return Arrays.binarySearch(existing, new String[] {propertyName.getQualifier(), propertyName.getLocalName(), null}, COMPARATOR); } public PropertyEntry(IPath path, PropertyEntry base) { @@ -129,7 +135,7 @@ * Compacts the data array removing any null slots. If non-null slots * are found, the entry is marked for removal. */ - void compact() { + private void compact() { if (!isDirty()) return; int occurrences = 0; @@ -155,16 +161,16 @@ } public String getProperty(QualifiedName name) { - int index = search(value, name.toString()); - return index < 0 ? null : value[index][1]; + int index = search(value, name); + return index < 0 ? null : value[index][2]; } public Object getPropertyName(int i) { - return this.value[i][0]; + return new QualifiedName(this.value[i][0], this.value[i][1]); } public Object getPropertyValue(int i) { - return this.value[i][1]; + return this.value[i][2]; } public Object getValue() { @@ -176,6 +182,11 @@ } } + public static final byte INDEX = 1; + + private static final String PROPERTIES_FILE_NAME = "properties"; //$NON-NLS-1$ + public static final byte QNAME = 2; + /** Version number for the current implementation file's format. * <p> * Version 1: @@ -193,8 +204,10 @@ */ private static final byte VERSION = 1; - public PropertyBucket(File root) { - super(root); + private List qualifierIndex = new ArrayList(); + + public PropertyBucket() { + super(); } protected Entry createEntry(IPath path, Object value) { @@ -209,6 +222,10 @@ return new PropertyEntry(path, existing); } + protected String getFileName() { + return PROPERTIES_FILE_NAME; + } + public String getProperty(IPath path, QualifiedName name) { PropertyEntry entry = getEntry(path); if (entry == null) @@ -220,16 +237,44 @@ return VERSION; } - protected Object readEntryValue(DataInputStream source) throws IOException { + public void load(String newProjectName, File baseLocation, boolean force) throws CoreException { + qualifierIndex = new ArrayList(5); + super.load(newProjectName, baseLocation, force); + } + + protected Object readEntryValue(DataInputStream source) throws IOException, CoreException { int length = source.readUnsignedShort(); - String[][] properties = new String[length][2]; + String[][] properties = new String[length][3]; for (int j = 0; j < properties.length; j++) { - properties[j][0] = source.readUTF(); + // qualifier + byte constant = source.readByte(); + switch (constant) { + case QNAME : + properties[j][0] = source.readUTF(); + qualifierIndex.add(properties[j][0]); + break; + case INDEX : + properties[j][0] = (String) qualifierIndex.get(source.readInt()); + break; + default : + //if we get here the properties file is corrupt + IPath resourcePath = projectName == null ? Path.ROOT : Path.ROOT.append(projectName); + String msg = Policy.bind("properties.readProperties", resourcePath.toString()); //$NON-NLS-1$ + throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, null, msg, null); + } + // localName properties[j][1] = source.readUTF(); + // propertyValue + properties[j][2] = source.readUTF(); } return properties; } + public void save() throws CoreException { + qualifierIndex = new ArrayList(5); + super.save(); + } + public void setProperties(PropertyEntry entry) { IPath path = entry.getPath(); String[][] additions = (String[][]) entry.getValue(); @@ -244,18 +289,17 @@ public void setProperty(IPath path, QualifiedName name, String value) { String pathAsString = path.toString(); - String nameAsString = name.toString(); String[][] existing = (String[][]) getEntryValue(pathAsString); if (existing == null) { if (value != null) - setEntryValue(pathAsString, new String[][] { {nameAsString, value}}); + setEntryValue(pathAsString, new String[][] { {name.getQualifier(), name.getLocalName(), value}}); return; } String[][] newValue; if (value != null) - newValue = PropertyEntry.insert(existing, nameAsString, value); + newValue = PropertyEntry.insert(existing, name, value); else - newValue = PropertyEntry.delete(existing, nameAsString); + newValue = PropertyEntry.delete(existing, name); // even if newValue == existing we should mark as dirty (insert may not create a new array) setEntryValue(pathAsString, newValue); } @@ -264,10 +308,20 @@ String[][] properties = (String[][]) entryValue; destination.writeShort(properties.length); for (int j = 0; j < properties.length; j++) { - // writes the property key - destination.writeUTF(properties[j][0]); - // then the property value + // writes the property key qualifier + int index = qualifierIndex.indexOf(properties[j][0]); + if (index == -1) { + destination.writeByte(QNAME); + destination.writeUTF(properties[j][0]); + qualifierIndex.add(properties[j][0]); + } else { + destination.writeByte(INDEX); + destination.writeInt(index); + } + // then the local name destination.writeUTF(properties[j][1]); + // then the property value + destination.writeUTF(properties[j][2]); } } -} +} \ No newline at end of file
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java index 0175010..07edf14 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager.java
@@ -295,7 +295,7 @@ Map properties = new HashMap(); for (int i = 0; i < listSize; i++) { StoredProperty prop = (StoredProperty) projectProperties.get(i); - properties.put(prop.getName().toString(), prop.getStringValue()); + properties.put(prop.getName(), prop.getStringValue()); } return properties; }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager2.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager2.java index a25f652..a30bbc3 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager2.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyManager2.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at @@ -12,8 +12,7 @@ import java.io.File; import java.util.*; -import org.eclipse.core.internal.localstore.Bucket; -import org.eclipse.core.internal.localstore.BucketTree; +import org.eclipse.core.internal.localstore.*; import org.eclipse.core.internal.localstore.Bucket.Entry; import org.eclipse.core.internal.properties.PropertyBucket.PropertyEntry; import org.eclipse.core.internal.resources.ResourceException; @@ -46,7 +45,7 @@ // make effective all changes collected Iterator i = changes.iterator(); PropertyEntry entry = (PropertyEntry) i.next(); - bucket.load(tree.locationFor(entry.getPath())); + tree.loadBucketFor(entry.getPath()); bucket.setProperties(entry); while (i.hasNext()) bucket.setProperties((PropertyEntry) i.next()); @@ -62,14 +61,10 @@ } } - private File baseLocation; - private BucketTree tree; public PropertyManager2(Workspace workspace) { - baseLocation = workspace.getMetaArea().getPropertyStoreLocation().toFile(); - baseLocation.mkdirs(); - this.tree = new BucketTree(baseLocation, createPropertyIndex()); + this.tree = new BucketTree(workspace, new PropertyBucket()); } public void closePropertyStore(IResource target) throws CoreException { @@ -93,10 +88,6 @@ tree.accept(copyVisitor, source, BucketTree.DEPTH_INFINITE); } - private PropertyBucket createPropertyIndex() { - return new PropertyBucket(baseLocation); - } - public synchronized void deleteProperties(IResource target, int depth) throws CoreException { tree.accept(new PropertyBucket.Visitor() { public int visit(Entry entry) { @@ -127,8 +118,7 @@ public synchronized String getProperty(IResource target, QualifiedName name) throws CoreException { IPath resourcePath = target.getFullPath(); PropertyBucket current = (PropertyBucket) tree.getCurrent(); - File indexDir = tree.locationFor(resourcePath); - current.load(indexDir); + tree.loadBucketFor(resourcePath); return current.getProperty(resourcePath, name); } @@ -147,9 +137,8 @@ throw new ResourceException(IResourceStatus.FAILED_WRITE_METADATA, target.getFullPath(), message, null); } IPath resourcePath = target.getFullPath(); - PropertyBucket current = (PropertyBucket) tree.getCurrent(); - File indexDir = tree.locationFor(resourcePath); - current.load(indexDir); + tree.loadBucketFor(resourcePath); + PropertyBucket current = (PropertyBucket) tree.getCurrent(); current.setProperty(resourcePath, name, value); current.save(); }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyStoreConverter.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyStoreConverter.java index f09c24f..be7e85d 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyStoreConverter.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/properties/PropertyStoreConverter.java
@@ -56,7 +56,7 @@ */ public IStatus convertProperties(Workspace workspace, final PropertyManager2 destination) { // Quickly check whether should try converting persistent properties - // We cannot pay the cost of checking very project so, instead, we try to find + // We cannot pay the cost of checking every project so, instead, we try to find // a single file used by the new implementation File versionFile = destination.getVersionFile(); if (versionFile.isFile())
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 bcabf23..b441e7d 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
@@ -208,6 +208,16 @@ public boolean hasSavedWorkspace() { return getLocation().toFile().exists() || getBackupLocationFor(getLocation()).toFile().exists(); } + + /** + * Returns the local filesystem location in which the meta data for the + * resource with the given path is stored. + */ + public IPath locationFor(IPath resourcePath) { + if (Path.ROOT.equals(resourcePath)) + return getLocation().append(F_ROOT); + return getLocation().append(F_PROJECTS).append(resourcePath.segment(0)); + } /** * Returns the local filesystem location in which the meta data for the
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceTree.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceTree.java index 8eda21d..9f99585 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceTree.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceTree.java
@@ -83,7 +83,7 @@ * associated IFile under destination. */ private void copyLocalHistory(IResource source, IResource destination) { - ((Resource) destination).getLocalManager().getHistoryStore().copyHistory(source, destination); + ((Resource) destination).getLocalManager().getHistoryStore().copyHistory(source, destination, true); } /**
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties index 85d77ea..066e3ba 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/messages.properties
@@ -383,8 +383,9 @@ ### history store -history.conversionFailed = Conversion of local history failed. -history.conversionSucceeded = Conversion of local history completed successfully. +history.conversionTransitional = Conversion of transitional local history performed. +history.conversionFailed = Conversion of local history completed. +history.conversionSucceeded = Conversion of local history completed successfully. history.corrupt = The history store got corrupted. Local history is lost. A new store is being created. history.couldNotAdd = Could not add history for {0}. history.errorContentDescription = Error retrieving content description for local history for: {0}. @@ -422,11 +423,13 @@ properties.couldNotReadProp = Could not read property: {0} {1}. properties.couldNotWriteProp = Could not write property: {0} {1}. properties.invalidPropName = Invalid property name: {0} {1}. +properties.readProperties = Failure while reading persistent properties for resource {0}, file was corrupt. Some properties may be lost. properties.storeNotAvailable = Property store is not available for: {0}. properties.storeProblem = Problems accessing property store. properties.couldNotClose = Could not close property store for: {0}. properties.valueTooLong = Property value is too long. + ### preferences preferences.noProject=Cannot calculate project name for preference node: {0}. preferences.noFile=Cannot determine location of preferences file for node: {0}.
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/BucketTreeTests.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/BucketTreeTests.java index d6ce68d..4b95089 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/BucketTreeTests.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/BucketTreeTests.java
@@ -16,6 +16,10 @@ import junit.framework.TestSuite; import org.eclipse.core.internal.localstore.Bucket; import org.eclipse.core.internal.localstore.BucketTree; +import org.eclipse.core.internal.resources.Workspace; +import org.eclipse.core.resources.*; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.*; import org.eclipse.core.tests.resources.ResourceTest; @@ -44,8 +48,12 @@ } } - public SimpleBucket(File root) { - super(root); + public SimpleBucket() { + super(); + } + + protected String getFileName() { + return "simple_bucket.index"; } protected Entry createEntry(IPath path, Object value) { @@ -112,14 +120,15 @@ IPath baseLocation = getRandomLocation(); try { // keep the reference around - it is the same returned by tree.getCurrent() - SimpleBucket bucket = new SimpleBucket(baseLocation.toFile()); - BucketTree tree = new BucketTree(baseLocation.toFile(), bucket); - IPath proj1 = new Path("/proj1"); - IPath proj2 = new Path("/proj2"); - IPath file1 = proj1.append("file1.txt"); - IPath folder1 = proj1.append("folder1"); - IPath file2 = folder1.append("file2.txt"); - IPath[] paths = {Path.ROOT, proj1, file1, folder1, file2, proj2}; + SimpleBucket bucket = new SimpleBucket(); + BucketTree tree = new BucketTree((Workspace) getWorkspace(), bucket); + IProject proj1 = getWorkspace().getRoot().getProject("proj1"); + IProject proj2 = getWorkspace().getRoot().getProject("proj2"); + IFile file1 = proj1.getFile("file1.txt"); + IFolder folder1 = proj1.getFolder("folder1"); + IFile file2 = folder1.getFile("file2.txt"); + ensureExistsInWorkspace(new IResource[] {file1, file2, proj2}, true); + IPath[] paths = {Path.ROOT, proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath(), file2.getFullPath(), proj2.getFullPath()}; for (int i = 0; i < paths.length; i++) { try { tree.loadBucketFor(paths[i]); @@ -135,23 +144,23 @@ fail("0.2", e); } verify(tree, "1.1", Path.ROOT, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {Path.ROOT})); - verify(tree, "1.2", Path.ROOT, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {Path.ROOT, proj1, proj2})); - verify(tree, "1.3", Path.ROOT, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {Path.ROOT, proj1, file1, folder1, file2, proj2})); - verify(tree, "2.1", proj1, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {proj1})); - verify(tree, "2.2", proj1, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {proj1, file1, folder1})); - verify(tree, "2.3", proj1, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {proj1, file1, folder1, file2})); - verify(tree, "3.1", file1, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {file1})); - verify(tree, "3.2", file1, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {file1})); - verify(tree, "3.3", file1, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {file1})); - verify(tree, "4.1", folder1, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {folder1})); - verify(tree, "4.2", folder1, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {folder1, file2})); - verify(tree, "4.3", folder1, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {folder1, file2})); - verify(tree, "5.1", file2, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {file2})); - verify(tree, "5.2", file2, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {file2})); - verify(tree, "5.3", file2, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {file2})); - verify(tree, "6.1", proj2, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {proj2})); - verify(tree, "6.2", proj2, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {proj2})); - verify(tree, "6.3", proj2, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {proj2})); + verify(tree, "1.2", Path.ROOT, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {Path.ROOT, proj1.getFullPath(), proj2.getFullPath()})); + verify(tree, "1.3", Path.ROOT, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {Path.ROOT, proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath(), file2.getFullPath(), proj2.getFullPath()})); + verify(tree, "2.1", proj1.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {proj1.getFullPath()})); + verify(tree, "2.2", proj1.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath()})); + verify(tree, "2.3", proj1.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath(), file2.getFullPath()})); + verify(tree, "3.1", file1.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {file1.getFullPath()})); + verify(tree, "3.2", file1.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {file1.getFullPath()})); + verify(tree, "3.3", file1.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {file1.getFullPath()})); + verify(tree, "4.1", folder1.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {folder1.getFullPath()})); + verify(tree, "4.2", folder1.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {folder1.getFullPath(), file2.getFullPath()})); + verify(tree, "4.3", folder1.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {folder1.getFullPath(), file2.getFullPath()})); + verify(tree, "5.1", file2.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {file2.getFullPath()})); + verify(tree, "5.2", file2.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {file2.getFullPath()})); + verify(tree, "5.3", file2.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {file2.getFullPath()})); + verify(tree, "6.1", proj2.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {proj2.getFullPath()})); + verify(tree, "6.2", proj2.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {proj2.getFullPath()})); + verify(tree, "6.3", proj2.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {proj2.getFullPath()})); } finally { ensureDoesNotExistInFileSystem(baseLocation.toFile());
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryBucketTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryBucketTest.java index fcdf61a..f18a42d 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryBucketTest.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryBucketTest.java
@@ -35,10 +35,10 @@ public void testDuplicates() { IPath baseLocation = getRandomLocation(); try { - HistoryBucket index1 = new HistoryBucket(baseLocation.toFile()); + HistoryBucket index1 = new HistoryBucket(); IPath location1 = baseLocation.append("location1"); try { - index1.load(location1.toFile()); + index1.load("foo", location1.toFile()); } catch (CoreException e) { fail("1.0", e); } @@ -63,10 +63,10 @@ public void testPersistence() { IPath baseLocation = getRandomLocation(); try { - HistoryBucket index1 = new HistoryBucket(baseLocation.toFile()); + HistoryBucket index1 = new HistoryBucket(); IPath location = baseLocation.append("location"); try { - index1.load(location.toFile()); + index1.load("foo", location.toFile()); } catch (CoreException e) { fail("1.0", e); } @@ -81,9 +81,9 @@ } catch (CoreException e) { fail("2.1", e); } - HistoryBucket index2 = new HistoryBucket(baseLocation.toFile()); + HistoryBucket index2 = new HistoryBucket(); try { - index2.load(location.toFile(), false); + index2.load("foo", location.toFile(), false); } catch (CoreException e) { fail("3.0", e); } @@ -103,7 +103,7 @@ fail("4.0", e); } try { - index1.load(location.toFile(), true); + index1.load("foo", location.toFile(), true); } catch (CoreException e) { fail("4.1", e); } @@ -127,7 +127,7 @@ entry = index1.getEntry(path); assertNull("5.1", entry); try { - index2.load(location.toFile(), true); + index2.load("foo", location.toFile(), true); } catch (CoreException e) { fail("5.2", e); } @@ -138,49 +138,47 @@ } } + /** + * This test does not cause any data to be written. + */ public void testSort() { - IPath baseLocation = getRandomLocation(); - try { - HistoryBucket index = new HistoryBucket(baseLocation.toFile()); - IPath path = new Path("/foo"); - assertNull("1.0", index.getEntry(path)); - UniversalUniqueIdentifier uuid1 = new UniversalUniqueIdentifier(); - long timestamp1 = 10; - index.addBlob(path, uuid1, timestamp1); - HistoryBucket.HistoryEntry entry = index.getEntry(path); - assertNotNull("2.0", entry); - assertEquals("2.1", 1, entry.getOccurrences()); - assertEquals("2.2", uuid1, entry.getUUID(0)); - assertEquals("2.3", timestamp1, entry.getTimestamp(0)); - // adds a new state with a more recent timestamp - UniversalUniqueIdentifier uuid2 = new UniversalUniqueIdentifier(); - long timestamp2 = timestamp1 + 1; - index.addBlob(path, uuid2, timestamp2); - entry = index.getEntry(path); - assertNotNull("3.0", entry); - // since it is newer, should appear first - assertEquals("3.1", 2, entry.getOccurrences()); - assertEquals("3.2", uuid2, entry.getUUID(0)); - assertEquals("3.3", timestamp2, entry.getTimestamp(0)); - assertEquals("3.4", uuid1, entry.getUUID(1)); - assertEquals("3.5", timestamp1, entry.getTimestamp(1)); - // adds a 3rd state, with the same timestamp as the 1st - UniversalUniqueIdentifier uuid3 = new UniversalUniqueIdentifier(); - long timestamp3 = timestamp1; - index.addBlob(path, uuid3, timestamp3); - entry = index.getEntry(path); - assertNotNull("4.0", entry); - // its UUID was created later so it will be considered more recent - // even if it has the same timestamp - assertEquals("4.1", 3, entry.getOccurrences()); - assertEquals("4.2", uuid2, entry.getUUID(0)); - assertEquals("4.3", timestamp2, entry.getTimestamp(0)); - assertEquals("4.4", uuid3, entry.getUUID(1)); - assertEquals("4.5", timestamp3, entry.getTimestamp(1)); - assertEquals("4.6", uuid1, entry.getUUID(2)); - assertEquals("4.7", timestamp1, entry.getTimestamp(2)); - } finally { - ensureDoesNotExistInFileSystem(baseLocation.toFile()); - } + HistoryBucket index = new HistoryBucket(); + IPath path = new Path("/foo"); + assertNull("1.0", index.getEntry(path)); + UniversalUniqueIdentifier uuid1 = new UniversalUniqueIdentifier(); + long timestamp1 = 10; + index.addBlob(path, uuid1, timestamp1); + HistoryBucket.HistoryEntry entry = index.getEntry(path); + assertNotNull("2.0", entry); + assertEquals("2.1", 1, entry.getOccurrences()); + assertEquals("2.2", uuid1, entry.getUUID(0)); + assertEquals("2.3", timestamp1, entry.getTimestamp(0)); + // adds a new state with a more recent timestamp + UniversalUniqueIdentifier uuid2 = new UniversalUniqueIdentifier(); + long timestamp2 = timestamp1 + 1; + index.addBlob(path, uuid2, timestamp2); + entry = index.getEntry(path); + assertNotNull("3.0", entry); + // since it is newer, should appear first + assertEquals("3.1", 2, entry.getOccurrences()); + assertEquals("3.2", uuid2, entry.getUUID(0)); + assertEquals("3.3", timestamp2, entry.getTimestamp(0)); + assertEquals("3.4", uuid1, entry.getUUID(1)); + assertEquals("3.5", timestamp1, entry.getTimestamp(1)); + // adds a 3rd state, with the same timestamp as the 1st + UniversalUniqueIdentifier uuid3 = new UniversalUniqueIdentifier(); + long timestamp3 = timestamp1; + index.addBlob(path, uuid3, timestamp3); + entry = index.getEntry(path); + assertNotNull("4.0", entry); + // its UUID was created later so it will be considered more recent + // even if it has the same timestamp + assertEquals("4.1", 3, entry.getOccurrences()); + assertEquals("4.2", uuid2, entry.getUUID(0)); + assertEquals("4.3", timestamp2, entry.getTimestamp(0)); + assertEquals("4.4", uuid3, entry.getUUID(1)); + assertEquals("4.5", timestamp3, entry.getTimestamp(1)); + assertEquals("4.6", uuid1, entry.getUUID(2)); + assertEquals("4.7", timestamp1, entry.getTimestamp(2)); } }
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryStoreTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryStoreTest.java index 661c924..3d4a3a8 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryStoreTest.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/HistoryStoreTest.java
@@ -97,7 +97,11 @@ } public static Test suite() { - return new TestSuite(HistoryStoreTest.class); +// TestSuite suite = new TestSuite(HistoryStoreTest.class.getName()); +// suite.addTest(new HistoryStoreTest("testMoveProject")); +// suite.addTest(new HistoryStoreTest("testFindDeleted")); +// return suite; + return new TestSuite(HistoryStoreTest.class); } /* @@ -370,7 +374,7 @@ assertEquals("2.0", 1, states.length); // copy the data - store.copyHistory(folder, destinationFolder); + store.copyHistory(folder, destinationFolder, true); states = store.getStates(destinationFile.getFullPath(), getMonitor()); assertEquals("3.0", 1, states.length); @@ -742,7 +746,7 @@ // Test with null source and/or destination IHistoryStore store = ((Resource) file).getLocalManager().getHistoryStore(); verifier.addExpected(IResourceStatus.INTERNAL_ERROR); - store.copyHistory(null, null); + store.copyHistory(null, null, false); try { verifier.verify(); } catch (VerificationFailedException e) { @@ -751,7 +755,7 @@ verifier.reset(); verifier.addExpected(IResourceStatus.INTERNAL_ERROR); - store.copyHistory(null, file2); + store.copyHistory(null, file2, false); try { verifier.verify(); } catch (VerificationFailedException e) { @@ -760,7 +764,7 @@ verifier.reset(); verifier.addExpected(IResourceStatus.INTERNAL_ERROR); - store.copyHistory(file, null); + store.copyHistory(file, null, false); try { verifier.verify(); } catch (VerificationFailedException e) { @@ -770,7 +774,7 @@ // Try to copy the history store stuff to the same location verifier.addExpected(IResourceStatus.INTERNAL_ERROR); - store.copyHistory(file, file); + store.copyHistory(file, file, false); try { verifier.verify(); } catch (VerificationFailedException e) { @@ -783,7 +787,7 @@ log.removeLogListener(verifier); // Test a valid copy of a file - store.copyHistory(file, file2); + store.copyHistory(file, file2, false); IFileState[] states = null; try { states = file2.getHistory(getMonitor()); @@ -844,7 +848,7 @@ // Test a valid copy of a folder IHistoryStore store = ((Resource) file).getLocalManager().getHistoryStore(); - store.copyHistory(folder, folder2); + store.copyHistory(folder, folder2, false); IFileState[] states = null; try { states = file2.getHistory(getMonitor()); @@ -906,7 +910,7 @@ // Test a valid copy of a folder IHistoryStore store = ((Resource) file).getLocalManager().getHistoryStore(); - store.copyHistory(project, project2); + store.copyHistory(project, project2, false); IFileState[] states = null; try { states = file2.getHistory(getMonitor()); @@ -1611,9 +1615,9 @@ // Check the local history of both files states = file.getHistory(getMonitor()); - assertEquals("2.0", 2, states.length); - assertTrue("2.1", compareContent(getContents(contents[1]), states[0].getContents())); - assertTrue("2.2", compareContent(getContents(contents[0]), states[1].getContents())); + + // original file should not remember history when project is moved + assertEquals("2.0", 0, states.length); states = file2.getHistory(getMonitor()); assertEquals("2.3", 4, states.length); assertTrue("2.4", compareContent(getContents(contents[3]), states[0].getContents()));
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyConversionTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyConversionTest.java index de5ee77..92daaf2 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyConversionTest.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyConversionTest.java
@@ -45,7 +45,7 @@ Map otherProperties = another.getProperties(resource); assertEquals(tag + ".1 - " + resource.getFullPath(), baseProperties.size(), otherProperties.size()); for (Iterator i = baseProperties.keySet().iterator(); i.hasNext();) { - String propertyKey = (String) i.next(); + QualifiedName propertyKey = (QualifiedName) i.next(); assertEquals(tag + ".2 - " + resource.getFullPath(), baseProperties.get(propertyKey), otherProperties.get(propertyKey)); } return true;
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyManagerTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyManagerTest.java index 1a093e4..a021cbd 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyManagerTest.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/properties/PropertyManagerTest.java
@@ -32,7 +32,7 @@ public static Test suite() { // TestSuite suite = new TestSuite(); -// suite.addTest(new PropertyManagerTest("testProperties")); +// suite.addTest(new PropertyManagerTest("testDeleteProperties")); // return suite; return new TestSuite(PropertyManagerTest.class); }
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/PropertyManagerPerformanceTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/PropertyManagerPerformanceTest.java index 7ea0f84..5911c28 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/PropertyManagerPerformanceTest.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/perf/PropertyManagerPerformanceTest.java
@@ -41,7 +41,7 @@ } /** - * Creates a tree of resources containing history. + * Creates a tree of resources. */ private List createTree(IFolder base, int filesPerFolder) { IFolder[] folders = new IFolder[5]; @@ -72,7 +72,7 @@ IResource resource = (IResource) i.next(); for (int j = 0; j < properties; j++) try { - resource.setPersistentProperty(new QualifiedName("qualifier", "prop" + j), getPropertyValue(200)); + resource.setPersistentProperty(new QualifiedName(PI_RESOURCES_TESTS, "prop" + j), getPropertyValue(200)); } catch (CoreException ce) { fail("0.2", ce); } @@ -84,7 +84,7 @@ for (Iterator i = allResources.iterator(); i.hasNext();) { IResource resource = (IResource) i.next(); try { - assertNotNull(resource.getPersistentProperty(new QualifiedName("qualifier", "prop" + j))); + assertNotNull(resource.getPersistentProperty(new QualifiedName(PI_RESOURCES_TESTS, "prop" + j))); } catch (CoreException ce) { fail("0.2", ce); } @@ -129,7 +129,7 @@ for (Iterator i = allResources.iterator(); i.hasNext();) { IResource resource = (IResource) i.next(); try { - resource.setPersistentProperty(new QualifiedName("qualifier", "prop" + ((int) Math.random() * 50)), getPropertyValue(2048)); + resource.setPersistentProperty(new QualifiedName(PI_RESOURCES_TESTS, "prop" + ((int) Math.random() * 50)), getPropertyValue(200)); } catch (CoreException ce) { fail("0.2", ce); }