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);
 					}