1 11 package org.eclipse.core.internal.localstore; 12 13 import java.io.InputStream ; 14 import java.util.*; 15 import org.eclipse.core.filesystem.*; 16 import org.eclipse.core.internal.localstore.Bucket.Entry; 17 import org.eclipse.core.internal.localstore.HistoryBucket.HistoryEntry; 18 import org.eclipse.core.internal.resources.*; 19 import org.eclipse.core.internal.utils.*; 20 import org.eclipse.core.resources.*; 21 import org.eclipse.core.runtime.*; 22 23 public class HistoryStore2 implements IHistoryStore { 24 25 class HistoryCopyVisitor extends Bucket.Visitor { 26 private List changes = new ArrayList(); 27 private IPath destination; 28 private IPath source; 29 30 public HistoryCopyVisitor(IPath source, IPath destination) { 31 this.source = source; 32 this.destination = destination; 33 } 34 35 public void afterSaving(Bucket bucket) throws CoreException { 36 saveChanges(); 37 changes.clear(); 38 } 39 40 private void saveChanges() throws CoreException { 41 if (changes.isEmpty()) 42 return; 43 Iterator i = changes.iterator(); 45 HistoryEntry entry = (HistoryEntry) i.next(); 46 tree.loadBucketFor(entry.getPath()); 47 HistoryBucket bucket = (HistoryBucket) tree.getCurrent(); 48 bucket.addBlobs(entry); 49 while (i.hasNext()) 50 bucket.addBlobs((HistoryEntry) i.next()); 51 bucket.save(); 52 } 53 54 public int visit(Entry sourceEntry) { 55 IPath destinationPath = destination.append(sourceEntry.getPath().removeFirstSegments(source.segmentCount())); 56 HistoryEntry destinationEntry = new HistoryEntry(destinationPath, (HistoryEntry) sourceEntry); 57 changes.add(destinationEntry); 60 return CONTINUE; 61 } 62 } 63 64 private BlobStore blobStore; 65 private Set blobsToRemove = new HashSet(); 66 final BucketTree tree; 67 private Workspace workspace; 68 69 public HistoryStore2(Workspace workspace, IFileStore store, int limit) { 70 this.workspace = workspace; 71 try { 72 store.mkdir(EFS.NONE, null); 73 } catch (CoreException e) { 74 } 77 this.blobStore = new BlobStore(store, limit); 78 this.tree = new BucketTree(workspace, new HistoryBucket()); 79 } 80 81 84 public synchronized IFileState addState(IPath key, IFileStore localFile, IFileInfo info, boolean moveContents) { 85 long lastModified = info.getLastModified(); 86 if (Policy.DEBUG_HISTORY) 87 System.out.println("History: Adding state for key: " + key + ", file: " + localFile + ", timestamp: " + lastModified + ", size: " + localFile.fetchInfo().getLength()); if (!isValid(localFile, info)) 89 return null; 90 UniversalUniqueIdentifier uuid = null; 91 try { 92 uuid = blobStore.addBlob(localFile, moveContents); 93 tree.loadBucketFor(key); 94 HistoryBucket currentBucket = (HistoryBucket) tree.getCurrent(); 95 currentBucket.addBlob(key, uuid, lastModified); 96 } catch (CoreException e) { 98 log(e); 99 } 100 return new FileState(this, key, lastModified, uuid); 101 } 102 103 public synchronized Set allFiles(IPath root, int depth, IProgressMonitor monitor) { 104 final Set allFiles = new HashSet(); 105 try { 106 tree.accept(new Bucket.Visitor() { 107 public int visit(Entry fileEntry) { 108 allFiles.add(fileEntry.getPath()); 109 return CONTINUE; 110 } 111 }, root, depth == IResource.DEPTH_INFINITE ? BucketTree.DEPTH_INFINITE : depth); 112 } catch (CoreException e) { 113 log(e); 114 } 115 return allFiles; 116 } 117 118 121 protected void applyPolicy(HistoryEntry fileEntry, int maxStates, long minTimeStamp) { 122 for (int i = 0; i < fileEntry.getOccurrences(); i++) { 123 if (i < maxStates && fileEntry.getTimestamp(i) >= minTimeStamp) 124 continue; 125 blobsToRemove.add(fileEntry.getUUID(i)); 127 fileEntry.deleteOccurrence(i); 128 } 129 } 130 131 134 private void applyPolicy(IPath root) throws CoreException { 135 IWorkspaceDescription description = workspace.internalGetDescription(); 136 final long minimumTimestamp = System.currentTimeMillis() - description.getFileStateLongevity(); 137 final int maxStates = description.getMaxFileStates(); 138 tree.accept(new Bucket.Visitor() { 140 public int visit(Entry entry) { 141 applyPolicy((HistoryEntry) entry, maxStates, minimumTimestamp); 142 return CONTINUE; 143 } 144 }, root, BucketTree.DEPTH_INFINITE); 145 tree.getCurrent().save(); 146 } 147 148 public synchronized void clean(IProgressMonitor monitor) { 149 long start = System.currentTimeMillis(); 150 try { 151 IWorkspaceDescription description = workspace.internalGetDescription(); 152 final long minimumTimestamp = System.currentTimeMillis() - description.getFileStateLongevity(); 153 final int maxStates = description.getMaxFileStates(); 154 final int[] entryCount = new int[1]; 155 tree.accept(new Bucket.Visitor() { 156 public int visit(Entry fileEntry) { 157 entryCount[0] += fileEntry.getOccurrences(); 158 applyPolicy((HistoryEntry) fileEntry, maxStates, minimumTimestamp); 159 return CONTINUE; 160 } 161 }, Path.ROOT, BucketTree.DEPTH_INFINITE); 162 if (Policy.DEBUG_HISTORY) { 163 Policy.debug("Time to apply history store policies: " + (System.currentTimeMillis() - start) + "ms."); Policy.debug("Total number of history store entries: " + entryCount[0]); } 166 start = System.currentTimeMillis(); 167 blobStore.deleteBlobs(blobsToRemove); 169 if (Policy.DEBUG_HISTORY) 170 Policy.debug("Time to remove " + blobsToRemove.size() + " unreferenced blobs: " + (System.currentTimeMillis() - start) + "ms."); blobsToRemove = new HashSet(); 172 } catch (Exception e) { 173 String message = Messages.history_problemsCleaning; 174 ResourceStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, null, message, e); 175 Policy.log(status); 176 } 177 } 178 179 182 public void closeHistoryStore(IResource resource) { 183 try { 184 tree.getCurrent().save(); 185 tree.getCurrent().flush(); 186 } catch (CoreException e) { 187 log(e); 188 } 189 } 190 191 195 public synchronized void copyHistory(IResource sourceResource, IResource destinationResource, boolean moving) { 196 if (sourceResource == null || destinationResource == null) { 199 String message = Messages.history_copyToNull; 200 ResourceStatus status = new ResourceStatus(IResourceStatus.INTERNAL_ERROR, null, message, null); 201 Policy.log(status); 202 return; 203 } 204 if (sourceResource.equals(destinationResource)) { 205 String message = Messages.history_copyToSelf; 206 ResourceStatus status = new ResourceStatus(IResourceStatus.INTERNAL_ERROR, sourceResource.getFullPath(), message, null); 207 Policy.log(status); 208 return; 209 } 210 211 final IPath source = sourceResource.getFullPath(); 212 final IPath destination = destinationResource.getFullPath(); 213 Assert.isLegal(source.segmentCount() > 0); 214 Assert.isLegal(destination.segmentCount() > 0); 215 Assert.isLegal(source.segmentCount() > 1 || destination.segmentCount() == 1); 216 217 try { 218 if (moving && sourceResource.getType() == IResource.PROJECT) { 220 final Bucket bucket = tree.getCurrent(); 222 bucket.save(); 223 bucket.flush(); 224 return; 225 } 226 HistoryCopyVisitor copyVisitor = new HistoryCopyVisitor(source, destination); 228 tree.accept(copyVisitor, source, BucketTree.DEPTH_INFINITE); 229 applyPolicy(destinationResource.getFullPath()); 231 } catch (CoreException e) { 232 log(e); 233 } 234 } 235 236 public boolean exists(IFileState target) { 237 return blobStore.fileFor(((FileState) target).getUUID()).fetchInfo().exists(); 238 } 239 240 public InputStream getContents(IFileState target) throws CoreException { 241 if (!target.exists()) { 242 String message = Messages.history_notValid; 243 throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, target.getFullPath(), message, null); 244 } 245 return blobStore.getBlob(((FileState) target).getUUID()); 246 } 247 248 public synchronized IFileState[] getStates(IPath filePath, IProgressMonitor monitor) { 249 try { 250 tree.loadBucketFor(filePath); 251 HistoryBucket currentBucket = (HistoryBucket) tree.getCurrent(); 252 HistoryEntry fileEntry = currentBucket.getEntry(filePath); 253 if (fileEntry == null || fileEntry.isEmpty()) 254 return new IFileState[0]; 255 IFileState[] states = new IFileState[fileEntry.getOccurrences()]; 256 for (int i = 0; i < states.length; i++) 257 states[i] = new FileState(this, fileEntry.getPath(), fileEntry.getTimestamp(i), fileEntry.getUUID(i)); 258 return states; 259 } catch (CoreException ce) { 260 log(ce); 261 return new IFileState[0]; 262 } 263 } 264 265 public BucketTree getTree() { 266 return tree; 267 } 268 269 278 private boolean isValid(IFileStore localFile, IFileInfo info) { 279 WorkspaceDescription description = workspace.internalGetDescription(); 280 long length = info.getLength(); 281 boolean result = length <= description.getMaxFileStateSize(); 282 if (Policy.DEBUG_HISTORY && !result) 283 System.out.println("History: Ignoring file (too large). File: " + localFile.toString() + ", size: " + length + ", max: " + description.getMaxFileStateSize()); return result; 287 } 288 289 292 private void log(CoreException e) { 293 IStatus status = e.getStatus(); 295 if (status.getException() == null) 296 status = new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_WRITE_METADATA, "Internal error in history store", e); Policy.log(status); 298 } 299 300 public synchronized void remove(IPath root, IProgressMonitor monitor) { 301 try { 302 final Set tmpBlobsToRemove = blobsToRemove; 303 tree.accept(new Bucket.Visitor() { 304 public int visit(Entry fileEntry) { 305 for (int i = 0; i < fileEntry.getOccurrences(); i++) 306 tmpBlobsToRemove.add(((HistoryEntry) fileEntry).getUUID(i)); 308 fileEntry.delete(); 309 return CONTINUE; 310 } 311 }, root, BucketTree.DEPTH_INFINITE); 312 } catch (CoreException ce) { 313 log(ce); 314 } 315 } 316 317 320 public synchronized void removeGarbage() { 321 try { 322 final Set tmpBlobsToRemove = blobsToRemove; 323 tree.accept(new Bucket.Visitor() { 324 public int visit(Entry fileEntry) { 325 for (int i = 0; i < fileEntry.getOccurrences(); i++) 326 tmpBlobsToRemove.remove(((HistoryEntry) fileEntry).getUUID(i)); 328 return CONTINUE; 329 } 330 }, Path.ROOT, BucketTree.DEPTH_INFINITE); 331 blobStore.deleteBlobs(blobsToRemove); 332 blobsToRemove = new HashSet(); 333 } catch (Exception e) { 334 String message = Messages.history_problemsCleaning; 335 ResourceStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, null, message, e); 336 Policy.log(status); 337 } 338 } 339 340 public synchronized void shutdown(IProgressMonitor monitor) throws CoreException { 341 tree.close(); 342 } 343 344 public void startup(IProgressMonitor monitor) { 345 } 347 } 348 | Popular Tags |