Preparing for merging
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketIndex.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketIndex.java index 083a01f..301a36f 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketIndex.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/BucketIndex.java
@@ -21,18 +21,29 @@ public class BucketIndex { + /** + * A entry in the bucket index. Each entry has one file path and a collection + * of states, which by their turn contain a (UUID, timestamp) pair. + */ public static final class Entry { - public final static int LONG_LENGTH = 8; - public final static int UUID_LENGTH = UniversalUniqueIdentifier.BYTES_SIZE; - public final static int DATA_LENGTH = UUID_LENGTH + LONG_LENGTH; + // the length of a long in bytes + private final static int LONG_LENGTH = 8; + // the length of a UUID in bytes + private final static int UUID_LENGTH = UniversalUniqueIdentifier.BYTES_SIZE; + public final static int DATA_LENGTH = UUID_LENGTH + LONG_LENGTH; byte[][] data; IPath path; + /** + * Returns the byte array representation of a (UUID, timestamp) pair. + */ public static byte[] getDataAsByteArray(byte[] uuid, long timestamp) { byte[] item = new byte[DATA_LENGTH]; System.arraycopy(uuid, 0, item, 0, uuid.length); - for (int j = 0; j < LONG_LENGTH; j++) - item[UUID_LENGTH + j] = (byte) (0xFF & (timestamp >>> (j * 8))); + for (int j = 0; j < LONG_LENGTH; j++) { + item[UUID_LENGTH + j] = (byte) (0xFF & timestamp); + timestamp >>>= 8; + } return item; } @@ -47,7 +58,7 @@ return new UniversalUniqueIdentifier(item); } - Entry(IPath path, byte[][] data) { + public Entry(IPath path, byte[][] data) { this.path = path; this.data = data; } @@ -111,29 +122,46 @@ public boolean isEmpty() { return data == null || data.length == 0; } + + public void sortStates() { + sortStates(this.data); + } + public static void sortStates(byte[][] data) { + Arrays.sort(data, new Comparator() { + // sort in inverse order + public int compare(Object o1, Object o2) { + byte[] state1 = (byte[]) o1; + byte[] state2 = (byte[]) o2; + long timestamp1 = getTimestamp(state1); + long timestamp2 = getTimestamp(state2); + if (timestamp1 == timestamp2) + return -UniversalUniqueIdentifier.compareTime(state1, state2); + return timestamp1 < timestamp2 ? +1 : -1; + } + }); + } } public abstract static interface Visitor { - - // should stop the traversal + // should continue the traversal public final static int CONTINUE = 0; // should delete this entry (can be combined with the other constants except for UPDATE) public final static int DELETE = 0x100; // should stop looking at states for files in this container (or any of its children) public final static int RETURN = 2; - // keep visiting, still happy + // should stop the traversal public final static int STOP = 1; // should update this entry (can be combined with the other constants except for DELETE) public final static int UPDATE = 0x200; /** - * @return either STOP, CONTINUE or RETURN and optionally DELETE + * @return either STOP, CONTINUE or RETURN and optionally DELETE or UPDATE */ public int visit(Entry entry); } - private static final String BUCKET = ".bucket"; //$NON-NLS-1$ + private static final String BUCKET = "bucket.index"; //$NON-NLS-1$ public final static byte VERSION = 1; @@ -175,7 +203,7 @@ * @return one of STOP, RETURN or CONTINUE constants * @throws CoreException */ - public int accept(Visitor visitor, IPath filter, boolean exactMatch, boolean sorted) throws CoreException { + public int accept(Visitor visitor, IPath filter, boolean exactMatch) throws CoreException { if (entries.isEmpty()) return Visitor.CONTINUE; try { @@ -187,6 +215,7 @@ continue; // calls the visitor passing all uuids for the entry final Entry fileEntry = new Entry(path, (byte[][]) entry.getValue()); + fileEntry.sortStates(); int outcome = visitor.visit(fileEntry); if ((outcome & Visitor.UPDATE) != 0) { needSaving = true; @@ -228,7 +257,6 @@ byte[][] newValue = new byte[existing.length + 1][]; System.arraycopy(existing, 0, newValue, 0, existing.length); newValue[newValue.length - 1] = item; - sortUUIDs(newValue); entries.put(pathAsString, newValue); needSaving = true; } @@ -279,7 +307,6 @@ byte[][] existing = (byte[][]) entries.get(pathAsString); if (existing == null) return new Entry(path, null); - sortUUIDs(existing); return new Entry(path, existing); } @@ -290,6 +317,7 @@ public void load(File baseLocation) throws CoreException { load(baseLocation, false); } + public void load(File baseLocation, boolean force) throws CoreException { try { // avoid reloading @@ -362,15 +390,7 @@ } } - private void sortUUIDs(byte[][] uuids) { - Arrays.sort(uuids, new Comparator() { - public int compare(Object o1, Object o2) { - return -UniversalUniqueIdentifier.compareTime((byte[]) o1, (byte[]) o2); - } - }); - } - public int getEntryCount() { - return entries.size(); + return entries.size(); } }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java index 8fed670..a11a301 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java
@@ -150,18 +150,19 @@ /** * Factory method for creating history stores. */ - private static IHistoryStore createHistoryStore(Workspace workspace, IPath location, int limit) { - if (Boolean.getBoolean(ENABLE_NEW_HISTORY_STORE)) { - HistoryStore2 newHistoryStore = new HistoryStore2(workspace, location, limit); - if (Boolean.getBoolean(CONVERT_HISTORY_STORE)) { - IStatus conversionOutcome = new HistoryStoreConverter().convertHistory(workspace, location, limit, newHistoryStore, true); - if (conversionOutcome.getSeverity() != IStatus.OK) - // if either we fail or succeed, a non-OK status is returned - ResourcesPlugin.getPlugin().getLog().log(conversionOutcome); - } + private static IHistoryStore createHistoryStore(Workspace workspace, IPath location, int limit) { + if (!Boolean.getBoolean(ENABLE_NEW_HISTORY_STORE)) + // keep using the old history store + return new HistoryStore(workspace, location, limit); + HistoryStore2 newHistoryStore = new HistoryStore2(workspace, location, limit); + if (!Boolean.getBoolean(CONVERT_HISTORY_STORE)) + // do not try to convert - return as it is return newHistoryStore; - } - return new HistoryStore(workspace, location, limit); + IStatus result = new HistoryStoreConverter().convertHistory(workspace, location, limit, newHistoryStore, true); + if (result.getSeverity() != IStatus.OK) + // if we do anything (either we fail or succeed converting), a non-OK status is returned + ResourcesPlugin.getPlugin().getLog().log(result); + return newHistoryStore; } public void delete(IResource target, boolean force, boolean convertToPhantom, boolean keepHistory, IProgressMonitor monitor) throws CoreException {
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 15a294b..b44bbeb 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
@@ -400,7 +400,7 @@ } return blobStore.getBlob(((FileState) target).getUUID()); } - + /** * @see IHistoryStore#getStates(IPath, IProgressMonitor) */
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 b1eef9f..d1b23e4 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
@@ -38,17 +38,13 @@ this.currentBucket = createBucketTable(); } - public void accept(Visitor visitor, IPath root, int depth) throws CoreException { - accept(visitor, root, depth, false); - } - /** * From a starting point in the tree, visit all nodes under it. * @param visitor * @param root * @param depth */ - public void accept(Visitor visitor, IPath root, int depth, boolean sorted) throws CoreException { + public void accept(Visitor visitor, IPath root, int depth) throws CoreException { // we only do anything for the root if depth == infinite if (root.isRoot()) { if (depth != IResource.DEPTH_INFINITE) @@ -60,7 +56,7 @@ return; for (int i = 0; i < projects.length; i++) if (projects[i].isDirectory()) - if (!internalAccept(visitor, root.append(projects[i].getName()), projects[i], IResource.DEPTH_INFINITE, sorted)) + if (!internalAccept(visitor, root.append(projects[i].getName()), projects[i], IResource.DEPTH_INFINITE)) break; // done return; @@ -68,10 +64,10 @@ // handles the case the starting point is a file path if (root.segmentCount() > 1) { currentBucket.load(locationFor(root.removeLastSegments(1))); - if (currentBucket.accept(visitor, root, true, sorted) != Visitor.CONTINUE || depth == IResource.DEPTH_ZERO) + if (currentBucket.accept(visitor, root, true) != Visitor.CONTINUE || depth == IResource.DEPTH_ZERO) return; } - internalAccept(visitor, root, locationFor(root), depth, sorted); + internalAccept(visitor, root, locationFor(root), depth); } /** @@ -135,7 +131,7 @@ } return changed ? UPDATE : CONTINUE; } - }, root, IResource.DEPTH_INFINITE, true); + }, root, IResource.DEPTH_INFINITE); // remove unreferenced blobs blobStore.deleteBlobs(blobsToRemove); blobsToRemove = new HashSet(); @@ -266,19 +262,8 @@ states.add(new FileState(HistoryStore2.this, fileEntry.getPath(), fileEntry.getTimestamp(i), fileEntry.getUUID(i))); return CONTINUE; } - }, filePath, IResource.DEPTH_ZERO, true); - IFileState[] result = (IFileState[]) states.toArray(new IFileState[states.size()]); - // sort states based on modification time + uuid - Arrays.sort(result, new Comparator() { - public int compare(Object o1, Object o2) { - FileState fs1 = (FileState) o1; - FileState fs2 = (FileState) o2; - if (fs1.getModificationTime() == fs1.getModificationTime()) - return -UniversalUniqueIdentifier.compareTime(fs1.getUUID(), fs2.getUUID()); - return (fs1.getModificationTime() < fs2.getModificationTime()) ? 1 : -1; - } - }); - return result; + }, filePath, IResource.DEPTH_ZERO); + return (IFileState[]) states.toArray(new IFileState[states.size()]); } catch (CoreException ce) { ResourcesPlugin.getPlugin().getLog().log(ce.getStatus()); return new IFileState[0]; @@ -289,9 +274,9 @@ * * @return whether to continue visiting other branches */ - private boolean internalAccept(Visitor visitor, IPath root, File bucketDir, int depth, boolean sorted) throws CoreException { + private boolean internalAccept(Visitor visitor, IPath root, File bucketDir, int depth) throws CoreException { currentBucket.load(bucketDir); - int outcome = currentBucket.accept(visitor, root, depth == IResource.DEPTH_ZERO, sorted); + int outcome = currentBucket.accept(visitor, root, depth == IResource.DEPTH_ZERO); if (outcome != Visitor.CONTINUE) return outcome == Visitor.RETURN; // nothing else to be done @@ -302,7 +287,7 @@ return true; for (int i = 0; i < subDirs.length; i++) if (subDirs[i].isDirectory()) - if (!internalAccept(visitor, root, subDirs[i], IResource.DEPTH_INFINITE, sorted)) + if (!internalAccept(visitor, root, subDirs[i], IResource.DEPTH_INFINITE)) return false; return true; }
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 4048e3e..56badac 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
@@ -18,8 +18,6 @@ import org.eclipse.core.runtime.*; public class HistoryStoreConverter { - private static final String BACKUP_FILE_EXTENSION = "bak"; //$NON-NLS-1$ - /** * Converts an existing history store lying on disk to the new history store. * Returns Status.OK_STATUS if nothing is done, an IStatus.INFO status if
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/Policy.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/Policy.java index 26a02a5..f2b65bd 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/Policy.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/Policy.java
@@ -53,7 +53,6 @@ public static boolean DEBUG_SAVE_SYNCINFO = false; public static boolean DEBUG_SAVE_TREE = false; public static boolean DEBUG_SAVE_METAINFO = false; - public static boolean DEBUG_SAVE_SNAPSHOTS = false; public static boolean DEBUG_SAVE_MASTERTABLE = false; public static boolean DEBUG_AUTO_REFRESH = false; @@ -85,7 +84,6 @@ DEBUG_SAVE_SYNCINFO = sTrue.equalsIgnoreCase(Platform.getDebugOption(ResourcesPlugin.PI_RESOURCES + "/save/syncinfo")); //$NON-NLS-1$ DEBUG_SAVE_TREE = sTrue.equalsIgnoreCase(Platform.getDebugOption(ResourcesPlugin.PI_RESOURCES + "/save/tree")); //$NON-NLS-1$ DEBUG_SAVE_METAINFO = sTrue.equalsIgnoreCase(Platform.getDebugOption(ResourcesPlugin.PI_RESOURCES + "/save/metainfo")); //$NON-NLS-1$ - DEBUG_SAVE_SNAPSHOTS = sTrue.equalsIgnoreCase(Platform.getDebugOption(ResourcesPlugin.PI_RESOURCES + "/save/snapshots")); //$NON-NLS-1$ DEBUG_SAVE_MASTERTABLE = sTrue.equalsIgnoreCase(Platform.getDebugOption(ResourcesPlugin.PI_RESOURCES + "/save/mastertable")); //$NON-NLS-1$ DEBUG_SAVE = sTrue.equalsIgnoreCase(Platform.getDebugOption(ResourcesPlugin.PI_RESOURCES + "/save")); //$NON-NLS-1$
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/UniversalUniqueIdentifier.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/UniversalUniqueIdentifier.java index a484496..7299722 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/UniversalUniqueIdentifier.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/UniversalUniqueIdentifier.java
@@ -100,15 +100,10 @@ @see #BYTES_SIZE */ public UniversalUniqueIdentifier(byte[] byteValue) { - this(byteValue, 0); - } - - public UniversalUniqueIdentifier(byte[] byteValue, int start) { fBits = new byte[BYTES_SIZE]; - if (byteValue.length - start >= BYTES_SIZE) - System.arraycopy(byteValue, start, fBits, 0, fBits.length); + if (byteValue.length >= BYTES_SIZE) + System.arraycopy(byteValue, 0, fBits, 0, BYTES_SIZE); } - /** Construct an instance whose internal representation is defined by the given string. @@ -123,7 +118,7 @@ // Check to ensure it is a String of the right length. // do not use Assert to avoid having to call Policy.bind ahead of time if (string.length() != PrintStringSize) - throw new IllegalArgumentException(Policy.bind("utils.wrongLength", string)); //$NON-NLS-1$ + Assert.isTrue(false, Policy.bind("utils.wrongLength", string)); //$NON-NLS-1$ char[] newChars = string.toCharArray(); @@ -174,6 +169,22 @@ } /** + * Compares the time component of two UUIDs. + * + * @see Comparable#compareTo(java.lang.Object) + */ + public int compareTime(UniversalUniqueIdentifier other) { + return compareTime(this.fBits, other.fBits); + } + + public static int compareTime(byte[] fBits1, byte[] fBits2) { + for (int i = TIME_FIELD_STOP; i >= 0; i--) + if (fBits1[i] != fBits2[i]) + return (0xFF & fBits1[i]) - (0xFF & fBits2[i]); + return 0; + } + + /** * Answers the node address attempting to mask the IP * address of this machine. * @@ -460,64 +471,4 @@ } return result + "}"; //$NON-NLS-1$ } - -// public static void main(String[] args) throws Exception { -// StringWriter writer = new StringWriter(2000); -// PrintWriter pw = new PrintWriter(writer); -// int j = 0; -// while (true) { -// j++; -// UniversalUniqueIdentifier uuid = new UniversalUniqueIdentifier(); -// byte[] bytes = uuid.toBytes(); -// for (int i = 0; i < 6; i++) { -// pw.print(Integer.toHexString(bytes[i] & 0xFF)); -// pw.print(" "); -// } -// pw.print(Integer.toHexString(bytes[7] & HIGH_NIBBLE_MASK)); -// pw.print(" -- "); -// pw.println(uuid); -// if (j % 80 == 0) { -// pw.flush(); -// System.out.println(writer.getBuffer()); -// writer.getBuffer().setLength(0); -// } -// } -// } - - public static void main(String[] args) throws Exception { - int i = 0; - UniversalUniqueIdentifier last = new UniversalUniqueIdentifier(); - while (true) { - i++; - UniversalUniqueIdentifier current = new UniversalUniqueIdentifier(); - if (compareTime(last, current) >= 0) { - System.out.println("Broke comparison at " + i); - System.out.println(last); - System.out.println(current); - break; - } -// -// if (current.toBytes()[0] == last.toBytes()[0]) { -// System.out.println("Collision at " + i); -// System.out.println(last); -// System.out.println(current); -// break; -// } - last = current; - } - } - - public static int compareTime(UniversalUniqueIdentifier uuid1, UniversalUniqueIdentifier uuid2) { - return compareTime(uuid1.fBits, uuid2.fBits); - } - public static int compareTime(byte[] fBits1, byte[] fBits2) { - for (int i = TIME_FIELD_STOP; i >= 0; i--) - if (fBits1[i] != fBits2[i]) - return (0xFF & fBits1[i]) - (0xFF & fBits2[i]); - return 0; - } - public static int compareTime(String uuid1, String uuid2) { - // TODO this must be more efficient - return compareTime(new UniversalUniqueIdentifier(uuid1), new UniversalUniqueIdentifier(uuid2)); - } } \ No newline at end of file