From 8cb8bc26a955976914e10938b76ea258666d316d Mon Sep 17 00:00:00 2001 From: Michael Valenta Date: Fri, 13 Dec 2002 15:50:14 +0000 Subject: Backed out of space optimizations due to time cost --- .../internal/ccvs/core/resources/EclipseFile.java | 4 +- .../ccvs/core/resources/EclipseFolder.java | 46 +- .../core/resources/EclipsePhantomSynchronizer.java | 638 ++++++++++++++++ .../ccvs/core/resources/EclipseResource.java | 26 +- .../ccvs/core/resources/EclipseSynchronizer.java | 815 +++++++++++++-------- .../core/resources/FileModificationManager.java | 8 + .../ccvs/core/resources/LowLevelSyncInfoCache.java | 148 ---- .../resources/SessionPropertySyncInfoCache.java | 546 -------------- .../core/resources/SynchronizerSyncInfoCache.java | 478 ------------ .../ccvs/core/syncinfo/ResourceSyncInfo.java | 12 - .../internal/ccvs/core/util/MoveDeleteHook.java | 2 +- .../internal/ccvs/core/util/SyncFileWriter.java | 73 +- .../eclipse/team/internal/ccvs/core/util/Util.java | 12 - 13 files changed, 1230 insertions(+), 1578 deletions(-) create mode 100644 bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java delete mode 100644 bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java delete mode 100644 bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java delete mode 100644 bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java index 24af7d793..458784654 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java @@ -473,7 +473,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile { ((EclipseFolder)getParent()).adjustModifiedCount(false); } // make sure the file is no longer marked - EclipseSynchronizer.getInstance().flushDirtyCache(getIResource(), IResource.DEPTH_ZERO); + flushModificationCache(); return; } setModified(isModified(getSyncInfo())); @@ -546,7 +546,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile { * Flush all cached info for the file and it's ancestors */ protected void flushModificationCache() throws CVSException { - EclipseSynchronizer.getInstance().flushDirtyCache(getIFile(), IResource.DEPTH_ZERO); + EclipseSynchronizer.getInstance().flushModificationCache(getIFile()); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java index ded8328df..16e8d54ea 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java @@ -126,9 +126,8 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { * Method folderCreated. */ protected void folderCreated() throws CVSException { - // flush the dirty cache for the ancestors - String indicator = EclipseSynchronizer.getInstance().getDirtyIndicator(getIResource()); - if (indicator != null) { + Integer count = EclipseSynchronizer.getInstance().getDirtyCount((IContainer)getIResource()); + if (count != null) { flushWithAncestors(); } EclipseSynchronizer.getInstance().folderCreated((IFolder)getIResource()); @@ -219,14 +218,14 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { setSyncInfo(new ResourceSyncInfo(getName())); // if the sync info changed from null, we may need to adjust the ancestors if (oldInfo == null) { - int count = synchronizer.getDirtyCount((IContainer)getIResource()); - if (count == -1) { + Integer count = synchronizer.getDirtyCount((IContainer)getIResource()); + if (count == null) { // There was no cached count. Flush the ancestors so they are recalculated flushWithAncestors(); } else { // There is a count. Decrement the parent's count if the count is zero. // Otherwise, the receiver and it's parents remain dirty. - if (count == 0) { + if (count.intValue() == 0) { synchronizer.setDirtyIndicator(getIResource(), EclipseSynchronizer.NOT_DIRTY_INDICATOR); ((EclipseFolder)getParent()).adjustModifiedCount(false); } @@ -266,13 +265,13 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { monitor.beginTask(null, 10); monitor.subTask(container.getFullPath().toOSString()); EclipseSynchronizer.getInstance().deleteFolderSync(container); - EclipseSynchronizer.getInstance().flushDirtyCache(container, IResource.DEPTH_ZERO); + EclipseSynchronizer.getInstance().flushModificationCache(container); IResource[] members = container.members(true); for (int i = 0; i < members.length; i++) { monitor.worked(1); IResource resource = members[i]; if (members[i].getType() == IResource.FILE) { - EclipseSynchronizer.getInstance().flushDirtyCache(resource, IResource.DEPTH_ZERO); + EclipseSynchronizer.getInstance().flushModificationCache((IFile)resource); } else { recursiveUnmanage((IContainer) resource, monitor); } @@ -361,19 +360,17 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { public ICVSResource[] fetchChildren(IProgressMonitor monitor) throws CVSException { return members(FILE_MEMBERS | FOLDER_MEMBERS); } - /** * @see org.eclipse.team.internal.ccvs.core.ICVSResource#delete() */ public void delete() throws CVSException { if (!exists()) return; if (isCVSFolder()) { - // EclipseSynchronizer.getInstance().prepareForDeletion((IContainer)getIResource()); } super.delete(); } - + /** * Method adjustParentCount. * @param file @@ -390,7 +387,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { * Flush all cached info for the container and it's ancestors */ protected void flushModificationCache() throws CVSException { - EclipseSynchronizer.getInstance().flushDirtyCache(getIResource(), IResource.DEPTH_ZERO); + EclipseSynchronizer.getInstance().flushModificationCache((IContainer)getIResource()); } /* @@ -399,11 +396,8 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { */ protected void handleDeletion(IFile file, boolean modified) throws CVSException { boolean adjustParent; - int dirtyCount = EclipseSynchronizer.getInstance().getDirtyCount((IContainer)getIResource()); - if (dirtyCount == -1) { - flushWithAncestors(); - return; - } + Integer dirtyCount = EclipseSynchronizer.getInstance().getDirtyCount((IContainer)getIResource()); + if (dirtyCount == null) return; if (modified) { adjustParent = EclipseSynchronizer.getInstance().addDeletedChild((IContainer)getIResource(), file); } else { @@ -419,8 +413,8 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { // if (isIgnored()) return false; IContainer container = (IContainer)getIResource(); boolean shared = isCVSFolder(); - int count = EclipseSynchronizer.getInstance().getDirtyCount(container); - if (count == -1) { + Integer count = EclipseSynchronizer.getInstance().getDirtyCount(container); + if (count == null) { if (!exists()) return false; String indicator = EclipseSynchronizer.getInstance().getDirtyIndicator(container); if (indicator == null) { @@ -439,7 +433,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { } return EclipseSynchronizer.IS_DIRTY_INDICATOR.equals(indicator); } else { - return isModified(count, shared); + return isModified(count.intValue(), shared); } } @@ -493,6 +487,16 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { return count > 0 || !shared; } + /* + * @see org.eclipse.team.internal.ccvs.core.resources.EclipseResource#prepareToBeDeleted() + */ + protected void prepareToBeDeleted() throws CVSException { + if (isCVSFolder()) { + EclipseSynchronizer.getInstance().prepareForDeletion((IContainer)getIResource()); + } + super.prepareToBeDeleted(); + } + public void syncInfoChanged() throws CVSException { // It hard to deterime the effect of sync info for forlders so just flush the parent info String indicator = EclipseSynchronizer.getInstance().getDirtyIndicator(getIResource()); @@ -501,7 +505,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { } if (isIgnored()) { // make sure the folder (or any of it's childen are no longer marked - EclipseSynchronizer.getInstance().flushDirtyCache((IContainer)getIResource(), IResource.DEPTH_INFINITE); + EclipseSynchronizer.getInstance().flushModificationCache((IContainer)getIResource(), IResource.DEPTH_INFINITE); } } } \ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java new file mode 100644 index 000000000..0c2fd5ff8 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java @@ -0,0 +1,638 @@ +/******************************************************************************* + * Copyright (c) 2002 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM - Initial API and implementation + ******************************************************************************/ +package org.eclipse.team.internal.ccvs.core.resources; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ISynchronizer; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; +import org.eclipse.team.internal.ccvs.core.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.ICVSResource; +import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; + +/** + * Wraps the CVS EclipseSynchronizer with phantoms for folder deletions. + */ +public class EclipsePhantomSynchronizer extends EclipseSynchronizer { + + private static final QualifiedName FOLDER_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync"); //$NON-NLS-1$ + private static final QualifiedName RESOURCE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync"); //$NON-NLS-1$ + + private Set changedResources = new HashSet(); + + EclipsePhantomSynchronizer() { + // Add the sync keys to the workspace synchronizer which is used to handle folder deletions + getWorkspaceSynchronizer().add(FOLDER_SYNC_KEY); + getWorkspaceSynchronizer().add(RESOURCE_SYNC_KEY); + getWorkspaceSynchronizer().add(DIRTY_COUNT); + } + + /** + * Gets the folder sync info for the specified folder. + * + * @param folder the folder + * @return the folder sync info associated with the folder, or null if none. + * @see #setFolderSync, #deleteFolderSync + */ + public FolderSyncInfo getFolderSync(IContainer container) throws CVSException{ + if (container.isPhantom()) { + return getPhantomFolderSyncInfo(container); + } + return super.getFolderSync(container); + } + + /** + * @see EclipseSynchronizer#setFolderSync(IContainer, FolderSyncInfo) + */ + public void setFolderSync(IContainer container, FolderSyncInfo info) throws CVSException { + if (container.isPhantom()) { + try { + beginOperation(null); + changedResources.add(container); + try { + getWorkspaceSynchronizer().setSyncInfo(FOLDER_SYNC_KEY, container, getBytes(info)); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } finally { + endOperation(null); + } + } else { + super.setFolderSync(container, info); + } + } + + /** + * Deletes the folder sync for the specified folder and the resource sync + * for all of its children. Does not recurse. + * + * @param folder the folder + * @see #getFolderSync, #setFolderSync + */ + public void deleteFolderSync(IContainer container) throws CVSException { + if (container.isPhantom()) { + try { + beginOperation(null); + changedResources.add(container); + flushPhantomInfo(container); + } finally { + endOperation(null); + } + } else { + super.deleteFolderSync(container); + } + } + + /** + * Gets the resource sync info for the specified folder. + * + * @param resource the resource + * @return the resource sync info associated with the resource, or null if none. + * @see #setResourceSync, #deleteResourceSync + */ + public ResourceSyncInfo getResourceSync(IResource resource) throws CVSException { + IContainer parent = resource.getParent(); + if (parent != null && parent.isPhantom()) { + Map map = getPhantomResourceSyncInfoMap(parent); + return (ResourceSyncInfo)map.get(resource.getName()); + } + return super.getResourceSync(resource); + } + + /** + * @see EclipseSynchronizer#setResourceSync(IResource, ResourceSyncInfo) + */ + public void setResourceSync(IResource resource, ResourceSyncInfo info) throws CVSException { + IContainer parent = resource.getParent(); + if (parent != null && parent.isPhantom()) { + // Look for the sync info in the workspace synchronizer + try { + beginOperation(null); + Map map = getPhantomResourceSyncInfoMap(parent); + map.put(resource.getName(), info); + getWorkspaceSynchronizer().setSyncInfo(RESOURCE_SYNC_KEY, parent, getBytes(map)); + changedResources.add(resource); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } finally { + endOperation(null); + } + } else { + super.setResourceSync(resource, info); + } + } + + /** + * Deletes the resource sync info for the specified resource, if it exists. + * + * @param resource the resource + * @see #getResourceSync, #setResourceSync + */ + public void deleteResourceSync(IResource resource) throws CVSException { + IContainer parent = resource.getParent(); + if (parent != null && parent.isPhantom()) { + // Look for the sync info in the workspace synchronizer + try { + beginOperation(null); + Map map = getPhantomResourceSyncInfoMap(parent); + map.remove(resource.getName()); + getWorkspaceSynchronizer().setSyncInfo(RESOURCE_SYNC_KEY, parent, getBytes(map)); + changedResources.add(resource); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } finally { + endOperation(null); + } + } else { + super.deleteResourceSync(resource); + } + } + + /** + * Flush the folder sync and resource sync for a phantom folder that has no childen + * @param folder an empty phantom folder + */ + private void flushEmptyFolder(IContainer folder) throws CVSException { + deleteFolderSync(folder); + deleteResourceSync(folder); + } + + /** + * Returns the members of this folder which are either phantom folder + * or file deletions + * + * @param folder the container to list + * @return the array of members + */ + public IResource[] members(IContainer container) throws CVSException { + if (container.isPhantom()) { + Map map = getPhantomResourceSyncInfoMap(container); + Set childResources = new HashSet(); + for (Iterator it = map.values().iterator(); it.hasNext();) { + ResourceSyncInfo info = (ResourceSyncInfo) it.next(); + IPath path = new Path(info.getName()); + if(info.isDirectory()) { + childResources.add(container.getFolder(path)); + } else { + childResources.add(container.getFile(path)); + } + } + return (IResource[])childResources.toArray(new IResource[childResources.size()]); + } else { + return super.members(container); + } + } + + /** + * Notify the receiver that a folder has been created. + * Any existing phantom sync info will be moved + * + * @param folder the folder that has been created + */ + public void folderCreated(IFolder folder) throws CVSException { + try { + // set the dirty count using what was cached in the phantom it + beginOperation(null); + FolderSyncInfo folderInfo = getPhantomFolderSyncInfo(folder); + if (folderInfo != null) { + Map map = getPhantomResourceSyncInfoMap(folder); + if (folder.getFolder(SyncFileWriter.CVS_DIRNAME).exists()) { + // There is already a CVS subdirectory which indicates that + // either the folder was recreated by an external tool or that + // a folder with CVS information was copied from another location. + // To know the difference, we need to compare the folder sync info. + // If they are mapped to the same root and repository then just + // purge the phantom info. Otherwise, keep the original sync info. + + // flush the phantom info so we can get what is on disk. + flushPhantomInfo(folder); + + // Get the new folder sync info + FolderSyncInfo newFolderInfo = getFolderSync(folder); + if (newFolderInfo.getRoot().equals(folderInfo.getRoot()) + && newFolderInfo.getRepository().equals(folderInfo.getRepository())) { + // The folder is the same so use what is on disk + return; + } + + // The folder is mapped to a different location. + // Purge new resource sync before restoring from phantom + ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder); + ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS); + for (int i = 0; i < children.length; i++) { + ICVSResource resource = children[i]; + deleteResourceSync(resource.getIResource()); + } + } + + // set the sync info using what was cached in the phantom + setFolderSync(folder, folderInfo); + for (Iterator it = map.values().iterator(); it.hasNext();) { + ResourceSyncInfo info = (ResourceSyncInfo) it.next(); + IPath path = new Path(info.getName()); + IResource childResource; + if(info.isDirectory()) { + childResource = folder.getFolder(path); + } else { + childResource = folder.getFile(path); + } + setResourceSync(childResource, info); + } + } + } finally { + try { + endOperation(null); + } finally { + flushPhantomInfo(folder); + } + } + } + + /** + * Return the cached folder sync info for the given container or null + * if there is none. + */ + private FolderSyncInfo getPhantomFolderSyncInfo(IContainer container) throws CVSException { + try { + byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(FOLDER_SYNC_KEY, container); + if (bytes == null) return null; + return getFolderSyncInfo(bytes); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + private Map getPhantomResourceSyncInfoMap(IContainer container) throws CVSException { + try { + byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(RESOURCE_SYNC_KEY, container); + if (bytes == null) return new HashMap(); + return getResourceSyncInfoMap(bytes); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Flush any info cahced for the folder + */ + private void flushPhantomInfo(IContainer container) throws CVSException { + try { + if (container.exists() || container.isPhantom()) { + getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_ZERO); + } + if (container.exists() || container.isPhantom()) { + getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, container, IResource.DEPTH_ZERO); + } + internalFlushModificationCache(container); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Return the Eclipse Workspace Synchronizer (from org.eclipse.core.resources) + */ + private ISynchronizer getWorkspaceSynchronizer() { + return ResourcesPlugin.getWorkspace().getSynchronizer(); + } + + /** + * The folder is about to be deleted so move the folder's CVS information + * to the workspace synchronizer so it will survive the deletion + */ + public void prepareForDeletion(IContainer container) throws CVSException { + try { + beginOperation(null); + if (container.getType() == IResource.PROJECT) { + getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_INFINITE); + getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, container, IResource.DEPTH_INFINITE); + getWorkspaceSynchronizer().flushSyncInfo(DIRTY_COUNT, container, IResource.DEPTH_INFINITE); + } else { + // Move the folder sync info into phantom space + FolderSyncInfo info = getFolderSync(container); + if (info == null) return; + getWorkspaceSynchronizer().setSyncInfo(FOLDER_SYNC_KEY, container, getBytes(info)); + getWorkspaceSynchronizer().setSyncInfo(RESOURCE_SYNC_KEY, container, getBytes(getResourceSyncInfosForChildren(container))); + changedResources.add(container); + // Move the dirty count into phantom space + Integer dirtyCount = getDirtyCount(container); + if (dirtyCount != null) { + internalSetDirtyCount(container, dirtyCount.intValue()); + } + } + } catch (CoreException e) { + throw CVSException.wrapException(e); + } finally { + endOperation(null); + } + } + + /** + * Return a map of resource name to ResourceSyncInfo + * + * This should only be used on folders that exist in the workspace + */ + private Map getResourceSyncInfosForChildren(IContainer parent) throws CVSException { + ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(parent); + ICVSResource[] files = folder.members(ICVSFolder.FILE_MEMBERS | ICVSFolder.FOLDER_MEMBERS | ICVSFolder.MANAGED_MEMBERS); + Map result = new HashMap(); + for (int i = 0; i < files.length; i++) { + ICVSResource resource = files[i]; + result.put(resource.getName(), resource.getSyncInfo()); + } + return result; + } + + /** + * Convert a byte array that was created using getBytes(FolderSyncInfo) + * into a FolderSyncInfo + */ + private static FolderSyncInfo getFolderSyncInfo(byte[] bytes) throws CVSException { + ByteArrayInputStream in = new ByteArrayInputStream(bytes); + DataInputStream dis = new DataInputStream(in); + String root; + String repository; + CVSEntryLineTag tag; + boolean isStatic; + try { + root = dis.readUTF(); + repository = dis.readUTF(); + String tagName = dis.readUTF(); + if (tagName.length() == 0) { + tag = null; + } else { + tag = new CVSEntryLineTag(tagName); + } + isStatic = dis.readBoolean(); + } catch (IOException e) { + throw CVSException.wrapException(e); + } + return new FolderSyncInfo(repository, root, tag, isStatic); + } + + /** + * Convert a FolderSyncInfo into a byte array that can be stored + * in the workspace synchronizer + */ + private static byte[] getBytes(FolderSyncInfo info) throws CVSException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(out); + try { + dos.writeUTF(info.getRoot()); + dos.writeUTF(info.getRepository()); + CVSEntryLineTag tag = info.getTag(); + if (tag == null) { + dos.writeUTF(""); //$NON-NLS-1$ + } else { + dos.writeUTF(tag.toString()); + } + dos.writeBoolean(info.getIsStatic()); + dos.close(); + } catch (IOException e) { + throw CVSException.wrapException(e); + } + return out.toByteArray(); + } + + /** + * Convert a Map of ResourceSyncInfo into a byte array that can be stored + * in the workspace synchronizer + */ + private static byte[] getBytes(Map infos) throws CVSException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(out); + try { + dos.writeInt(infos.size()); + Iterator iter = infos.values().iterator(); + while (iter.hasNext()) { + ResourceSyncInfo info = (ResourceSyncInfo)iter.next(); + dos.writeUTF(info.getEntryLine()); + } + } catch (IOException e) { + throw CVSException.wrapException(e); + } + return out.toByteArray(); + } + + /** + * Convert a byte array that was created using getBytes(Map) + * into a Map of ResourceSyncInfo + */ + private static Map getResourceSyncInfoMap(byte[] bytes) throws CVSException { + ByteArrayInputStream in = new ByteArrayInputStream(bytes); + DataInputStream dis = new DataInputStream(in); + Map result = new HashMap(); + try { + int size = dis.readInt(); + for (int i = 0; i < size; i++) { + ResourceSyncInfo info = new ResourceSyncInfo(dis.readUTF(), null, null); + result.put(info.getName(), info); + } + } catch (IOException e) { + throw CVSException.wrapException(e); + } + return result; + } + + /** + * @see EclipseSynchronizer#broadcastResourceStateChanges(IResource[]) + */ + void broadcastResourceStateChanges(IResource[] resources) { + // Add the changedResources to the list of broadcasted resources + if (changedResources.size() > 0) { + ArrayList allResources = new ArrayList(); + allResources.addAll(Arrays.asList(resources)); + allResources.addAll(changedResources); + resources = (IResource[]) allResources.toArray(new IResource[allResources.size()]); + changedResources.clear(); + } + super.broadcastResourceStateChanges(resources); + } + + /* + * Return the dirty count for the given folder. For existing folders, the + * dirty count may not have been calculated yet and this method will return + * null in that case. For phantom folders, the dirty count is calculated if + * it does not exist yet. + */ + protected Integer getDirtyCount(IContainer parent) throws CVSException { + if (parent.isPhantom()) { + // get the count from the synchronizer + int count = internalGetDirtyCount(parent); + if (count == -1) { + count = calculateDirtyCountForPhantom(parent); + //setDirtyCount(parent, count); + } + return new Integer(count); + } else { + return super.getDirtyCount(parent); + } + } + + protected int internalGetDirtyCount(IContainer parent) throws CVSException { + try { + byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(DIRTY_COUNT, parent); + if (bytes == null) return -1; + return intFromBytes(bytes); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + protected void setDirtyCount(IContainer container, int count) throws CVSException { + if (container.isPhantom()) { + internalSetDirtyCount(container, count); + } else { + super.setDirtyCount(container, count); + } + } + + protected void internalSetDirtyCount(IContainer container, int count) throws CVSException { + try { + beginOperation(null); + getWorkspaceSynchronizer().setSyncInfo(DIRTY_COUNT, container, getBytes(count)); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } finally { + endOperation(null); + } + } + + /* + * Calculate the dirty count for the given phantom folder, performing any + * necessary calculations on the childen as well + */ + private int calculateDirtyCountForPhantom(IContainer parent) throws CVSException { + ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(parent); + ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS | ICVSFolder.PHANTOM_MEMBERS); + int count = 0; + for (int i = 0; i < children.length; i++) { + ICVSResource resource = children[i]; + if (resource.isFolder()) { + Integer dc = getDirtyCount((IContainer)resource.getIResource()); + if (dc.intValue() > 0) count++; + } else { + // Any non-existant managed files are dirty (outgoing deletion) + count++; + } + } + return count; + } + /* + * Convert an int to a byte array + */ + private byte[] getBytes(int count) { + byte[] result = new byte[4]; + result[0] = (byte)(count & 256); + result[1] = (byte)(count<<8 & 256); + result[1] = (byte)(count<<16 & 256); + result[1] = (byte)(count<<24 & 256); + return result; + } + + /* + * Convert a byte array to an int + */ + private int intFromBytes(byte[] bytes) { + return bytes[0] + (bytes[1]>>8) + (bytes[2]>>16) + (bytes[3]>>24); + } + + /* + * Flush all cached info for the container and it's ancestors + */ + protected void flushModificationCache(IContainer container) throws CVSException { + internalFlushModificationCache(container); + super.flushModificationCache(container); + } + + private void internalFlushModificationCache(IContainer container) throws CVSException { +// if (container.exists() || container.isPhantom()) { +// try { +// getWorkspaceSynchronizer().flushSyncInfo(DIRTY_COUNT, container, IResource.DEPTH_ZERO); +// } catch (CoreException e) { +// throw CVSException.wrapException(e); +// } +// } + } + + /** + * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#addDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) + */ + protected boolean addDeletedChild(IContainer container, IFile file) throws CVSException { + if (container.isPhantom()) { +// try { +// beginOperation(null); +// int oldCount = internalGetDirtyCount(container); +// if (oldCount == -1) { +// // there is no cached count so wait until the first query +// // or there was no deleted file +// return false; +// } +// int newCount = calculateDirtyCountForPhantom(container); +// // adjust the parent folder count if the newCount is 1; +// return oldCount == 0 && newCount == 1; +// } finally { +// endOperation(null); +// } + return true; + } else { + return super.addDeletedChild(container, file); + } + } + + /** + * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#removeDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) + */ + protected boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { + if (container.isPhantom()) { +// try { +// beginOperation(null); +// int oldCount = internalGetDirtyCount(container); +// if (oldCount == -1 || oldCount == 0) { +// // there is no cached count so wait until the first query +// // or there was no deleted file +// return false; +// } +// int newCount = calculateDirtyCountForPhantom(container); +// // adjust the parent folder count if the newCount is 0; +// return newCount == 0; +// } finally { +// endOperation(null); +// } + return true; + } else { + return super.removeDeletedChild(container, file); + } + } +} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java index 541163c25..84e58f931 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseResource.java @@ -267,13 +267,23 @@ abstract class EclipseResource implements ICVSResource, Comparable { return resource; } + /* + * Flush all cached modification info for the resource and it's ancestors + */ + protected abstract void flushModificationCache() throws CVSException; + public abstract boolean handleModification(boolean forAddition) throws CVSException; /* * Flush all cached info for the file and it's ancestors */ protected void flushWithAncestors() throws CVSException { - EclipseSynchronizer.getInstance().flushDirtyCacheWithAncestors(getIResource()); + if (resource.getType() == IResource.ROOT) return; + try { + flushModificationCache(); + } finally { + ((EclipseResource)getParent()).flushWithAncestors(); + } } protected String getDirtyIndicator() throws CVSException { @@ -284,6 +294,20 @@ abstract class EclipseResource implements ICVSResource, Comparable { EclipseSynchronizer.getInstance().setDirtyIndicator(getIResource(), indicator); } + /* + * Method prepareToBeDeleted is invoked by the move/delete hook to allow the + * resource to prepare to be deleted. + */ + protected void prepareToBeDeleted() throws CVSException { + // Flush the dirty info for the resource and it's ancestors. + // Although we could be smarter, we need to do this because the + // deletion may fail. + String indicator = EclipseSynchronizer.getInstance().getDirtyIndicator(getIResource()); + if (indicator != null) { + flushWithAncestors(); + } + } + /* * Method syncInfoChanged is invoked by the sync file change listener. */ diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java index c256171bb..e95f73bcd 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java @@ -7,6 +7,7 @@ package org.eclipse.team.internal.ccvs.core.resources; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -17,7 +18,6 @@ import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.runtime.CoreException; @@ -26,11 +26,11 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.core.runtime.Status; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.CVSStatus; -import org.eclipse.team.internal.ccvs.core.ICVSFolder; -import org.eclipse.team.internal.ccvs.core.ICVSResource; import org.eclipse.team.internal.ccvs.core.ICVSRunnable; import org.eclipse.team.internal.ccvs.core.Policy; import org.eclipse.team.internal.ccvs.core.syncinfo.BaserevInfo; @@ -48,10 +48,26 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; * @see ResourceSyncInfo * @see FolderSyncInfo */ -public class EclipseSynchronizer { - protected static final String IS_DIRTY_INDICATOR = LowLevelSyncInfoCache.IS_DIRTY_INDICATOR; - protected static final String NOT_DIRTY_INDICATOR = LowLevelSyncInfoCache.NOT_DIRTY_INDICATOR; - +public class EclipseSynchronizer { + // the resources plugin synchronizer is used to cache and possibly persist. These + // are keys for storing the sync info. + private static final QualifiedName FOLDER_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync"); //$NON-NLS-1$ + private static final QualifiedName RESOURCE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync"); //$NON-NLS-1$ + private static final QualifiedName IGNORE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-ignore"); //$NON-NLS-1$ + + protected static final QualifiedName IS_DIRTY = new QualifiedName(CVSProviderPlugin.ID, "is-dirty"); + protected static final QualifiedName CLEAN_UPDATE = new QualifiedName(CVSProviderPlugin.ID, "clean-update"); + protected static final QualifiedName DIRTY_COUNT = new QualifiedName(CVSProviderPlugin.ID, "dirty-count"); + protected static final QualifiedName DELETED_CHILDREN = new QualifiedName(CVSProviderPlugin.ID, "deleted"); + protected static final String IS_DIRTY_INDICATOR = "d"; + protected static final String NOT_DIRTY_INDICATOR = "c"; + protected static final String UPDATED_INDICATOR = "u"; + + private static final String[] NULL_IGNORES = new String[0]; + private static final FolderSyncInfo NULL_FOLDER_SYNC_INFO = new FolderSyncInfo("", "", null, false); //$NON-NLS-1$ //$NON-NLS-2$ + + private static final IStatus STATUS_OK = new Status(IStatus.OK, CVSProviderPlugin.ID, 0, Policy.bind("ok"), null); //$NON-NLS-1$ + // the cvs eclipse synchronizer is a singleton private static EclipseSynchronizer instance; @@ -61,13 +77,6 @@ public class EclipseSynchronizer { private Set changedResources = new HashSet(); private Set changedFolders = new HashSet(); - private static IContainer cachedFolder; - private static Map cachedResourceSyncInfos; - private static boolean cacheDirty = false; - - private SessionPropertySyncInfoCache sessionPropertyCache = new SessionPropertySyncInfoCache(); - private SynchronizerSyncInfoCache synchronizerCache = new SynchronizerSyncInfoCache(); - /* * Package private contructor to allow specialized subclass for handling folder deletions */ @@ -79,23 +88,11 @@ public class EclipseSynchronizer { */ public static EclipseSynchronizer getInstance() { if(instance==null) { - instance = new EclipseSynchronizer(); + instance = new EclipsePhantomSynchronizer(); } return instance; } - - public LowLevelSyncInfoCache getLowLevelCacheFor(IResource resource) { - if (resource.isPhantom()) { - return synchronizerCache; - } else { - return sessionPropertyCache; - } - } - private boolean isValid(IResource resource) { - return resource.exists() || resource.isPhantom(); - } - /** * Sets the folder sync info for the specified folder. * The folder must exist and must not be the workspace root. @@ -106,14 +103,14 @@ public class EclipseSynchronizer { */ public void setFolderSync(IContainer folder, FolderSyncInfo info) throws CVSException { Assert.isNotNull(info); // enforce the use of deleteFolderSync - if (folder.getType() == IResource.ROOT || !isValid(folder)) { + if (folder.getType() == IResource.ROOT || ! folder.exists()) { throw new CVSException(IStatus.ERROR, CVSException.UNABLE, Policy.bind("EclipseSynchronizer.ErrorSettingFolderSync", folder.getFullPath().toString())); //$NON-NLS-1$ } try { beginOperation(null); // set folder sync and notify - getLowLevelCacheFor(folder).setCachedFolderSync(folder, info); + setCachedFolderSync(folder, info); changedFolders.add(folder); } finally { endOperation(null); @@ -128,11 +125,11 @@ public class EclipseSynchronizer { * @see #setFolderSync, #deleteFolderSync */ public FolderSyncInfo getFolderSync(IContainer folder) throws CVSException { - if (folder.getType() == IResource.ROOT || !isValid(folder)) return null; + if (folder.getType() == IResource.ROOT || ! folder.exists()) return null; try { beginOperation(null); // cache folder sync and return it - return getLowLevelCacheFor(folder).cacheFolderSync(folder); + return cacheFolderSync(folder); } finally { endOperation(null); } @@ -146,17 +143,17 @@ public class EclipseSynchronizer { * @see #getFolderSync, #setFolderSync */ public void deleteFolderSync(IContainer folder) throws CVSException { - if (folder.getType() == IResource.ROOT || !isValid(folder)) return; + if (folder.getType() == IResource.ROOT || ! folder.exists()) return; try { beginOperation(null); // delete folder sync - getLowLevelCacheFor(folder).setCachedFolderSync(folder, null); + setCachedFolderSync(folder, null); changedFolders.add(folder); // iterate over all children with sync info and prepare notifications - getLowLevelCacheFor(folder).cacheResourceSyncForChildren(folder); - fastCacheResourceSyncForChildren(folder); - for (Iterator iter = cachedResourceSyncInfos.values().iterator(); iter.hasNext();) { - ResourceSyncInfo info = (ResourceSyncInfo) iter.next(); + cacheResourceSyncForChildren(folder); + Collection infos = getCachedResourceSyncForChildren(folder); + for (Iterator it = infos.iterator(); it.hasNext();) { + ResourceSyncInfo info = (ResourceSyncInfo) it.next(); IPath path = new Path(info.getName()); if(info.isDirectory()) { changedResources.add(folder.getFolder(path)); @@ -165,7 +162,7 @@ public class EclipseSynchronizer { } } // delete resource sync for all children - getLowLevelCacheFor(folder).setCachedResourceSyncForChildren(folder, null); + deleteCachedResourceSyncForChildren(folder); } finally { endOperation(null); } @@ -182,14 +179,14 @@ public class EclipseSynchronizer { public void setResourceSync(IResource resource, ResourceSyncInfo info) throws CVSException { Assert.isNotNull(info); // enforce the use of deleteResourceSync IContainer parent = resource.getParent(); - if (parent == null || parent.getType() == IResource.ROOT || !isValid(parent)) { + if (parent == null || ! parent.exists() || parent.getType() == IResource.ROOT) { throw new CVSException(IStatus.ERROR, CVSException.UNABLE, Policy.bind("EclipseSynchronizer.ErrorSettingResourceSync", resource.getFullPath().toString())); //$NON-NLS-1$ } try { beginOperation(null); // cache resource sync for siblings, set for self, then notify - getLowLevelCacheFor(parent).cacheResourceSyncForChildren(parent); + cacheResourceSyncForChildren(parent); setCachedResourceSync(resource, info); changedResources.add(resource); } finally { @@ -206,11 +203,11 @@ public class EclipseSynchronizer { */ public ResourceSyncInfo getResourceSync(IResource resource) throws CVSException { IContainer parent = resource.getParent(); - if (parent == null || parent.getType() == IResource.ROOT || !isValid(parent)) return null; + if (parent == null || ! parent.exists() || parent.getType() == IResource.ROOT) return null; try { beginOperation(null); // cache resource sync for siblings, then return for self - getLowLevelCacheFor(parent).cacheResourceSyncForChildren(parent); + cacheResourceSyncForChildren(parent); return getCachedResourceSync(resource); } finally { endOperation(null); @@ -225,11 +222,11 @@ public class EclipseSynchronizer { */ public void deleteResourceSync(IResource resource) throws CVSException { IContainer parent = resource.getParent(); - if (parent == null || parent.getType() == IResource.ROOT || !isValid(parent)) return; + if (parent == null || ! parent.exists() || parent.getType() == IResource.ROOT) return; try { beginOperation(null); // cache resource sync for siblings, delete for self, then notify - getLowLevelCacheFor(parent).cacheResourceSyncForChildren(parent); + cacheResourceSyncForChildren(resource.getParent()); if (getCachedResourceSync(resource) != null) { // avoid redundant notifications setCachedResourceSync(resource, null); changedResources.add(resource); @@ -247,7 +244,7 @@ public class EclipseSynchronizer { * @see #addIgnored */ public String[] getIgnored(IContainer folder) throws CVSException { - if (folder.getType() == IResource.ROOT || ! folder.exists()) return SessionPropertySyncInfoCache.NULL_IGNORES; + if (folder.getType() == IResource.ROOT || ! folder.exists()) return NULL_IGNORES; try { beginOperation(null); return cacheFolderIgnores(folder); @@ -302,16 +299,16 @@ public class EclipseSynchronizer { * @return the array of members */ public IResource[] members(IContainer folder) throws CVSException { - if (! isValid(folder)) return new IResource[0]; + if (! folder.exists()) return new IResource[0]; try { beginOperation(null); if (folder.getType() == IResource.ROOT) return folder.members(); - getLowLevelCacheFor(folder).cacheResourceSyncForChildren(folder); - fastCacheResourceSyncForChildren(folder); + cacheResourceSyncForChildren(folder); + Collection infos = getCachedResourceSyncForChildren(folder); // add all children with or without sync info Set childResources = new HashSet(); - for (Iterator iter = cachedResourceSyncInfos.values().iterator(); iter.hasNext();) { - ResourceSyncInfo info = (ResourceSyncInfo) iter.next(); + for (Iterator it = infos.iterator(); it.hasNext();) { + ResourceSyncInfo info = (ResourceSyncInfo) it.next(); IPath path = new Path(info.getName()); if(info.isDirectory()) { childResources.add(folder.getFolder(path)); @@ -319,8 +316,7 @@ public class EclipseSynchronizer { childResources.add(folder.getFile(path)); } } - if (folder.exists()) - childResources.addAll(Arrays.asList(folder.members())); + childResources.addAll(Arrays.asList(folder.members())); return (IResource[])childResources.toArray(new IResource[childResources.size()]); } catch (CoreException e) { throw CVSException.wrapException(e); @@ -356,11 +352,11 @@ public class EclipseSynchronizer { */ public void endOperation(IProgressMonitor monitor) throws CVSException { try { - IStatus status = LowLevelSyncInfoCache.STATUS_OK; + IStatus status = STATUS_OK; if (lock.getNestingCount() == 1) { status = commitCache(monitor); } - if (!status.isOK()) { + if (status != STATUS_OK) { throw new CVSException(status); } } finally { @@ -397,12 +393,12 @@ public class EclipseSynchronizer { IStatus status = commitCache(Policy.subMonitorFor(monitor, 7)); // purge from memory too if we were asked to - if (purgeCache) sessionPropertyCache.purgeCache(root, deep); + if (purgeCache) purgeCache(root, deep); // prepare for the operation again if we cut the last one short prepareCache(Policy.subMonitorFor(monitor, 1)); - if (!status.isOK()) { + if (status != STATUS_OK) { throw new CVSException(status); } } finally { @@ -438,94 +434,15 @@ public class EclipseSynchronizer { * The folder is about to be deleted (including its CVS subfolder). * Take any appropriate action to remember the CVS information. */ - public void prepareForDeletion(IResource resource) throws CVSException { - try { - beginOperation(null); - // Flush the dirty info for the resource and it's ancestors. - // Although we could be smarter, we need to do this because the - // deletion may fail. - String indicator = EclipseSynchronizer.getInstance().getDirtyIndicator(resource); - if (indicator != null) { - flushDirtyCacheWithAncestors(resource); - } - if (resource.getType() != IResource.FILE) { - IContainer container = (IContainer)resource; - purgeFastCache(); - if (container.getType() == IResource.PROJECT) { - synchronizerCache.flush((IProject)container); - } else { - // Move the folder sync info into phantom space - FolderSyncInfo info = getFolderSync(container); - if (info == null) return; - synchronizerCache.setCachedFolderSync(container, info); - synchronizerCache.setCachedResourceSyncForChildren(container, sessionPropertyCache.getCachedResourceSyncForChildren(container)); - changedFolders.add(container); - // todo - // Move the dirty count into phantom space - int dirtyCount = getDirtyCount(container); - if (dirtyCount != -1) { - synchronizerCache.setCachedDirtyCount(container, dirtyCount); - } - } - } - } finally { - endOperation(null); - } + public void prepareForDeletion(IContainer container) throws CVSException { } /** - * Notify the receiver that a folder has been created. - * Any existing phantom sync info will be moved - * - * @param folder the folder that has been created + * Signal to the synchronizer that a folder has been created + * + * @param folder the folder to be created */ public void folderCreated(IFolder folder) throws CVSException { - try { - // set the dirty count using what was cached in the phantom it - beginOperation(null); - FolderSyncInfo folderInfo = synchronizerCache.getCachedFolderSync(folder); - if (folderInfo != null) { - byte[][] infos = synchronizerCache.getCachedResourceSyncForChildren(folder); - if (folder.getFolder(SyncFileWriter.CVS_DIRNAME).exists()) { - // There is already a CVS subdirectory which indicates that - // either the folder was recreated by an external tool or that - // a folder with CVS information was copied from another location. - // To know the difference, we need to compare the folder sync info. - // If they are mapped to the same root and repository then just - // purge the phantom info. Otherwise, keep the original sync info. - - // flush the phantom info so we can get what is on disk. - synchronizerCache.flush(folder); - - // Get the new folder sync info - FolderSyncInfo newFolderInfo = getFolderSync(folder); - if (newFolderInfo.getRoot().equals(folderInfo.getRoot()) - && newFolderInfo.getRepository().equals(folderInfo.getRepository())) { - // The folder is the same so use what is on disk - return; - } - - // The folder is mapped to a different location. - // Purge new resource sync before restoring from phantom - ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder); - ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS); - for (int i = 0; i < children.length; i++) { - ICVSResource resource = children[i]; - deleteResourceSync(resource.getIResource()); - } - } - - // set the sync info using what was cached in the phantom - setFolderSync(folder, folderInfo); - sessionPropertyCache.setCachedResourceSyncForChildren(folder, infos); - } - } finally { - try { - endOperation(null); - } finally { - synchronizerCache.flush(folder); - } - } } /** @@ -547,49 +464,103 @@ public class EclipseSynchronizer { * @param monitor the progress monitor, may be null */ private IStatus commitCache(IProgressMonitor monitor) { - // write the fast cache to the low level cache - IStatus status = LowLevelSyncInfoCache.STATUS_OK; - try { - purgeFastCache(); - } catch (CVSException e) { - status = e.getStatus(); + if (changedFolders.isEmpty() && changedResources.isEmpty()) { + broadcastResourceStateChanges(new IResource[0]); + return STATUS_OK; } - - // Commit the session property cache to disk. - status = mergeStatus(sessionPropertyCache.commitCache(monitor), status); + List errors = new ArrayList(); + try { + /*** prepare operation ***/ + // find parents of changed resources + Set dirtyParents = new HashSet(); + for(Iterator it = changedResources.iterator(); it.hasNext();) { + IResource resource = (IResource) it.next(); + IContainer folder = resource.getParent(); + dirtyParents.add(folder); + } + + monitor = Policy.monitorFor(monitor); + int numDirty = dirtyParents.size(); + int numResources = changedFolders.size() + numDirty; + monitor.beginTask(null, numResources); + if(monitor.isCanceled()) { + monitor.subTask(Policy.bind("EclipseSynchronizer.UpdatingSyncEndOperationCancelled")); //$NON-NLS-1$ + } else { + monitor.subTask(Policy.bind("EclipseSynchronizer.UpdatingSyncEndOperation")); //$NON-NLS-1$ + } + + /*** write sync info to disk ***/ + // folder sync info changes + for(Iterator it = changedFolders.iterator(); it.hasNext();) { + IContainer folder = (IContainer) it.next(); + if (folder.exists() && folder.getType() != IResource.ROOT) { + try { + FolderSyncInfo info = getCachedFolderSync(folder); + if (info == null) { + // deleted folder sync info since we loaded it + SyncFileWriter.deleteFolderSync(folder); + dirtyParents.remove(folder); + } else { + // modified or created new folder sync info since we loaded it + SyncFileWriter.writeFolderSync(folder, info); + } + } catch(CVSException e) { + try { + purgeCache(folder, true /* deep */); + } catch(CVSException pe) { + errors.add(pe.getStatus()); + } + errors.add(e.getStatus()); + } + } + monitor.worked(1); + } - /*** broadcast events ***/ - changedResources.addAll(changedFolders); - IResource[] resources = (IResource[]) changedResources.toArray( - new IResource[changedResources.size()]); - broadcastResourceStateChanges(resources); - changedResources.clear(); - changedFolders.clear(); - return status; - } - - /** - * Method mergeStatus. - * @param iStatus - * @param status - * @return IStatus - */ - private IStatus mergeStatus(IStatus status1, IStatus status2) { - if (status1.isOK()) return status2; - if (status2.isOK()) return status1; - if (status1.isMultiStatus()) { - ((MultiStatus)status1).merge(status2); - return status1; - } - if (status2.isMultiStatus()) { - ((MultiStatus)status2).merge(status1); - return status2; + // update progress for parents we will skip because they were deleted + monitor.worked(numDirty - dirtyParents.size()); + + // resource sync info changes + for (Iterator it = dirtyParents.iterator(); it.hasNext();) { + IContainer folder = (IContainer) it.next(); + if (folder.exists() && folder.getType() != IResource.ROOT) { + // write sync info for all children in one go + try { + Collection infos = getCachedResourceSyncForChildren(folder); + SyncFileWriter.writeAllResourceSync(folder, + (ResourceSyncInfo[]) infos.toArray(new ResourceSyncInfo[infos.size()])); + } catch(CVSException e) { + try { + purgeCache(folder, false /* depth 1 */); + } catch(CVSException pe) { + errors.add(pe.getStatus()); + } + errors.add(e.getStatus()); + } + } + monitor.worked(1); + } + + /*** broadcast events ***/ + changedResources.addAll(changedFolders); + IResource[] resources = (IResource[]) changedResources.toArray( + new IResource[changedResources.size()]); + broadcastResourceStateChanges(resources); + changedResources.clear(); + changedFolders.clear(); + if ( ! errors.isEmpty()) { + MultiStatus status = new MultiStatus(CVSProviderPlugin.ID, + CVSStatus.COMMITTING_SYNC_INFO_FAILED, + Policy.bind("EclipseSynchronizer.ErrorCommitting"), //$NON-NLS-1$ + null); + for (int i = 0; i < errors.size(); i++) { + status.merge((IStatus)errors.get(i)); + } + return status; + } + return STATUS_OK; + } finally { + monitor.done(); } - return new MultiStatus(CVSProviderPlugin.ID, - CVSStatus.COMMITTING_SYNC_INFO_FAILED, - new IStatus[] { status1, status2 }, - Policy.bind("EclipseSynchronizer.ErrorCommitting"), //$NON-NLS-1$ - null); } /** @@ -601,6 +572,61 @@ public class EclipseSynchronizer { } } + /** + * Purges the cache recursively for all resources beneath the container. + * There must not be any pending uncommitted changes. + */ + private static void purgeCache(IContainer container, boolean deep) throws CVSException { + if (! container.exists()) return; + try { + if (container.getType() != IResource.ROOT) { + container.setSessionProperty(RESOURCE_SYNC_KEY, null); + container.setSessionProperty(IGNORE_SYNC_KEY, null); + container.setSessionProperty(FOLDER_SYNC_KEY, null); + } + if(deep) { + IResource[] members = container.members(); + for (int i = 0; i < members.length; i++) { + IResource resource = members[i]; + if (resource.getType() != IResource.FILE) { + purgeCache((IContainer) resource, deep); + } + } + } + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * If not already cached, loads and caches the resource sync for the children of the container. + * Folder must exist and must not be the workspace root. + * + * @param container the container + */ + private static void cacheResourceSyncForChildren(IContainer container) throws CVSException { + try { + // don't try to load if the information is already cached + HashMap children = (HashMap)container.getSessionProperty(RESOURCE_SYNC_KEY); + if (children == null) { + // load the sync info from disk + ResourceSyncInfo[] infos = SyncFileWriter.readAllResourceSync(container); + if (infos != null) { + children = new HashMap(infos.length); + for (int i = 0; i < infos.length; i++) { + ResourceSyncInfo syncInfo = infos[i]; + children.put(syncInfo.getName(), syncInfo); + } + } else { + children = new HashMap(0); + } + container.setSessionProperty(RESOURCE_SYNC_KEY, children); + } + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + /** * Returns the resource sync info for the resource; null if none. * Parent must exist and must not be the workspace root. @@ -610,77 +636,153 @@ public class EclipseSynchronizer { * @return the resource sync info for the resource, or null * @see #cacheResourceSyncForChildren */ - private ResourceSyncInfo getCachedResourceSync(IResource resource) throws CVSException { - fastCacheResourceSyncForChildren(resource.getParent()); - return (ResourceSyncInfo) cachedResourceSyncInfos.get(resource.getName()); - } - - private void fastCacheResourceSyncForChildren(IContainer parent) throws CVSException { - if (!parent.equals(cachedFolder)) { - purgeFastCache(); - byte[][] infos = getLowLevelCacheFor(parent).getCachedResourceSyncForChildren(parent); - if (infos == null) { + private static ResourceSyncInfo getCachedResourceSync(IResource resource) throws CVSException { + try { + IContainer parent = resource.getParent(); + HashMap children = (HashMap)resource.getParent().getSessionProperty(RESOURCE_SYNC_KEY); + if (children == null) { // There should be sync info but it was missing. Report the error throw new CVSException(Policy.bind("EclipseSynchronizer.folderSyncInfoMissing", parent.getFullPath().toString())); //$NON-NLS-1$ } - HashMap children = new HashMap(); - for (int i = 0; i < infos.length; i++) { - ResourceSyncInfo info = new ResourceSyncInfo(infos[i]); - children.put(info.getName(), info); + return (ResourceSyncInfo) children.get(resource.getName()); + } catch(CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Sets the resource sync info for the resource; if null, deletes it. + * Parent must exist and must not be the workspace root. + * The resource sync info for the children of the parent container MUST ALREADY BE CACHED. + * + * @param resource the resource + * @param info the new resource sync info + * @see #cacheResourceSyncForChildren + */ + private static void setCachedResourceSync(IResource resource, ResourceSyncInfo info) throws CVSException { + try { + IContainer parent = resource.getParent(); + HashMap children = (HashMap)parent.getSessionProperty(RESOURCE_SYNC_KEY); + Assert.isNotNull(children); + if (info == null) { + children.remove(resource.getName()); + } else { + children.put(resource.getName(), info); } - cachedResourceSyncInfos = children; - cachedFolder = parent; + } catch(CoreException e) { + throw CVSException.wrapException(e); } } /** - * Method purgeCurrentFolderCache. + * Returns the resource sync info for all children of the container. + * Container must exist and must not be the workspace root. + * The resource sync info for the children of the container MUST ALREADY BE CACHED. + * + * @param container the container + * @return a collection of the resource sync info's for all children + * @see #cacheResourceSyncForChildren */ - private void purgeFastCache() throws CVSException { + private static Collection /* of ResourceSyncInfo */ getCachedResourceSyncForChildren(IContainer container) throws CVSException { try { - beginOperation(null); - if (cacheDirty) { - byte[][] newInfos; - if (cachedResourceSyncInfos.isEmpty()) { - newInfos = LowLevelSyncInfoCache.EMPTY_RESOURCE_SYNC_INFOS; + HashMap children = (HashMap)container.getSessionProperty(RESOURCE_SYNC_KEY); + if (children == null) { + // There should be sync info but it was missing. Report the error + throw new CVSException(Policy.bind("EclipseSynchronizer.folderSyncInfoMissing", container.getFullPath().toString())); //$NON-NLS-1$ + } + return children.values(); + } catch(CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Deletes the resource sync info for all children of the container. + * Container must exist and must not be the workspace root. + * The resource sync info for the children of the container need not have previously been cached. + * + * @param container the container + */ + private static void deleteCachedResourceSyncForChildren(IContainer container) throws CVSException { + try { + HashMap children = (HashMap)container.getSessionProperty(RESOURCE_SYNC_KEY); + if (children != null) { + children.clear(); + } else { + children = new HashMap(0); + container.setSessionProperty(RESOURCE_SYNC_KEY, children); + } + } catch(CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * If not already cached, loads and caches the folder sync for the container. + * Folder must exist and must not be the workspace root. + * + * @param container the container + * @return the folder sync info for the folder, or null if none. + */ + private static FolderSyncInfo cacheFolderSync(IContainer container) throws CVSException { + try { + // don't try to load if the information is already cached + FolderSyncInfo info = (FolderSyncInfo)container.getSessionProperty(FOLDER_SYNC_KEY); + if (info == null) { + // read folder sync info and remember it + info = SyncFileWriter.readFolderSync(container); + if (info == null) { + container.setSessionProperty(FOLDER_SYNC_KEY, NULL_FOLDER_SYNC_INFO); } else { - newInfos = new byte[cachedResourceSyncInfos.size()][]; - int i = 0; - for (Iterator iter = cachedResourceSyncInfos.values().iterator(); iter.hasNext();) { - ResourceSyncInfo info = (ResourceSyncInfo) iter.next(); - newInfos[i++] = info.getBytes(); - } + container.setSessionProperty(FOLDER_SYNC_KEY, info); } - getLowLevelCacheFor(cachedFolder).setCachedResourceSyncForChildren(cachedFolder, newInfos); + } else if (info == NULL_FOLDER_SYNC_INFO) { + info = null; } - cacheDirty = false; - cachedFolder = null; - cachedResourceSyncInfos = null; - } finally { - endOperation(null); + return info; + } catch (CoreException e) { + throw CVSException.wrapException(e); } } /** - * Sets the resource sync info for the resource; if null, deletes it. Parent - * must exist and must not be the workspace root. The resource sync info for - * the children of the parent container MUST ALREADY BE CACHED. + * Returns the folder sync info for the container; null if none. + * Folder must exist and must not be the workspace root. + * The folder sync info for the container MUST ALREADY BE CACHED. * - * @param resource the resource - * @param info the new resource sync info - * @see #cacheResourceSyncForChildren + * @param container the container + * @return the folder sync info for the folder, or null if none. + * @see #cacheFolderSync */ - private void setCachedResourceSync(IResource resource, ResourceSyncInfo info) throws CVSException { - // Get the old info to trigger caching for the parent - fastCacheResourceSyncForChildren(resource.getParent()); - Assert.isNotNull(cachedResourceSyncInfos); - Assert.isTrue(resource.getParent().equals(cachedFolder)); - if (info == null) { - cachedResourceSyncInfos.remove(resource.getName()); - } else { - cachedResourceSyncInfos.put(resource.getName(), info); + private static FolderSyncInfo getCachedFolderSync(IContainer container) throws CVSException { + try { + FolderSyncInfo info = (FolderSyncInfo)container.getSessionProperty(FOLDER_SYNC_KEY); + if (info == null) { + // There should be sync info but it was missing. Report the error + throw new CVSException(Policy.bind("EclipseSynchronizer.folderSyncInfoMissing", container.getFullPath().toString())); //$NON-NLS-1$ + } + if (info == NULL_FOLDER_SYNC_INFO) return null; + return info; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Sets the folder sync info for the container; if null, deletes it. + * Folder must exist and must not be the workspace root. + * The folder sync info for the container need not have previously been cached. + * + * @param container the container + * @param info the new folder sync info + */ + private static void setCachedFolderSync(IContainer container, FolderSyncInfo info) throws CVSException { + try { + if (info == null) info = NULL_FOLDER_SYNC_INFO; + container.setSessionProperty(FOLDER_SYNC_KEY, info); + } catch (CoreException e) { + throw CVSException.wrapException(e); } - cacheDirty = true; } /** @@ -690,8 +792,20 @@ public class EclipseSynchronizer { * @param container the container * @return the folder ignore patterns, or an empty array if none */ - private String[] cacheFolderIgnores(IContainer container) throws CVSException { - return sessionPropertyCache.cacheFolderIgnores(container); + private static String[] cacheFolderIgnores(IContainer container) throws CVSException { + try { + // don't try to load if the information is already cached + String[] ignores = (String[])container.getSessionProperty(IGNORE_SYNC_KEY); + if (ignores == null) { + // read folder ignores and remember it + ignores = SyncFileWriter.readCVSIgnoreEntries(container); + if (ignores == null) ignores = NULL_IGNORES; + container.setSessionProperty(IGNORE_SYNC_KEY, ignores); + } + return ignores; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } } /** @@ -701,8 +815,12 @@ public class EclipseSynchronizer { * @param container the container * @param ignores the array of ignore patterns */ - private void setCachedFolderIgnores(IContainer container, String[] ignores) throws CVSException { - sessionPropertyCache.setCachedFolderIgnores(container, ignores); + private static void setCachedFolderIgnores(IContainer container, String[] ignores) throws CVSException { + try { + container.setSessionProperty(IGNORE_SYNC_KEY, ignores); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } } /** @@ -714,23 +832,17 @@ public class EclipseSynchronizer { */ private void accumulateNonManagedChildren(IContainer folder, List possibleIgnores) throws CVSException { try { - getLowLevelCacheFor(folder).cacheResourceSyncForChildren(folder); + cacheResourceSyncForChildren(folder); IResource[] children = folder.members(); - List folders = new ArrayList(); - // deal with all files first and then folders to be otimized for caching scheme for (int i = 0; i < children.length; i++) { IResource child = children[i]; if(getCachedResourceSync(child)==null) { possibleIgnores.add(child); } if(child.getType()!=IResource.FILE) { - folders.add(child); + accumulateNonManagedChildren((IContainer)child, possibleIgnores); } } - for (Iterator iter = folders.iterator(); iter.hasNext();) { - IContainer child = (IContainer) iter.next(); - accumulateNonManagedChildren(child, possibleIgnores); - } } catch(CoreException e) { throw CVSException.wrapException(e); } @@ -921,7 +1033,17 @@ public class EclipseSynchronizer { // for all folders that have a CVS folder, ensure the sync info is cached for (int i = 0; i < folders.length; i++) { IContainer parent = folders[i]; - if (!getLowLevelCacheFor(parent).isSyncInfoLoaded(parent)) { + try { + if (parent.getFolder(new Path(SyncFileWriter.CVS_DIRNAME)).exists()) { + if (parent.getSessionProperty(RESOURCE_SYNC_KEY) == null) + return false; + if (parent.getSessionProperty(FOLDER_SYNC_KEY) == null) + return false; + if (parent.getSessionProperty(IGNORE_SYNC_KEY) == null) + return false; + } + } catch (CoreException e) { + // let future operations surface the error return false; } } @@ -942,8 +1064,8 @@ public class EclipseSynchronizer { IContainer parent = folders[i]; try { beginOperation(null); - getLowLevelCacheFor(parent).cacheResourceSyncForChildren(parent); - getLowLevelCacheFor(parent).cacheFolderSync(parent); + cacheResourceSyncForChildren(parent); + cacheFolderSync(parent); cacheFolderIgnores(parent); } finally { endOperation(null); @@ -1005,11 +1127,46 @@ public class EclipseSynchronizer { } protected void setDirtyIndicator(IResource resource, String indicator) throws CVSException { - getLowLevelCacheFor(resource).setDirtyIndicator(resource, indicator); + if (resource.getType() == IResource.FILE) { + internalSetDirtyIndicator((IFile)resource, indicator); + } else { + internalSetDirtyIndicator((IContainer)resource, indicator); + } } - protected String getDirtyIndicator(IResource resource) throws CVSException { - return getLowLevelCacheFor(resource).getDirtyIndicator(resource); + if (resource.getType() == IResource.FILE) { + return internalGetDirtyIndicator((IFile)resource); + } else { + return internalGetDirtyIndicator((IContainer)resource); + } + } + private void internalSetDirtyIndicator(IFile file, String indicator) throws CVSException { + try { + file.setSessionProperty(IS_DIRTY, indicator); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + private String internalGetDirtyIndicator(IFile file) throws CVSException { + try { + return (String)file.getSessionProperty(IS_DIRTY); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + private void internalSetDirtyIndicator(IContainer container, String indicator) throws CVSException { + try { + container.setPersistentProperty(IS_DIRTY, indicator); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + private String internalGetDirtyIndicator(IContainer container) throws CVSException { + try { + return container.getPersistentProperty(IS_DIRTY); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } } /* @@ -1018,35 +1175,56 @@ public class EclipseSynchronizer { * null in that case. For phantom folders, the dirty count is calculated if * it does not exist yet. */ - protected int getDirtyCount(IContainer container) throws CVSException { + protected Integer getDirtyCount(IContainer parent) throws CVSException { + if (!parent.exists()) return null; try { beginOperation(null); - return getLowLevelCacheFor(container).getCachedDirtyCount(container); + return (Integer)parent.getSessionProperty(DIRTY_COUNT); + } catch (CoreException e) { + throw CVSException.wrapException(e); } finally { endOperation(null); } } protected void setDirtyCount(IContainer container, int count) throws CVSException { + if (!container.exists()) return; try { beginOperation(null); - getLowLevelCacheFor(container).setCachedDirtyCount(container, count); + container.setSessionProperty(DIRTY_COUNT, new Integer(count)); + } catch (CoreException e) { + throw CVSException.wrapException(e); } finally { endOperation(null); } } + + /* + * Mark the given existing file as either modified or clean using a session + * property. Also notify the parent to adjust it's modified count. Do + * nothing if the modified state is already what we want. + */ + protected boolean setModified(IFile file, boolean modified) throws CVSException { + String indicator = modified ? IS_DIRTY_INDICATOR : NOT_DIRTY_INDICATOR; + if (getDirtyIndicator(file) == indicator) return false; + setDirtyIndicator(file, indicator); + return true; + } /* - * Mark the given resource as either modified or clean using a persistant - * property. Do nothing if the modified state is already what we want. - * Return true if the modification state was changed. + * Mark the given existing folder as either modified or clean using a + * persistant property. Do nothing if the modified state is already what we + * want. */ - protected boolean setModified(IResource container, boolean modified) throws CVSException { + protected void setModified(IContainer container, boolean modified) throws CVSException { + if (!container.exists()) return; String indicator = modified ? IS_DIRTY_INDICATOR : NOT_DIRTY_INDICATOR; + // if it's already set, no need to set the property or adjust the parents count - if (indicator.equals(getDirtyIndicator(container))) return false; + if (indicator.equals(getDirtyIndicator(container))) return; + // set the dirty indicator and adjust the parent accordingly setDirtyIndicator(container, indicator); - return true; + return; } /* @@ -1054,10 +1232,10 @@ public class EclipseSynchronizer { * parent should be adjusted */ protected boolean adjustModifiedCount(IContainer container, boolean dirty) throws CVSException { - if (container.getType() == IResource.ROOT || !isValid(container)) return false; - int count = getDirtyCount(container); + if (container.getType() == IResource.ROOT) return false; + Integer property = getDirtyCount(container); boolean updateParent = false; - if (count == -1) { + if (property == null) { // The number of dirty children has not been tallied for this parent. // (i.e. no one has queried this folder yet) if (dirty) { @@ -1077,6 +1255,7 @@ public class EclipseSynchronizer { // property is still acurate. } } else { + int count = property.intValue(); if (dirty) { count++; if (count == 1) { @@ -1102,8 +1281,17 @@ public class EclipseSynchronizer { protected boolean addDeletedChild(IContainer container, IFile file) throws CVSException { try { beginOperation(null); - getLowLevelCacheFor(container).addDeletedChild(container, file); + Set deletedFiles = getDeletedChildren(container); + if (deletedFiles == null) + deletedFiles = new HashSet(); + String fileName = file.getName(); + if (deletedFiles.contains(fileName)) + return false; + deletedFiles.add(fileName); + setDeletedChildren(container, deletedFiles); return true; + } catch (CoreException e) { + throw CVSException.wrapException(e); } finally { endOperation(null); } @@ -1112,8 +1300,18 @@ public class EclipseSynchronizer { protected boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { try { beginOperation(null); - getLowLevelCacheFor(container).removeDeletedChild(container, file); + Set deletedFiles = getDeletedChildren(container); + if (deletedFiles == null || deletedFiles.isEmpty()) + return false; + String fileName = file.getName(); + if (!deletedFiles.contains(fileName)) + return false; + deletedFiles.remove(fileName); + if (deletedFiles.isEmpty()) deletedFiles = null; + setDeletedChildren(container, deletedFiles); return true; + } catch (CoreException e) { + throw CVSException.wrapException(e); } finally { endOperation(null); } @@ -1121,49 +1319,76 @@ public class EclipseSynchronizer { protected void setDeletedChildren(IContainer parent, Set deletedFiles) throws CVSException { if (!parent.exists()) return; - sessionPropertyCache.setDeletedChildren(parent, deletedFiles); + try { + parent.setSessionProperty(DELETED_CHILDREN, deletedFiles); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + private Set getDeletedChildren(IContainer parent) throws CoreException { + return (Set)parent.getSessionProperty(DELETED_CHILDREN); + } + /* + * Flush all cached info for the container and it's ancestors + */ + protected void flushModificationCache(IContainer container) throws CVSException { + if (container.getType() == IResource.ROOT) return; + if (container.exists()) { + try { + beginOperation(null); + container.setSessionProperty(DIRTY_COUNT, null); + container.setSessionProperty(DELETED_CHILDREN, null); + container.setPersistentProperty(IS_DIRTY, null); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } finally { + endOperation(null); + } + } } - protected void flushDirtyCache(IResource resource, int depth) throws CVSException { - if (resource.getType() == IResource.ROOT) return; - if (!isValid(resource)) return; + protected void flushModificationCache(IContainer container, int depth) throws CVSException { + if (container.getType() == IResource.ROOT) return; + final CVSException[] exception = new CVSException[] { null }; try { - final CVSException[] exception = new CVSException[] { null }; - beginOperation(null); - resource.accept(new IResourceVisitor() { + container.accept(new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { try { - getLowLevelCacheFor(resource).flushDirtyCache(resource); + if (resource.getType() == IResource.FILE) { + flushModificationCache((IFile)resource); + } else { + flushModificationCache((IContainer)resource); + } } catch (CVSException e) { exception[0] = e; } return true; } }, depth, true); - if (exception[0] != null) { - throw exception[0]; - } } catch (CoreException e) { throw CVSException.wrapException(e); - } finally { - endOperation(null); + } + if (exception[0] != null) { + throw exception[0]; } } - + /* - * Flush all cached info for the file and it's ancestors + * Flush all cached info for + * the file and it's ancestors */ - protected void flushDirtyCacheWithAncestors(IResource resource) throws CVSException { - if (resource.getType() == IResource.ROOT) return; - try { - beginOperation(null); + protected void flushModificationCache(IFile file) throws CVSException { + if (file.exists()) { try { - getLowLevelCacheFor(resource).flushDirtyCache(resource); + beginOperation(null); + file.setSessionProperty(IS_DIRTY, null); + file.setSessionProperty(CLEAN_UPDATE, null); + } catch (CoreException e) { + throw CVSException.wrapException(e); } finally { - flushDirtyCacheWithAncestors(resource.getParent()); + endOperation(null); } - } finally { - endOperation(null); } } @@ -1175,10 +1400,26 @@ public class EclipseSynchronizer { * @param mFile */ public void markFileAsUpdated(IFile file) throws CVSException { - sessionPropertyCache.markFileAsUpdated(file); + try { + file.setSessionProperty(CLEAN_UPDATE, UPDATED_INDICATOR); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } } protected boolean contentsChangedByUpdate(IFile file) throws CVSException { - return sessionPropertyCache.contentsChangedByUpdate(file); + try { + Object indicator = file.getSessionProperty(CLEAN_UPDATE); + boolean updated = false; + if (indicator == UPDATED_INDICATOR) { + // the file was changed due to a clean update (i.e. no local mods) so skip it + file.setSessionProperty(CLEAN_UPDATE, null); + file.setSessionProperty(IS_DIRTY, NOT_DIRTY_INDICATOR); + updated = true; + } + return updated; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java index 6299889c7..e1f6bfb4e 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java @@ -32,6 +32,7 @@ import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.ICVSFile; +import org.eclipse.team.internal.ccvs.core.ICVSResource; /** * This class performs several functions related to determining the modified @@ -185,5 +186,12 @@ public class FileModificationManager implements IResourceChangeListener, ISavePa throw e.toCoreException(); } } + /** + * Method prepareToDelete. + * @param resource + */ + public void prepareToDelete(ICVSResource resource) throws CVSException { + ((EclipseResource)resource).prepareToBeDeleted(); + } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java deleted file mode 100644 index c3ef6b1bf..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html - * - * Contributors: - * IBM - Initial implementation - ******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.resources; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.Status; -import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; -import org.eclipse.team.internal.ccvs.core.Policy; -import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; - -/** - * The low level cache provides the sync info as bytes - */ -/*package*/ abstract class LowLevelSyncInfoCache { - - // the resources plugin synchronizer is used to cache and possibly persist. These - // are keys for storing the sync info. - /*package*/ static final QualifiedName FOLDER_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync"); //$NON-NLS-1$ - /*package*/ static final QualifiedName RESOURCE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync"); //$NON-NLS-1$ - /*package*/ static final QualifiedName IGNORE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-ignore"); //$NON-NLS-1$ - - /*package*/ static final byte[][] EMPTY_RESOURCE_SYNC_INFOS = new byte[0][0]; - - /*package*/ static final QualifiedName IS_DIRTY = new QualifiedName(CVSProviderPlugin.ID, "is-dirty"); - /*package*/ static final QualifiedName CLEAN_UPDATE = new QualifiedName(CVSProviderPlugin.ID, "clean-update"); - /*package*/ static final QualifiedName DIRTY_COUNT = new QualifiedName(CVSProviderPlugin.ID, "dirty-count"); - /*package*/ static final QualifiedName DELETED_CHILDREN = new QualifiedName(CVSProviderPlugin.ID, "deleted"); - /*package*/ static final String IS_DIRTY_INDICATOR = "d"; - /*package*/ static final String NOT_DIRTY_INDICATOR = "c"; - /*package*/ static final String UPDATED_INDICATOR = "u"; - - /*package*/ static final IStatus STATUS_OK = new Status(IStatus.OK, CVSProviderPlugin.ID, 0, Policy.bind("ok"), null); //$NON-NLS-1$ - - /** - * If not already cached, loads and caches the folder sync for the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - * @return the folder sync info for the folder, or null if none. - */ - /*package*/ abstract FolderSyncInfo cacheFolderSync(IContainer container) throws CVSException; - - /** - * Returns the folder sync info for the container; null if none. - * Folder must exist and must not be the workspace root. - * The folder sync info for the container MUST ALREADY BE CACHED. - * - * @param container the container - * @return the folder sync info for the folder, or null if none. - * @see #cacheFolderSync - */ - /*package*/ abstract FolderSyncInfo getCachedFolderSync(IContainer container) throws CVSException; - - /** - * Sets the folder sync info for the container; if null, deletes it. - * Folder must exist and must not be the workspace root. - * The folder sync info for the container need not have previously been - * cached. - * - * @param container the container - * @param info the new folder sync info - */ - /*package*/ abstract void setCachedFolderSync(IContainer container, FolderSyncInfo info) throws CVSException; - - /** - * If not already cached, loads and caches the resource sync for the children of the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - */ - /*package*/ abstract void cacheResourceSyncForChildren(IContainer container) throws CVSException; - - /** - * Returns the resource sync info for all children of the container. - * Container must exist and must not be the workspace root. - * The resource sync info for the children of the container MUST ALREADY BE CACHED. - * - * @param container the container - * @return a collection of the resource sync info's for all children - * @see #cacheResourceSyncForChildren - */ - /*package*/ abstract byte[][] getCachedResourceSyncForChildren(IContainer container) throws CVSException; - - /** - * Sets the resource sync info for the resource; if null, deletes it. Parent - * must exist and must not be the workspace root. The resource sync info for - * the children of the parent container MUST ALREADY BE CACHED. - * - * @param resource the resource - * @param info the new resource sync info - * @see #cacheResourceSyncForChildren - */ - /*package*/ abstract void setCachedResourceSyncForChildren(IContainer container, byte[][] infos) throws CVSException; - - /** - * Commits the cache after a series of operations. - * - * Will return STATUS_OK unless there were problems writting sync - * information to disk. If an error occurs a multistatus is returned - * with the list of reasons for the failures. Failures are recovered, - * and all changed resources are given a chance to be written to disk. - * - * @param monitor the progress monitor, may be null - */ - /*package*/ abstract IStatus commitCache(IProgressMonitor monitor); - - /*package*/ abstract String getDirtyIndicator(IResource resource) throws CVSException; - - /*package*/ abstract void setDirtyIndicator(IResource resource, String indicator) throws CVSException; - - /** - * Return the dirty count for the given folder. For existing folders, the - * dirty count may not have been calculated yet and this method will return - * -1 in that case. - */ - /*package*/ abstract int getCachedDirtyCount(IContainer container) throws CVSException; - - /** - * Set the dirty count for the given container to the given count. - * - * @param container - * @param count - * @throws CVSException - */ - /*package*/ abstract void setCachedDirtyCount(IContainer container, int count) throws CVSException; - - /*package*/ abstract void flushDirtyCache(IResource resource) throws CVSException; - - /*package*/ abstract boolean addDeletedChild(IContainer container, IFile file) throws CVSException; - - /*package*/ abstract boolean removeDeletedChild(IContainer container, IFile file) throws CVSException; - - /*package*/ abstract boolean isSyncInfoLoaded(IContainer parent) throws CVSException; -} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java deleted file mode 100644 index 944fcb34b..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java +++ /dev/null @@ -1,546 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html - * - * Contributors: - * IBM - Initial implementation - ******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.resources; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; -import org.eclipse.team.internal.ccvs.core.CVSStatus; -import org.eclipse.team.internal.ccvs.core.Policy; -import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; -import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; - -/** - * This cache uses session properties to hold the bytes representing the sync - * info - */ -/*package*/ class SessionPropertySyncInfoCache extends LowLevelSyncInfoCache { - - /*package*/ static final String[] NULL_IGNORES = new String[0]; - private static final FolderSyncInfo NULL_FOLDER_SYNC_INFO = new FolderSyncInfo("", "", null, false); //$NON-NLS-1$ //$NON-NLS-2$ - - private Set changedResourceSync = new HashSet(); - private Set changedFolderSync = new HashSet(); - - /** - * If not already cached, loads and caches the folder ignores sync for the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - * @return the folder ignore patterns, or an empty array if none - */ - /*package*/ String[] cacheFolderIgnores(IContainer container) throws CVSException { - try { - // don't try to load if the information is already cached - String[] ignores = (String[])container.getSessionProperty(IGNORE_SYNC_KEY); - if (ignores == null) { - // read folder ignores and remember it - ignores = SyncFileWriter.readCVSIgnoreEntries(container); - if (ignores == null) ignores = NULL_IGNORES; - container.setSessionProperty(IGNORE_SYNC_KEY, ignores); - } - return ignores; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - - /** - * If not already cached, loads and caches the folder sync for the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - * @return the folder sync info for the folder, or null if none. - */ - /*package*/ FolderSyncInfo cacheFolderSync(IContainer container) throws CVSException { - if (!container.exists()) return null; - try { - // don't try to load if the information is already cached - FolderSyncInfo info = (FolderSyncInfo)container.getSessionProperty(FOLDER_SYNC_KEY); - if (info == null) { - // read folder sync info and remember it - info = SyncFileWriter.readFolderSync(container); - if (info == null) { - container.setSessionProperty(FOLDER_SYNC_KEY, NULL_FOLDER_SYNC_INFO); - } else { - container.setSessionProperty(FOLDER_SYNC_KEY, info); - } - } else if (info == NULL_FOLDER_SYNC_INFO) { - info = null; - } - return info; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - - /** - * If not already cached, loads and caches the resource sync for the children of the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - */ - /*package*/ void cacheResourceSyncForChildren(IContainer container) throws CVSException { - if (!container.exists()) return; - try { - // don't try to load if the information is already cached - byte[][] infos = (byte[][])container.getSessionProperty(RESOURCE_SYNC_KEY); - if (infos == null) { - // load the sync info from disk - infos = SyncFileWriter.readAllResourceSync(container); - if (infos == null) { - infos = EMPTY_RESOURCE_SYNC_INFOS; - } - container.setSessionProperty(RESOURCE_SYNC_KEY, infos); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Returns the folder sync info for the container; null if none. - * Folder must exist and must not be the workspace root. - * The folder sync info for the container MUST ALREADY BE CACHED. - * - * @param container the container - * @return the folder sync info for the folder, or null if none. - * @see #cacheFolderSync - */ - /*package*/ FolderSyncInfo getCachedFolderSync(IContainer container) throws CVSException { - if (!container.exists()) return null; - try { - FolderSyncInfo info = (FolderSyncInfo)container.getSessionProperty(FOLDER_SYNC_KEY); - if (info == null) { - // There should be sync info but it was missing. Report the error - throw new CVSException(Policy.bind("EclipseSynchronizer.folderSyncInfoMissing", container.getFullPath().toString())); //$NON-NLS-1$ - } - if (info == NULL_FOLDER_SYNC_INFO) return null; - return info; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Returns the resource sync info for all children of the container. - * Container must exist and must not be the workspace root. - * The resource sync info for the children of the container MUST ALREADY BE CACHED. - * - * @param container the container - * @return a collection of the resource sync info's for all children - * @see #cacheResourceSyncForChildren - */ - /*package*/ byte[][] getCachedResourceSyncForChildren(IContainer container) throws CVSException { - if (!container.exists()) return EMPTY_RESOURCE_SYNC_INFOS; - try { - byte[][] infos = (byte[][])container.getSessionProperty(RESOURCE_SYNC_KEY); - // todo: move check to caller - if (infos == null) { - // There should be sync info but it was missing. Report the error - throw new CVSException(Policy.bind("EclipseSynchronizer.folderSyncInfoMissing", container.getFullPath().toString())); //$NON-NLS-1$ - } - return infos; - } catch(CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Purges the cache recursively for all resources beneath the container. - * There must not be any pending uncommitted changes. - */ - /*package*/ void purgeCache(IContainer container, boolean deep) throws CVSException { - if (! container.exists()) return; - try { - if (container.getType() != IResource.ROOT) { - container.setSessionProperty(RESOURCE_SYNC_KEY, null); - container.setSessionProperty(IGNORE_SYNC_KEY, null); - container.setSessionProperty(FOLDER_SYNC_KEY, null); - } - if(deep) { - IResource[] members = container.members(); - for (int i = 0; i < members.length; i++) { - IResource resource = members[i]; - if (resource.getType() != IResource.FILE) { - purgeCache((IContainer) resource, deep); - } - } - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Sets the array of folder ignore patterns for the container, must not be null. - * Folder must exist and must not be the workspace root. - * - * @param container the container - * @param ignores the array of ignore patterns - */ - /*package*/ void setCachedFolderIgnores(IContainer container, String[] ignores) throws CVSException { - try { - container.setSessionProperty(IGNORE_SYNC_KEY, ignores); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - - /** - * Sets the folder sync info for the container; if null, deletes it. - * Folder must exist and must not be the workspace root. - * The folder sync info for the container need not have previously been cached. - * - * @param container the container - * @param info the new folder sync info - */ - /*package*/ void setCachedFolderSync(IContainer container, FolderSyncInfo info) throws CVSException { - if (!container.exists()) return; - try { - if (info == null) info = NULL_FOLDER_SYNC_INFO; - container.setSessionProperty(FOLDER_SYNC_KEY, info); - changedFolderSync.add(container); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Sets the resource sync info for the resource; if null, deletes it. Parent - * must exist and must not be the workspace root. The resource sync info for - * the children of the parent container MUST ALREADY BE CACHED. - * - * @param resource the resource - * @param info the new resource sync info - * @see #cacheResourceSyncForChildren - */ - /*package*/ void setCachedResourceSyncForChildren(IContainer container, byte[][] infos) throws CVSException { - if (!container.exists()) return; - try { - if (infos == null) - infos = EMPTY_RESOURCE_SYNC_INFOS; - container.setSessionProperty(RESOURCE_SYNC_KEY, infos); - changedResourceSync.add(container); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Commits the cache after a series of operations. - * - * Will return STATUS_OK unless there were problems writting sync - * information to disk. If an error occurs a multistatus is returned - * with the list of reasons for the failures. Failures are recovered, - * and all changed resources are given a chance to be written to disk. - * - * @param monitor the progress monitor, may be null - */ - /*package*/ IStatus commitCache(IProgressMonitor monitor) { - List errors = new ArrayList(); - try { - /*** prepare operation ***/ - // find parents of changed resources - - monitor = Policy.monitorFor(monitor); - int numDirty = changedResourceSync.size(); - int numResources = changedFolderSync.size() + numDirty; - monitor.beginTask(null, numResources); - if(monitor.isCanceled()) { - monitor.subTask(Policy.bind("EclipseSynchronizer.UpdatingSyncEndOperationCancelled")); //$NON-NLS-1$ - } else { - monitor.subTask(Policy.bind("EclipseSynchronizer.UpdatingSyncEndOperation")); //$NON-NLS-1$ - } - - /*** write sync info to disk ***/ - // folder sync info changes - for(Iterator it = changedFolderSync.iterator(); it.hasNext();) { - IContainer folder = (IContainer) it.next(); - if (folder.exists() && folder.getType() != IResource.ROOT) { - try { - FolderSyncInfo info = getCachedFolderSync(folder); - if (info == null) { - // deleted folder sync info since we loaded it - SyncFileWriter.deleteFolderSync(folder); - changedResourceSync.remove(folder); - } else { - // modified or created new folder sync info since we loaded it - SyncFileWriter.writeFolderSync(folder, info); - } - } catch(CVSException e) { - try { - purgeCache(folder, true /* deep */); - } catch(CVSException pe) { - errors.add(pe.getStatus()); - } - errors.add(e.getStatus()); - } - } - monitor.worked(1); - } - - // update progress for parents we will skip because they were deleted - monitor.worked(numDirty - changedResourceSync.size()); - - // resource sync info changes - for (Iterator it = changedResourceSync.iterator(); it.hasNext();) { - IContainer folder = (IContainer) it.next(); - if (folder.exists() && folder.getType() != IResource.ROOT) { - // write sync info for all children in one go - try { - byte[][] infos = getCachedResourceSyncForChildren(folder); - SyncFileWriter.writeAllResourceSync(folder, infos); - } catch(CVSException e) { - try { - purgeCache(folder, false /* depth 1 */); - } catch(CVSException pe) { - errors.add(pe.getStatus()); - } - errors.add(e.getStatus()); - } - } - monitor.worked(1); - } - - /*** broadcast events ***/ - changedResourceSync.clear(); - changedFolderSync.clear(); - if ( ! errors.isEmpty()) { - MultiStatus status = new MultiStatus(CVSProviderPlugin.ID, - CVSStatus.COMMITTING_SYNC_INFO_FAILED, - Policy.bind("EclipseSynchronizer.ErrorCommitting"), //$NON-NLS-1$ - null); - for (int i = 0; i < errors.size(); i++) { - status.merge((IStatus)errors.get(i)); - } - return status; - } - return STATUS_OK; - } finally { - monitor.done(); - } - } - - /*package*/ void setDirtyIndicator(IResource resource, String indicator) throws CVSException { - if (resource.getType() == IResource.FILE) { - internalSetDirtyIndicator((IFile)resource, indicator); - } else { - internalSetDirtyIndicator((IContainer)resource, indicator); - } - } - /*package*/ String getDirtyIndicator(IResource resource) throws CVSException { - if (resource.getType() == IResource.FILE) { - return internalGetDirtyIndicator((IFile)resource); - } else { - return internalGetDirtyIndicator((IContainer)resource); - } - } - private void internalSetDirtyIndicator(IFile file, String indicator) throws CVSException { - try { - file.setSessionProperty(IS_DIRTY, indicator); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - private String internalGetDirtyIndicator(IFile file) throws CVSException { - try { - return (String)file.getSessionProperty(IS_DIRTY); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - private void internalSetDirtyIndicator(IContainer container, String indicator) throws CVSException { - try { - container.setPersistentProperty(IS_DIRTY, indicator); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - private String internalGetDirtyIndicator(IContainer container) throws CVSException { - try { - return container.getPersistentProperty(IS_DIRTY); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Return the dirty count for the given folder. For existing folders, the - * dirty count may not have been calculated yet and this method will return - * null in that case. For phantom folders, the dirty count is calculated if - * it does not exist yet. - */ - /*package*/ int getCachedDirtyCount(IContainer container) throws CVSException { - if (!container.exists()) return -1; - try { - Integer dirtyCount = (Integer)container.getSessionProperty(DIRTY_COUNT); - if (dirtyCount == null) { - return -1; - } else { - return dirtyCount.intValue(); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /*package*/ void setCachedDirtyCount(IContainer container, int count) throws CVSException { - if (!container.exists()) return; - try { - container.setSessionProperty(DIRTY_COUNT, new Integer(count)); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /* - * Flush all cached info for the container and it's ancestors - */ - /*package*/ void flushDirtyCache(IResource resource) throws CVSException { - if (resource.exists()) { - try { - if (resource.getType() == IResource.FILE) { - resource.setSessionProperty(IS_DIRTY, null); - resource.setSessionProperty(CLEAN_UPDATE, null); - } else { - resource.setSessionProperty(DIRTY_COUNT, null); - resource.setSessionProperty(DELETED_CHILDREN, null); - resource.setPersistentProperty(IS_DIRTY, null); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - } - - /* - * Add the deleted child and return true if it didn't exist before - */ - /*package*/ boolean addDeletedChild(IContainer container, IFile file) throws CVSException { - try { - Set deletedFiles = getDeletedChildren(container); - if (deletedFiles == null) - deletedFiles = new HashSet(); - String fileName = file.getName(); - if (deletedFiles.contains(fileName)) - return false; - deletedFiles.add(fileName); - setDeletedChildren(container, deletedFiles); - return true; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /*package*/ boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { - try { - Set deletedFiles = getDeletedChildren(container); - if (deletedFiles == null || deletedFiles.isEmpty()) - return false; - String fileName = file.getName(); - if (!deletedFiles.contains(fileName)) - return false; - deletedFiles.remove(fileName); - if (deletedFiles.isEmpty()) deletedFiles = null; - setDeletedChildren(container, deletedFiles); - return true; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - protected void setDeletedChildren(IContainer parent, Set deletedFiles) throws CVSException { - if (!parent.exists()) return; - try { - parent.setSessionProperty(DELETED_CHILDREN, deletedFiles); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - private Set getDeletedChildren(IContainer parent) throws CoreException { - if (!parent.exists()) return null; - return (Set)parent.getSessionProperty(DELETED_CHILDREN); - } - - /** - * Method updated flags the objetc as having been modfied by the updated - * handler. This flag is read during the resource delta to determine whether - * the modification made the file dirty or not. - * - * @param mFile - */ - /*package*/ void markFileAsUpdated(IFile file) throws CVSException { - try { - file.setSessionProperty(CLEAN_UPDATE, UPDATED_INDICATOR); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /*package*/ boolean contentsChangedByUpdate(IFile file) throws CVSException { - try { - Object indicator = file.getSessionProperty(CLEAN_UPDATE); - boolean updated = false; - if (indicator == UPDATED_INDICATOR) { - // the file was changed due to a clean update (i.e. no local mods) so skip it - file.setSessionProperty(CLEAN_UPDATE, null); - file.setSessionProperty(IS_DIRTY, NOT_DIRTY_INDICATOR); - updated = true; - } - return updated; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Method isSyncInfoLoaded returns true if all the sync info for the - * provided resources is loaded into the internal cache. - * - * @param resources - * @param i - * @return boolean - */ - /*package*/ boolean isSyncInfoLoaded(IContainer parent) throws CVSException { - try { - if (parent.getFolder(new Path(SyncFileWriter.CVS_DIRNAME)).exists()) { - if (parent.getSessionProperty(RESOURCE_SYNC_KEY) == null) - return false; - if (parent.getSessionProperty(FOLDER_SYNC_KEY) == null) - return false; - if (parent.getSessionProperty(IGNORE_SYNC_KEY) == null) - return false; - } - } catch (CoreException e) { - // let future operations surface the error - return false; - } - return true; - } -} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java deleted file mode 100644 index 21c3b66b1..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java +++ /dev/null @@ -1,478 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html - * - * Contributors: - * IBM - Initial implementation - ******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.resources; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ISynchronizer; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.ICVSFolder; -import org.eclipse.team.internal.ccvs.core.ICVSResource; -import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; -import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; -import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; - -/** - * This cache uses session properties to hold the bytes representing the sync - * info - */ -/*package*/ class SynchronizerSyncInfoCache extends LowLevelSyncInfoCache { - - public SynchronizerSyncInfoCache() { - getWorkspaceSynchronizer().add(FOLDER_SYNC_KEY); - getWorkspaceSynchronizer().add(RESOURCE_SYNC_KEY); - getWorkspaceSynchronizer().add(DIRTY_COUNT); - } - /** - * Return the Eclipse Workspace Synchronizer (from org.eclipse.core.resources) - */ - private ISynchronizer getWorkspaceSynchronizer() { - return ResourcesPlugin.getWorkspace().getSynchronizer(); - } - - /** - * Convert a FolderSyncInfo into a byte array that can be stored - * in the workspace synchronizer - */ - private byte[] getBytes(FolderSyncInfo info) throws CVSException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(out); - try { - dos.writeUTF(info.getRoot()); - dos.writeUTF(info.getRepository()); - CVSEntryLineTag tag = info.getTag(); - if (tag == null) { - dos.writeUTF(""); //$NON-NLS-1$ - } else { - dos.writeUTF(tag.toString()); - } - dos.writeBoolean(info.getIsStatic()); - dos.close(); - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return out.toByteArray(); - } - - /** - * Convert a byte array that was created using getBytes(FolderSyncInfo) - * into a FolderSyncInfo - */ - private FolderSyncInfo getFolderSyncInfo(byte[] bytes) throws CVSException { - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - DataInputStream dis = new DataInputStream(in); - String root; - String repository; - CVSEntryLineTag tag; - boolean isStatic; - try { - root = dis.readUTF(); - repository = dis.readUTF(); - String tagName = dis.readUTF(); - if (tagName.length() == 0) { - tag = null; - } else { - tag = new CVSEntryLineTag(tagName); - } - isStatic = dis.readBoolean(); - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return new FolderSyncInfo(repository, root, tag, isStatic); - } - - /** - * Method getBytes converts an array of bytes into a single byte array - * @param infos - * @return byte[] - */ - private byte[] getBytes(byte[][] infos) throws CVSException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - SyncFileWriter.writeLines(out, infos); - return out.toByteArray(); - } - - /** - * Convert a byte array that was created using getBytes(Map) - * into a Map of ResourceSyncInfo - */ - private byte[][] getResourceSyncInfo(byte[] bytes) throws CVSException { - byte[][] infos = SyncFileWriter.readLines(new ByteArrayInputStream(bytes)); - // check to make sure the info is not stored in the old format - if (infos.length != 0) { - byte[] firstLine = infos[0]; - if (firstLine.length != 0 && (firstLine[0] != (byte)'/' && firstLine[0] != (byte)'D')) { - Map oldInfos = getResourceSyncInfoMap(bytes); - infos = new byte[oldInfos.size()][]; - int i = 0; - for (Iterator iter = oldInfos.values().iterator(); iter.hasNext();) { - ResourceSyncInfo element = (ResourceSyncInfo) iter.next(); - infos[i++] = element.getBytes(); - } - // We can't convert the info to the new format because the caller - // may either not be in a workspace runnable or the resource tree - // may be closed for modification - } - } - return infos; - } - - /** - * ResourceSyncInfo used to be stored as a Map of ResourceSyncInfo. - * We need to be able to retrieve that info the way it was and - * convert it to the new way. - * - * Convert a byte array that was created using - * getBytes(Map) into a Map of ResourceSyncInfo - */ - private Map getResourceSyncInfoMap(byte[] bytes) throws CVSException { - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - DataInputStream dis = new DataInputStream(in); - Map result = new HashMap(); - try { - int size = dis.readInt(); - for (int i = 0; i < size; i++) { - ResourceSyncInfo info = new ResourceSyncInfo(dis.readUTF(), null, null); - result.put(info.getName(), info); - } - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return result; - } - - /** - * Flush any info cahced for the folder - */ - private void flushPhantomInfo(IContainer container) throws CVSException { - try { - if (container.exists() || container.isPhantom()) { - getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_ZERO); - } - if (container.exists() || container.isPhantom()) { - getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, container, IResource.DEPTH_ZERO); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /*package*/ void flush(IProject project) throws CVSException { - try { - getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, project, IResource.DEPTH_INFINITE); - getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, project, IResource.DEPTH_INFINITE); - getWorkspaceSynchronizer().flushSyncInfo(DIRTY_COUNT, project, IResource.DEPTH_INFINITE); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Method flush. - * @param folder - */ - /*package*/ void flush(IFolder folder) throws CVSException { - flushPhantomInfo(folder); - } - - /** - * If not already cached, loads and caches the folder sync for the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - * @return the folder sync info for the folder, or null if none. - */ - /*package*/ FolderSyncInfo cacheFolderSync(IContainer container) throws CVSException { - // nothing needs to be done since the synchronizer is persisted - return getCachedFolderSync(container); - } - - /** - * Returns the folder sync info for the container; null if none. - * Folder must exist and must not be the workspace root. - * The folder sync info for the container MUST ALREADY BE CACHED. - * - * @param container the container - * @return the folder sync info for the folder, or null if none. - * @see #cacheFolderSync - */ - /*package*/ FolderSyncInfo getCachedFolderSync(IContainer container) throws CVSException { - try { - byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(FOLDER_SYNC_KEY, container); - if (bytes == null) return null; - return getFolderSyncInfo(bytes); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Sets the folder sync info for the container; if null, deletes it. - * Folder must exist and must not be the workspace root. - * The folder sync info for the container need not have previously been - * cached. - * - * @param container the container - * @param info the new folder sync info - */ - /*package*/ void setCachedFolderSync(IContainer container, FolderSyncInfo info) throws CVSException { - try { - if (info == null) { - if (container.exists() || container.isPhantom()) { - getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_ZERO); - } - } else { - getWorkspaceSynchronizer().setSyncInfo(FOLDER_SYNC_KEY, container, getBytes(info)); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * If not already cached, loads and caches the resource sync for the children of the container. - * Folder must exist and must not be the workspace root. - * - * @param container the container - */ - /*package*/ void cacheResourceSyncForChildren(IContainer container) throws CVSException { - // nothing needs to be done since the synchronizer is persisted - } - - /** - * Returns the resource sync info for all children of the container. - * Container must exist and must not be the workspace root. - * The resource sync info for the children of the container MUST ALREADY BE CACHED. - * - * @param container the container - * @return a collection of the resource sync info's for all children - * @see #cacheResourceSyncForChildren - */ - /*package*/ byte[][] getCachedResourceSyncForChildren(IContainer container) throws CVSException { - try { - byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(RESOURCE_SYNC_KEY, container); - if (bytes == null) return null; - return getResourceSyncInfo(bytes); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Sets the resource sync info for the resource; if null, deletes it. Parent - * must exist and must not be the workspace root. The resource sync info for - * the children of the parent container MUST ALREADY BE CACHED. - * - * @param resource the resource - * @param info the new resource sync info - * @see #cacheResourceSyncForChildren - */ - /*package*/ void setCachedResourceSyncForChildren(IContainer container, byte[][] infos) throws CVSException { - try { - if (infos == null) { - if (container.exists() || container.isPhantom()) { - getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, container, IResource.DEPTH_ZERO); - } - } else { - getWorkspaceSynchronizer().setSyncInfo(RESOURCE_SYNC_KEY, container, getBytes(infos)); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * @see org.eclipse.team.internal.ccvs.core.resources.LowLevelSyncInfoCache#commitCache(org.eclipse.core.runtime.IProgressMonitor) - */ - IStatus commitCache(IProgressMonitor monitor) { - // Nothing needs to be done since the synchronizer is persisted - return STATUS_OK; - } - - /** - * @see org.eclipse.team.internal.ccvs.core.resources.LowLevelSyncInfoCache#getDirtyIndicator(org.eclipse.core.resources.IResource) - */ - String getDirtyIndicator(IResource resource) throws CVSException { - if (resource.getType() == IResource.FILE) { - // if someone is asking about a non-existant file, it's probably dirty - return IS_DIRTY_INDICATOR; - } else { - int dirtyCount = getCachedDirtyCount((IContainer)resource); - switch (dirtyCount) { - case -1 : - return null; - case 0 : - return NOT_DIRTY_INDICATOR; - default : - return IS_DIRTY_INDICATOR; - } - } - } - /** - * @see org.eclipse.team.internal.ccvs.core.resources.LowLevelSyncInfoCache#setDirtyIndicator(org.eclipse.core.resources.IResource, java.lang.String) - */ - void setDirtyIndicator(IResource resource, String indicator) throws CVSException { - // The count is used as the indicator - } - - /** - * Return the dirty count for the given folder. For existing folders, the - * dirty count may not have been calculated yet and this method will return - * null in that case. For phantom folders, the dirty count is calculated if - * it does not exist yet. - */ - /*package*/ int getCachedDirtyCount(IContainer container) throws CVSException { - // get the count from the synchronizer - int count = internalGetDirtyCount(container); - if (count == -1) { - count = calculateDirtyCountForPhantom(container); - //setDirtyCount(parent, count); - } - return count; - } - - /** - * Set the dirty count for the given container to the given count. - * - * @param container - * @param count - * @throws CVSException - */ - /*package*/ void setCachedDirtyCount(IContainer container, int count) throws CVSException { - try { - getWorkspaceSynchronizer().setSyncInfo(DIRTY_COUNT, container, getBytes(count)); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /* - * Convert an int to a byte array - */ - private byte[] getBytes(int count) { - byte[] result = new byte[4]; - result[0] = (byte)(count & 256); - result[1] = (byte)(count<<8 & 256); - result[1] = (byte)(count<<16 & 256); - result[1] = (byte)(count<<24 & 256); - return result; - } - - /* - * Convert a byte array to an int - */ - private int intFromBytes(byte[] bytes) { - return bytes[0] + (bytes[1]>>8) + (bytes[2]>>16) + (bytes[3]>>24); - } - - private int internalGetDirtyCount(IContainer parent) throws CVSException { - try { - byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(DIRTY_COUNT, parent); - if (bytes == null) return -1; - return intFromBytes(bytes); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /* - * Calculate the dirty count for the given phantom folder, performing any - * necessary calculations on the childen as well - */ - private int calculateDirtyCountForPhantom(IContainer parent) throws CVSException { - ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(parent); - ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS | ICVSFolder.PHANTOM_MEMBERS); - int count = 0; - for (int i = 0; i < children.length; i++) { - ICVSResource resource = children[i]; - if (resource.isFolder()) { - int dc = getCachedDirtyCount((IContainer)resource.getIResource()); - if (dc > 0) count++; - } else { - // Any non-existant managed files are dirty (outgoing deletion) - count++; - } - } - return count; - } - - /*package*/ void flushDirtyCache(IResource container) throws CVSException { -// if (container.exists() || container.isPhantom()) { -// try { -// getWorkspaceSynchronizer().flushSyncInfo(DIRTY_COUNT, container, IResource.DEPTH_ZERO); -// } catch (CoreException e) { -// throw CVSException.wrapException(e); -// } -// } - } - - /** - * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#addDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) - */ - protected boolean addDeletedChild(IContainer container, IFile file) throws CVSException { -// try { -// beginOperation(null); -// int oldCount = internalGetDirtyCount(container); -// if (oldCount == -1) { -// // there is no cached count so wait until the first query -// // or there was no deleted file -// return false; -// } -// int newCount = calculateDirtyCountForPhantom(container); -// // adjust the parent folder count if the newCount is 1; -// return oldCount == 0 && newCount == 1; -// } finally { -// endOperation(null); -// } - return true; - } - - /** - * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#removeDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) - */ - protected boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { -// try { -// beginOperation(null); -// int oldCount = internalGetDirtyCount(container); -// if (oldCount == -1 || oldCount == 0) { -// // there is no cached count so wait until the first query -// // or there was no deleted file -// return false; -// } -// int newCount = calculateDirtyCountForPhantom(container); -// // adjust the parent folder count if the newCount is 0; -// return newCount == 0; -// } finally { -// endOperation(null); -// } - return true; - } - - /*package*/ boolean isSyncInfoLoaded(IContainer parent) throws CVSException { - return true; - } -} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java index dc5a13352..1bfcbdbeb 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java @@ -86,10 +86,6 @@ public class ResourceSyncInfo { protected ResourceSyncInfo() { } - public ResourceSyncInfo(byte[] entryLine) throws CVSException { - this(new String(entryLine), null, null); - } - /** * Constructor to create a sync object from entry line formats. The entry lines are parsed by this class. * The constructor can handle parsing entry lines from the server or from an entry file. @@ -526,12 +522,4 @@ public class ResourceSyncInfo { public void reported() { // do nothing } - - /** - * Method getBytes. - * @return byte[] - */ - public byte[] getBytes() { - return getEntryLine().getBytes(); - } } \ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java index e9eb16031..865f3db0f 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java @@ -386,6 +386,6 @@ public class MoveDeleteHook implements IMoveDeleteHook { * dirty count of it's parent can be reduced if appropriate. */ private void prepareToDelete(ICVSResource resource) throws CVSException { - EclipseSynchronizer.getInstance().prepareForDeletion(resource.getIResource()); + CVSProviderPlugin.getPlugin().getFileModificationManager().prepareToDelete(resource); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java index b834767e5..3fad8de16 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java @@ -9,11 +9,9 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -92,7 +90,7 @@ public class SyncFileWriter { * specified folder and returns ResourceSyncInfo instances for the data stored therein. * If the folder does not have a CVS subdirectory then null is returned. */ - public static byte[][] readAllResourceSync(IContainer parent) throws CVSException { + public static ResourceSyncInfo[] readAllResourceSync(IContainer parent) throws CVSException { IFolder cvsSubDir = getCVSSubdirectory(parent); if (! cvsSubDir.exists()) return null; @@ -125,14 +123,7 @@ public class SyncFileWriter { } } - //return (ResourceSyncInfo[])infos.values().toArray(new ResourceSyncInfo[infos.size()]); - byte[][] result = new byte[infos.size()][]; - int i = 0; - for (Iterator iter = infos.values().iterator(); iter.hasNext();) { - ResourceSyncInfo info = (ResourceSyncInfo) iter.next(); - result[i++] = info.getBytes(); - } - return result; + return (ResourceSyncInfo[])infos.values().toArray(new ResourceSyncInfo[infos.size()]); } /** @@ -160,27 +151,7 @@ public class SyncFileWriter { throw CVSException.wrapException(e); } } - - public static void writeAllResourceSync(IContainer parent, byte[][] infos) throws CVSException { - try { - IFolder cvsSubDir = createCVSSubdirectory(parent); - - // format file contents - String[] entries = new String[infos.length]; - for (int i = 0; i < infos.length; i++) { - byte[] info = infos[i]; - entries[i] = new String(info); - } - - // write Entries - writeLines(cvsSubDir.getFile(ENTRIES), entries); - - // delete Entries.log - cvsSubDir.getFile(ENTRIES_LOG).delete(IResource.NONE, null); - } catch(CoreException e) { - throw CVSException.wrapException(e); - } - } + /** * Reads the CVS/Root, CVS/Repository, CVS/Tag, and CVS/Entries.static files from * the specified folder and returns a FolderSyncInfo instance for the data stored therein. @@ -469,28 +440,6 @@ public class SyncFileWriter { } } - /* - * Reads all lines of the specified file. - * Returns null if the file does not exist. - */ - public static byte[][] readLines(InputStream stream) throws CVSException { - try { - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - List fileContentStore = new ArrayList(); - try { - String line; - while ((line = reader.readLine()) != null) { - fileContentStore.add(line.getBytes()); - } - return (byte[][]) fileContentStore.toArray(new byte[fileContentStore.size()][]); - } finally { - reader.close(); - } - } catch (IOException e) { - throw CVSException.wrapException(e); - } - } - /* * Writes all lines to the specified file, using linefeed terminators for * compatibility with other CVS clients. @@ -536,22 +485,6 @@ public class SyncFileWriter { throw CVSException.wrapException(e); } } - - public static void writeLines(OutputStream os, byte[][] contents) throws CVSException { - try { - try { - for (int i = 0; i < contents.length; i++) { - os.write(contents[i]); - os.write(0x0A); // newline byte - } - } finally { - os.close(); - } - } catch (IOException e) { - throw CVSException.wrapException(e); - } - } - /** * Method writeFileToBaseDirectory. * diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java index 360034080..f948ef0d0 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/Util.java @@ -240,16 +240,4 @@ public class Util { result.add(next); return (String[]) result.toArray(new String[result.size()]); } - - public static String getSubstring(byte[] bytes, byte delimiter, int index, boolean includeRest) { - String string = new String(bytes); - int start = 0; - for (int i = 0; i < index; i++) { - start = string.indexOf(delimiter, start); - if (start == -1) return null; - } - int end = string.indexOf(delimiter, start); - if (end == -1 || includeRest) return string.substring(start + 1); - return string.substring(start + 1, end); - } } \ No newline at end of file -- cgit v1.2.3