KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > localstore > HistoryStore2


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.localstore;
12
13 import java.io.InputStream JavaDoc;
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             // make effective all changes collected
44
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             // we may be copying to the same source bucket, collect to make change effective later
58
// since we cannot make changes to it while iterating
59
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             //ignore the failure here because there is no way to surface it.
75
//any attempt to write to the store will throw an appropriate exception
76
}
77         this.blobStore = new BlobStore(store, limit);
78         this.tree = new BucketTree(workspace, new HistoryBucket());
79     }
80
81     /**
82      * @see IHistoryStore#addState(IPath, IFileStore, IFileInfo, boolean)
83      */

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()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
88
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             // currentBucket.save();
97
} 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     /**
119      * Applies the clean-up policy to an entry.
120      */

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             // "delete" the current uuid
126
blobsToRemove.add(fileEntry.getUUID(i));
127             fileEntry.deleteOccurrence(i);
128         }
129     }
130
131     /**
132      * Applies the clean-up policy to a subtree.
133      */

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         // apply policy to the given tree
139
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."); //$NON-NLS-1$ //$NON-NLS-2$
164
Policy.debug("Total number of history store entries: " + entryCount[0]); //$NON-NLS-1$
165
}
166             start = System.currentTimeMillis();
167             // remove unreferenced blobs
168
blobStore.deleteBlobs(blobsToRemove);
169             if (Policy.DEBUG_HISTORY)
170                 Policy.debug("Time to remove " + blobsToRemove.size() + " unreferenced blobs: " + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
171
blobsToRemove = new HashSet();
172         } catch (Exception JavaDoc e) {
173             String JavaDoc message = Messages.history_problemsCleaning;
174             ResourceStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, null, message, e);
175             Policy.log(status);
176         }
177     }
178
179     /* (non-Javadoc)
180      * @see org.eclipse.core.internal.localstore.IHistoryStore#closeHistory(org.eclipse.core.resources.IResource)
181      */

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     /*
192      * (non-Javadoc)
193      * @see org.eclipse.core.internal.localstore.IHistoryStore#copyHistory(org.eclipse.core.resources.IResource, org.eclipse.core.resources.IResource, boolean)
194      */

195     public synchronized void copyHistory(IResource sourceResource, IResource destinationResource, boolean moving) {
196         // return early if either of the paths are null or if the source and
197
// destination are the same.
198
if (sourceResource == null || destinationResource == null) {
199             String JavaDoc 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 JavaDoc 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             // special case: we are moving a project
219
if (moving && sourceResource.getType() == IResource.PROJECT) {
220                 // flush the tree to avoid confusion if another project is created with the same name
221
final Bucket bucket = tree.getCurrent();
222                 bucket.save();
223                 bucket.flush();
224                 return;
225             }
226             // copy history by visiting the source tree
227
HistoryCopyVisitor copyVisitor = new HistoryCopyVisitor(source, destination);
228             tree.accept(copyVisitor, source, BucketTree.DEPTH_INFINITE);
229             // apply clean-up policy to the destination tree
230
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 JavaDoc getContents(IFileState target) throws CoreException {
241         if (!target.exists()) {
242             String JavaDoc 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     /**
270      * Return a boolean value indicating whether or not the given file
271      * should be added to the history store based on the current history
272      * store policies.
273      *
274      * @param localFile the file to check
275      * @return <code>true</code> if this file should be added to the history
276      * store and <code>false</code> otherwise
277      */

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() + //$NON-NLS-1$
284
", size: " + length + //$NON-NLS-1$
285
", max: " + description.getMaxFileStateSize()); //$NON-NLS-1$
286
return result;
287     }
288
289     /**
290      * Logs a CoreException
291      */

292     private void log(CoreException e) {
293         //create a new status to wrap the exception if there is no exception in the status
294
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); //$NON-NLS-1$
297
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                         // remember we need to delete the files later
307
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     /**
318      * @see IHistoryStore#removeGarbage()
319      */

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                         // remember we need to delete the files later
327
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 JavaDoc e) {
334             String JavaDoc 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         // nothing to be done
346
}
347 }
348
Popular Tags