Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 36958 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/core/internal/localstore/HistoryStore.java (-12 / +227 lines)
Lines 12-32 Link Here
12
12
13
import java.io.File;
13
import java.io.File;
14
import java.io.InputStream;
14
import java.io.InputStream;
15
import java.util.*;
15
import java.util.ArrayList;
16
import org.eclipse.core.internal.indexing.*;
16
import java.util.Date;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.LinkedList;
20
import java.util.List;
21
import java.util.Set;
22
23
import org.eclipse.core.internal.indexing.IndexCursor;
24
import org.eclipse.core.internal.indexing.IndexedStoreException;
25
import org.eclipse.core.internal.indexing.ObjectID;
17
import org.eclipse.core.internal.properties.IndexedStoreWrapper;
26
import org.eclipse.core.internal.properties.IndexedStoreWrapper;
18
import org.eclipse.core.internal.resources.*;
27
import org.eclipse.core.internal.resources.FileState;
19
import org.eclipse.core.internal.utils.*;
28
import org.eclipse.core.internal.resources.ICoreConstants;
20
import org.eclipse.core.resources.*;
29
import org.eclipse.core.internal.resources.ResourceException;
21
import org.eclipse.core.runtime.*;
30
import org.eclipse.core.internal.resources.ResourceStatus;
31
import org.eclipse.core.internal.resources.Workspace;
32
import org.eclipse.core.internal.resources.WorkspaceDescription;
33
import org.eclipse.core.internal.utils.Convert;
34
import org.eclipse.core.internal.utils.Policy;
35
import org.eclipse.core.internal.utils.UniversalUniqueIdentifier;
36
import org.eclipse.core.resources.Checkpoint;
37
import org.eclipse.core.resources.IContainer;
38
import org.eclipse.core.resources.IFile;
39
import org.eclipse.core.resources.IFileState;
40
import org.eclipse.core.resources.IResource;
41
import org.eclipse.core.resources.IResourceStatus;
42
import org.eclipse.core.resources.IResourceVisitor;
43
import org.eclipse.core.resources.IWorkspaceDescription;
44
import org.eclipse.core.resources.ResourcesPlugin;
45
import org.eclipse.core.runtime.CoreException;
46
import org.eclipse.core.runtime.IPath;
47
import org.eclipse.core.runtime.IProgressMonitor;
48
import org.eclipse.core.runtime.Path;
22
49
50
/*
51
 * HistoryStore
52
 *
53
 * Maintain Local History for the workspace.
54
 * <p>
55
 * Checkpoint notes:
56
 * </p><p>
57
 * Checkpoint garbage collection strategy is to remove all checkoints
58
 * that would be invalidated by the removal of a local history entry,
59
 * except in the case where a Project is deleted. Local History is
60
 * deleted whenever a project is deleted, which could easily cause us
61
 * to lose the entire set of checkpoints for other projects in the
62
 * workspace. That would be too limiting. Normal garbage collection of
63
 * local history entries due to expiration or limit counts will cause
64
 * all affected checkpoints to be removed.
65
 * </p>
66
 */
23
public class HistoryStore {
67
public class HistoryStore {
24
	protected Workspace workspace;
68
	protected Workspace workspace;
25
	protected IPath location;
69
	protected IPath location;
26
	protected BlobStore blobStore;
70
	protected BlobStore blobStore;
27
	private IndexedStoreWrapper store;
71
	private IndexedStoreWrapper store;
28
	private final static String INDEX_FILE = ".index"; //$NON-NLS-1$
72
	private final static String INDEX_FILE = ".index"; //$NON-NLS-1$
29
	
73
	private final static String CHECKPOINT_FILE = ".checkpoints.txt"; //$NON-NLS-1$
74
	private CheckpointFileStore fCheckpointStore;
30
	//flag used inside stateAlreadyExists to prevent creating an array
75
	//flag used inside stateAlreadyExists to prevent creating an array
31
	protected boolean stateAlreadyExists;
76
	protected boolean stateAlreadyExists;
32
77
Lines 34-39 Link Here
34
	this.workspace = workspace;
79
	this.workspace = workspace;
35
	blobStore = new BlobStore(location, limit);
80
	blobStore = new BlobStore(location, limit);
36
	store = new IndexedStoreWrapper(location.append(INDEX_FILE));
81
	store = new IndexedStoreWrapper(location.append(INDEX_FILE));
82
	fCheckpointStore  = new CheckpointFileStore(location.append(CHECKPOINT_FILE));
83
	initCheckpointStore();
84
}
85
86
private void initCheckpointStore() {
87
	long time = System.currentTimeMillis();
88
	Date date = new Date(time);
89
	fCheckpointStore.addCheckpoint("session startup "+date.toString());
37
}
90
}
38
/**
91
/**
39
 * Searches indexed store for key, and invokes visitor's defined behaviour on key matches.
92
 * Searches indexed store for key, and invokes visitor's defined behaviour on key matches.
Lines 181-187 Link Here
181
			HistoryStoreEntry entry = HistoryStoreEntry.create(store, cursor);
234
			HistoryStoreEntry entry = HistoryStoreEntry.create(store, cursor);
182
			// is it old?
235
			// is it old?
183
			if (entry.getLastModified() < minimumTimestamp) {
236
			if (entry.getLastModified() < minimumTimestamp) {
184
				remove(entry);
237
				remove(entry, true);
185
				continue;
238
				continue;
186
			}
239
			}
187
			if (!entry.getPath().equals(current)) {
240
			if (!entry.getPath().equals(current)) {
Lines 197-202 Link Here
197
		cursor.close();
250
		cursor.close();
198
		store.commit();
251
		store.commit();
199
		removeGarbage(blobs);
252
		removeGarbage(blobs);
253
		// clean up the Checkpoint store as well.
254
		fCheckpointStore.clean(minimumTimestamp);
200
	} catch (Exception e) {
255
	} catch (Exception e) {
201
		String message = Policy.bind("history.problemsCleaning"); //$NON-NLS-1$
256
		String message = Policy.bind("history.problemsCleaning"); //$NON-NLS-1$
202
		ResourceStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, null, message, e);
257
		ResourceStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, null, message, e);
Lines 378-392 Link Here
378
			", max: " + description.getMaxFileStateSize()); //$NON-NLS-1$
433
			", max: " + description.getMaxFileStateSize()); //$NON-NLS-1$
379
	return result;
434
	return result;
380
}
435
}
381
protected void remove(HistoryStoreEntry entry) throws IndexedStoreException {
436
protected void remove(HistoryStoreEntry entry, boolean cleanCheckpoints) throws IndexedStoreException {
382
	// Do not remove the blob yet.  It may be referenced by another
437
	// Do not remove the blob yet.  It may be referenced by another
383
	// history store entry.
438
	// history store entry.
384
	entry.remove();
439
	entry.remove();
440
	// collect any corresponding checkpoints that would be invalidated by
441
	// the removal of this entry
442
	if (cleanCheckpoints) {
443
		fCheckpointStore.clean(entry.getLastModified());
444
	}
385
}
445
}
386
/**
446
/**
387
 * Removes all file states from this store.
447
 * Removes all file states from this store.
388
 */
448
 */
389
public void removeAll() {
449
public void removeAll() {
450
	// GC the checkpoints en mass so that calls to clean() are fast.
451
	fCheckpointStore.cleanAll();
390
	// XXX: should implement a method with a better performance
452
	// XXX: should implement a method with a better performance
391
	removeAll(workspace.getRoot());
453
	removeAll(workspace.getRoot());
392
}
454
}
Lines 397-403 Link Here
397
		cursor.find(key);
459
		cursor.find(key);
398
		while (cursor.keyMatches(key)) {
460
		while (cursor.keyMatches(key)) {
399
			HistoryStoreEntry entry = HistoryStoreEntry.create(store, cursor);
461
			HistoryStoreEntry entry = HistoryStoreEntry.create(store, cursor);
400
			remove(entry);
462
			remove(entry, false);
401
		}
463
		}
402
		cursor.close();
464
		cursor.close();
403
		store.commit();
465
		store.commit();
Lines 439-446 Link Here
439
	if (entries.size() <= maxEntries)
501
	if (entries.size() <= maxEntries)
440
		return;
502
		return;
441
	int limit = entries.size() - maxEntries;
503
	int limit = entries.size() - maxEntries;
442
	for (int i = 0; i < limit; i++)
504
	for (int i = 0; i < limit; i++) {
443
		remove((HistoryStoreEntry) entries.get(i));
505
		HistoryStoreEntry entry = (HistoryStoreEntry) entries.get(i);
506
		remove(entry, true);
507
	}
444
}
508
}
445
public void shutdown(IProgressMonitor monitor) {
509
public void shutdown(IProgressMonitor monitor) {
446
	if (store == null)
510
	if (store == null)
Lines 451-456 Link Here
451
}
515
}
452
protected void resetIndexedStore() {
516
protected void resetIndexedStore() {
453
	store.reset();
517
	store.reset();
518
	fCheckpointStore.reset();
454
	IPath location = workspace.getMetaArea().getHistoryStoreLocation();
519
	IPath location = workspace.getMetaArea().getHistoryStoreLocation();
455
	java.io.File target = location.toFile();
520
	java.io.File target = location.toFile();
456
	Workspace.clear(target);
521
	Workspace.clear(target);
Lines 501-505 Link Here
501
	accept(path, new PathCollector(), true);
566
	accept(path, new PathCollector(), true);
502
	return allFiles;
567
	return allFiles;
503
}
568
}
569
	/**
570
	 * Add a new Checkpoint to the local history
571
	 */
572
	public void addCheckpoint(Checkpoint checkpoint) {
573
		fCheckpointStore.addCheckpoint(checkpoint);
574
	}
575
	
576
	/**
577
	 * Get the complete list of valid Checkpoints.
578
	 * Checkpoints for which there are no Local History States are not returned.
579
	 * The returned list is a deep copy, so any changes you make to the list or
580
	 * to the elements have no effect on the Local History or Checkpoint Store.
581
	 * @return List of <code>Checkpoint</code> objects
582
	 */
583
	public List getCheckpoints() {
584
		return fCheckpointStore.getCheckpointsClone();
585
	}
586
	/**
587
	 * Return the resources needed to rollback the workspace to the specified time.
588
	 * @param rollbackTime time to roll the workspace back to.
589
	 * @return Set[0] is a set of type <code>IFileState</code> that should be restored.
590
	 * Set[1] is a set of type <code>IFile</code> that should be deleted.
591
	 */
592
	public Set[] getRestoreAndDeleteFallbackStates (long rollbackTime) {
593
		Set sets[] = {null, null};
594
		Set oldFileStates = getRollbackFileStates(rollbackTime);
595
		Set modifiedSinceFiles = getFilesModifiedSince(rollbackTime);
596
		Set restoreStates = new HashSet();
597
		Set deleteStates = new HashSet();
598
	
599
		// restore files are those files modified just previous to and
600
		// not after the rollback time.
601
		Iterator states = oldFileStates.iterator();
602
		while (states.hasNext()) {
603
			IFileState state = (IFileState) states.next();
604
			if (containsState(state, modifiedSinceFiles)) {
605
				restoreStates.add(state);
606
			}
607
		}
608
		// deleted files are those files modified since the rollback time, but
609
		// not appearing in local history. They must have been created since
610
		// the rollback time. 
611
		Iterator files = modifiedSinceFiles.iterator();
612
		while (files.hasNext()) {
613
			IFile file = (IFile) files.next();
614
			if (!containsFile(file, oldFileStates)) {
615
				deleteStates.add(file);
616
			}
617
		}
618
		sets[0] = restoreStates;
619
		sets[1] = deleteStates;
620
		return sets;
621
	}
622
	
623
	private boolean containsFile(IFile file, Set stateSet) {
624
		String filePath = file.getFullPath().toString();
625
		
626
		Iterator iter = stateSet.iterator();
627
		while (iter.hasNext()) {
628
			IFileState state = (IFileState) iter.next();
629
			if (filePath.equals(state.getFullPath().toString())) {
630
				return true;
631
			}
632
		}
633
		return false;
634
	}
635
	
636
	private boolean containsState(IFileState state, Set fileSet) {
637
		String statePath = state.getFullPath().toString();
638
		
639
		Iterator iter = fileSet.iterator();
640
		while (iter.hasNext()) {
641
			IFile file = (IFile) iter.next();
642
			if (statePath.equals(file.getFullPath().toString())) {
643
				return true;
644
			}
645
		}
646
		return false;
647
	}
648
	
649
	/**
650
	 * Return the files from the workspace that are new since the last
651
	 * modification time.
652
	 * 
653
	 * @param lastModified return files newer than this date
654
	 * @return the set of newer files from the workspace. Element
655
	 * type is <code>IFile</code>.
656
	 */
657
	private Set getFilesModifiedSince(final long lastModified) {
658
		final Set set = new HashSet();
659
		IResource root = workspace.getRoot();
660
		IResourceVisitor visitor = new IResourceVisitor() {
661
			public boolean visit(IResource resource) {
662
				// boolean isLinked = resource.isLinked();
663
				if (resource.getType() == IResource.FILE) {
664
					IFile file = (IFile) resource;
665
					if (file.getLocalTimeStamp() >= lastModified) {
666
						set.add(file);
667
					}
668
				}
669
				return true;
670
			}};
671
			try {
672
				root.accept(visitor, IResource.DEPTH_INFINITE, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
673
			} catch (CoreException e) {
674
				// No exception should be thrown.
675
			}
676
		return set;
677
	}
504
678
679
	/**
680
	 * Examine the last modification times of all file
681
	 * states stored in the local history and return the set of file states that are
682
	 * present which have modifications nearest and previous to the rollback time.
683
	 * 
684
	 * @param rollbackTime
685
	 * @return Set the set of all file states that should be restored for this target rollback time.
686
	 * (element type is IFileState).
687
	 */
688
	private Set getRollbackFileStates(long rollbackTime) {
689
		// collect all files in the space most proximal to, and younger than <code>lastModified</code>
690
		Set rollbackStates = new HashSet();
691
		
692
		Set set = allFiles(new Path("/"), IResource.DEPTH_INFINITE); //$NON-NLS-1$
693
		Iterator paths = set.iterator();
694
		
695
		// for all file paths, add the one state needed for rollback
696
		while (paths.hasNext()) {
697
			IPath path = (IPath) paths.next();
698
			IFileState[] states = getStates(path);
699
			boolean stateFound = false;
700
701
			// select the state that occurs just before the rollbackTime, maybe none, by
702
			// looking through all stored states for this path and selecting the one that has
703
			// a lastmodification time just before the rollback time. If there is none, then
704
			// this file is not needed for rollback.
705
			//
706
			// states must be sorted from youngest to oldest for this implementation,
707
			// which currently is true using getStates().
708
			
709
			for (int i=0; i<states.length; i++) {
710
				IFileState state = states[i];
711
				if (!stateFound && state.getModificationTime() < rollbackTime) {
712
					stateFound = true;
713
					rollbackStates.add(state);
714
					continue;
715
				}
716
			}
717
		}
718
		return rollbackStates;
719
	}
505
}
720
}
(-)src/org/eclipse/core/internal/localstore/CheckpointFileStore.java (+213 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-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.BufferedReader;
14
import java.io.File;
15
import java.io.FileNotFoundException;
16
import java.io.FileOutputStream;
17
import java.io.FileReader;
18
import java.io.IOException;
19
import java.io.OutputStream;
20
import java.util.ArrayList;
21
import java.util.Iterator;
22
import java.util.List;
23
24
import org.eclipse.core.internal.utils.Assert;
25
import org.eclipse.core.resources.Checkpoint;
26
import org.eclipse.core.runtime.IPath;
27
import org.eclipse.core.runtime.Path;
28
29
/**
30
 * A file storage mechanism for Checkpoints.
31
 *
32
 * Checkpoints are stored sequentially in a store. New Checkpoints are written to
33
 * the end of the store. Old Checkpoints are periodically cleaned up from the front
34
 * of the store (presumably when the Local History Entries are cleaned up and thus
35
 * invalidate the Checkpoint).
36
 */
37
public class CheckpointFileStore extends CheckpointStore {
38
	/*
39
	 * location of CheckpointStore
40
	 */
41
	protected IPath fLocation = null;
42
	protected byte[] fNewline = {'\r','\n'};
43
	
44
	/*
45
	 * Construct a file-based store for Checkpoints
46
	 */
47
	public CheckpointFileStore(IPath location) {
48
		// ensure the location path is valid
49
		Assert.isNotNull(location);
50
		Assert.isTrue(!location.equals(Path.EMPTY));
51
		fLocation = location;
52
	}
53
54
	/*
55
	 * Write the checkpoint to the checkoint store right now. (non-Javadoc)
56
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#addCheckpoint(org.eclipse.core.internal.localstore.Checkpoint)
57
	 */
58
	public void addCheckpoint(Checkpoint cp) {
59
		// write to the end of the file
60
		try {
61
			// open in append-mode
62
			OutputStream output = new FileOutputStream(fLocation.toFile(), true);
63
			try {
64
				byte[] bytes = cp.getBytes();
65
				store(output, bytes);
66
			} finally {
67
				output.close();
68
			}
69
		} catch (IOException e) {
70
			String message = "CheckpointFileStore: failed to write checkpoint"; //$NON-NLS-1$
71
			// TODO: log an error
72
		}
73
	}
74
75
	/*
76
	 * add checkpoint for current time and specified label
77
	 */
78
	public void addCheckpoint (String label) {
79
		addCheckpoint(label, System.currentTimeMillis());
80
	}
81
	
82
	/*
83
	 *  (non-Javadoc)
84
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#getCheckpointsClone()
85
	 */
86
	public synchronized List getCheckpointsClone () {
87
		// reading is faster with just one synchronize call at the top level
88
		// rather than for each readLine(). It's unlikely anyone will be
89
		// writing new checkpoints while we read the old ones, however, so
90
		// the write-delay case is rare.
91
		List list = new ArrayList();
92
		BufferedReader reader = null;
93
		try {
94
			reader = new BufferedReader(new FileReader(fLocation.toFile()));
95
			while (reader.ready()) {
96
				String line = reader.readLine();
97
				Checkpoint cp = Checkpoint.createCheckpoint(line);
98
				if (cp != null) {
99
					list.add(cp);
100
				}
101
			}
102
			return list;
103
		} catch (FileNotFoundException e) {
104
			// TODO report badness via proper Logging
105
			String message = "FileNotFoundException: "+fLocation.toFile(); //$NON-NLS-1$
106
		} catch (IOException e) {
107
			// TODO report badness via proper Logging
108
			String message = "IOException: reading checkpoints from "+fLocation.toFile(); //$NON-NLS-1$
109
		} finally {
110
			try {
111
				if (reader != null)
112
					reader.close();
113
			} catch (IOException e) {
114
				// nothing more we can do.
115
			}
116
		}
117
		return list;
118
	}
119
120
	/**
121
	 * @return Returns the fLocation.
122
	 */
123
	public IPath getFLocation() {
124
		return fLocation;
125
	}
126
	/**
127
	 * @param location The fLocation to set.
128
	 */
129
	public void setFLocation(IPath location) {
130
		fLocation = location;
131
	}
132
133
	/**
134
	 * @return Returns the fNewline.
135
	 */
136
	public byte[] getFNewline() {
137
		return fNewline;
138
	}
139
	/**
140
	 * @param newline The fNewline to set.
141
	 */
142
	public void setFNewline(byte[] newline) {
143
		fNewline = newline;
144
	}
145
146
	/* (non-Javadoc)
147
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#clean(long)
148
	 */
149
	public void clean(long cutoffDate) {
150
		// get the list from file storage, collect it
151
		// and write it back out.
152
		List checkpoints = getCheckpointsClone();
153
		int oldSize = checkpoints.size();
154
		if (oldSize > 0) {
155
			// only try to GC non-empy checkoint lists
156
			checkpoints = CheckpointListStore.collectList(checkpoints, cutoffDate);
157
			if (checkpoints.size() < oldSize) {
158
				// only write file if the list shrunk
159
				writeCheckPointFile(checkpoints);
160
			}
161
		}
162
	}
163
	
164
	/* (non-Javadoc)
165
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#cleanAll()
166
	 */
167
	public void cleanAll() {
168
		List checkpoints = new ArrayList();
169
		writeCheckPointFile(checkpoints);
170
	}
171
	
172
	/* (non-Javadoc)
173
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#reset()
174
	 */
175
	public void reset() {
176
		// nothing to do
177
	}
178
	
179
	/*
180
	 * write a list of checkpoints to the file store
181
	 */
182
	private synchronized void writeCheckPointFile(List checkpoints) {
183
		try {
184
			// open in overwrite-mode
185
			OutputStream output = new FileOutputStream(fLocation.toFile());
186
			try {
187
				Iterator iter = checkpoints.iterator();
188
				while (iter.hasNext()) {
189
					Checkpoint cp = (Checkpoint)iter.next();
190
					byte[] bytes = cp.getBytes();
191
					store(output, bytes);
192
				}
193
			} finally {
194
				if (output != null) {
195
					output.close();
196
				}
197
			}
198
		} catch (IOException e) {
199
			String message = "CheckpointFileStore: failed to write checkpoint"; //$NON-NLS-1$
200
			// TODO: log an error
201
		}
202
	}
203
204
	/*
205
	 * Write the checkpoint to the end of the file, synchronized.
206
	 */
207
	private synchronized void store(OutputStream out, byte[] bytes) throws IOException {
208
        out.write(bytes);
209
        out.write(fNewline);
210
        out.flush();
211
    }
212
213
}
(-)src/org/eclipse/core/internal/localstore/CheckpointListStore.java (+119 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.internal.localstore;
12
13
import java.util.ArrayList;
14
import java.util.Iterator;
15
import java.util.List;
16
import java.util.ListIterator;
17
18
import org.eclipse.core.resources.Checkpoint;
19
20
/**
21
 * An in-memory storage mechanism for CheckpointEntry(s).
22
 *
23
 * Checkpoints are stored sequentially in a store. New Checkpoints are written to
24
 * the end of the store. Old Checkpoints are periodically cleaned up from the front
25
 * of the store (presumably when the Local History Entries are cleaned up and thus
26
 * invalidate the Checkpoint).
27
 */
28
public class CheckpointListStore extends CheckpointStore {
29
	
30
	// Storage for memory-based store (does not need to be sorted)
31
	protected List fCheckpoints = null;
32
	
33
	/*
34
	 * Construct a memory-based store for Checkpoints.
35
	 * This is not persisted over Eclipse startup/shutdown.
36
	 */
37
	public CheckpointListStore() {
38
		fCheckpoints = new ArrayList();
39
	}
40
	
41
	/*
42
	 *  (non-Javadoc)
43
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#addCheckpoint(java.lang.String, long)
44
	 */
45
	public void addCheckpoint (String label, long lastmodified) {
46
		Checkpoint cp = new Checkpoint(label,lastmodified);
47
		addCheckpoint(cp);
48
	}
49
	
50
	/*
51
	 *  (non-Javadoc)
52
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#addCheckpoint(java.lang.String)
53
	 */
54
	public void addCheckpoint (String label) {
55
		addCheckpoint(label, System.currentTimeMillis());
56
	}
57
	
58
	/*
59
	 *  (non-Javadoc)
60
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#getCheckpointsClone()
61
	 */
62
	public List getCheckpointsClone () {
63
		List cloneList = new ArrayList();
64
		ListIterator iter = fCheckpoints.listIterator();
65
		while (iter.hasNext()) {
66
			Checkpoint cp = (Checkpoint ) iter.next();
67
			cloneList.add(cp.clone());
68
		}
69
		return cloneList;
70
	}
71
72
	/* (non-Javadoc)
73
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#addCheckpoint(org.eclipse.core.internal.localstore.Checkpoint)
74
	 */
75
	public void addCheckpoint(Checkpoint checkpoint) {
76
		fCheckpoints.add(checkpoint); // ignore possible failure
77
	}
78
	/* (non-Javadoc)
79
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#clean(long)
80
	 */
81
	public void clean(long cutoffDate) {
82
		fCheckpoints = collectList(fCheckpoints, cutoffDate);
83
	}
84
	
85
	/* (non-Javadoc)
86
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#cleanAll()
87
	 */
88
	public void cleanAll() {
89
		fCheckpoints = new ArrayList();
90
	}
91
	
92
	/**
93
	 * Garbage collect the List, removing old checkpoints.
94
	 * Resulting list is unsorted.
95
	 * @param list list of Checkpoint(s) to garbage collect
96
	 * @param cutoffDate oldest date to collect
97
	 * @return list of surviving checkpoints
98
	 */
99
	static public synchronized List collectList(List list, long cutoffDate) {
100
		// search entire list. the list is not assumed to be sorted
101
		Iterator iter = list.iterator();
102
		List collectedList = new ArrayList();
103
		while (iter.hasNext()) {
104
			Checkpoint cp = (Checkpoint)iter.next();
105
			if (cp.getLastModified() > cutoffDate) {
106
				collectedList.add(cp);
107
			}
108
		}
109
		return collectedList;
110
	}
111
112
	/* (non-Javadoc)
113
	 * @see org.eclipse.core.internal.localstore.CheckpointStore#reset()
114
	 */
115
	public void reset() {
116
		// Nothing to do on a reset since we are in memory!	
117
	}
118
119
}
(-)src/org/eclipse/core/internal/localstore/CheckpointStore.java (+87 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.internal.localstore;
12
13
import java.util.List;
14
15
import org.eclipse.core.resources.*;
16
17
/**
18
 * A storage mechanism for CheckpointEntry(s).
19
 *
20
 * Checkpoints are stored sequentially in a store. New Checkpoints are written to
21
 * the end of the store. Old Checkpoints are periodically cleaned up from the front
22
 * of the store (presumably when the Local History Entries are cleaned up and thus
23
 * invalidate the Checkpoint).
24
 * <p>
25
 * The life cycle of checkpoints are simple. Call one of the <code>addCheckpoint</code>
26
 * methods to add a new checkpoint label/time to the checkpoint store whenever you
27
 * want. Later, you can get the list of checkpoints via <code>getCheckpointsClone</code>.
28
 * <p>
29
 * To garbage collect checkpoints, call <code>clean</code> with the oldest timestamp
30
 * you want to remove. Checkpoints with timestamps younger than the one specified are
31
 * kept.
32
 */
33
public abstract class CheckpointStore {
34
35
	/**
36
	 * Construct a memory-based store for Checkpoints.
37
	 * This is not persisted over Eclipse startup/shutdown.
38
	 */
39
	public CheckpointStore() {
40
	}
41
42
	/**
43
	 * add checkpoint for current time and specified label
44
	 * @param label readable name of the checkpoint
45
	 */
46
	public void addCheckpoint (String label) {
47
		addCheckpoint(label, System.currentTimeMillis());
48
	}
49
	
50
	/**
51
	 * add checkpoint for specified label and time.
52
	 * @param label readable name of the checkpoint
53
	 * @param lastmodified datestamp of the checkpoint
54
	 */
55
	public void addCheckpoint (String label, long lastmodified) {
56
		Checkpoint cp = new Checkpoint(label,lastmodified);
57
		addCheckpoint(cp);
58
	}
59
	
60
	public abstract void addCheckpoint(Checkpoint checkpoint);
61
	
62
	/**
63
	 * Return a deep copy of the List of checkpoints. Changes
64
	 * to the list or checkpoint elements have no effect on the store.
65
	 * @returns current list of <code>Checkpoint</code>s.
66
	 */
67
	public abstract List getCheckpointsClone ();
68
	
69
	/**
70
	 * Clean up old checkpoints.
71
	 * Any points having a last modified date equal to, or older than
72
	 * the specified date will be removed from the checkpoint store.
73
	 * @param cutoffDate remove points as old as this, and all older.
74
	 */
75
	public abstract void clean(long cutoffDate);
76
	
77
	/**
78
	 * Remove all checkpoints.
79
	 */
80
	public abstract void cleanAll();
81
	
82
	/**
83
	 * Reset from a failure.
84
	 * Do a best effort to clean up and save what we can.
85
	 */
86
	public abstract void reset();
87
}
(-)src/org/eclipse/core/resources/Checkpoint.java (+135 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.resources;
12
13
import org.eclipse.core.internal.utils.Convert;
14
15
16
/**
17
 * Represent one point in time that can be used as a rollback point for workspace
18
 * resources.
19
 * 
20
 * A checkpoint is defined by a user-settable label and a timestamp. It denotes
21
 * a point in time that corresponds with resources in the local history store.
22
 * A human or programmatic user can roll back to this point, assuming that the
23
 * needed files are located in the local history. Checkpoints are managed by the
24
 * CheckpointStore class.
25
 */
26
public class Checkpoint {
27
	// user-readable label for this checkpoint
28
	protected String fLabel = null;
29
	
30
	// system-meaningful timestamp of this checkpoint
31
	protected long fLastModified = 0;
32
33
	/**
34
	 * Construct a checkpoint with the given label. The timestamp is set at the
35
	 * current value of system time.
36
	 *
37
	 * @param label
38
	 */
39
	public Checkpoint(String label) {
40
		this(label, System.currentTimeMillis());
41
	}
42
43
	/**
44
	 * Construct a checkpoint with given label and timestamp.
45
	 * *
46
	 * @param label
47
	 * @param timestamp
48
	 */
49
	public Checkpoint(String label, long lastmodified) {
50
		fLabel = label;
51
		fLastModified = lastmodified;
52
	}
53
	
54
	/**
55
	 * Create a checkpoint from an array of UTF8-encoded bytes. Expected
56
	 * format is <code>(lastmodified-value)(space)(label-value)</code>
57
	 * @param bytes
58
	 */
59
	static public Checkpoint createCheckpoint(byte[] bytes) {
60
		String s = Convert.fromUTF8(bytes);
61
		return createCheckpoint(s);
62
	}
63
	
64
	/**
65
	 * Create a checkpoint from a string. Expected format
66
	 * is <code>(lastmodified-value)(space)(label-value)</code>
67
	 * @param string
68
	 */
69
	static public Checkpoint createCheckpoint(String string) {
70
		// parse string into fields
71
		String[] tokens = string.split(" ",2); //$NON-NLS-1$
72
		if (tokens.length != 2) {
73
			return null;
74
		}
75
		String label = tokens[1];
76
		String lastModString = tokens[0];
77
		return new Checkpoint(label,Long.parseLong(lastModString));
78
	}
79
	
80
	/**
81
	 * Return (printable) string representation of Checkpoint.
82
	 */
83
	public String toString() {
84
		StringBuffer s = new StringBuffer();
85
		s.append("("+Long.toString(fLastModified)+" "); //$NON-NLS-1$ //$NON-NLS-2$
86
		s.append(fLabel+")");  //$NON-NLS-1$
87
		return s.toString();
88
	}
89
90
	/**
91
	 * Return the UTF8-encoded bytes that represent this checkpoint.
92
	 */
93
	public byte[] getBytes() {
94
		// convert fields to bytes
95
		byte[] lastModifiedBytes = Convert.toUTF8(Long.toString(fLastModified));
96
		byte[] labelBytes = Convert.toUTF8(" "+fLabel);  //$NON-NLS-1$
97
		byte[] reply = new byte[lastModifiedBytes.length+labelBytes.length];
98
		// Copy values into reply
99
		System.arraycopy(lastModifiedBytes, 0, reply, 0, lastModifiedBytes.length);
100
		System.arraycopy(labelBytes, 0, reply, lastModifiedBytes.length, labelBytes.length);
101
		return reply;
102
	}
103
	/**
104
	 * @return Returns the Label.
105
	 */
106
	public String getLabel() {
107
		return fLabel;
108
	}
109
	/**
110
	 * @param label The Label to set.
111
	 */
112
	public void setLabel(String label) {
113
		fLabel = label;
114
	}
115
	/**
116
	 * @return Returns the LastModified.
117
	 */
118
	public long getLastModified() {
119
		return fLastModified;
120
	}
121
	/**
122
	 * @param lastModified The LastModified to set.
123
	 */
124
	public void setLastModified(long lastModified) {
125
		fLastModified = lastModified;
126
	}
127
	
128
	/*
129
	 * Make a shallow copy of this object
130
	 * @return new shallow copy of this checkpoint
131
	 */
132
	public Object clone() {
133
		return new Checkpoint(fLabel, fLastModified);
134
	}
135
}
(-)src/org/eclipse/core/resources/CheckpointBridge.java (+90 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.resources;
12
13
import java.util.List;
14
import java.util.Set;
15
16
import org.eclipse.core.internal.localstore.FileSystemResourceManager;
17
import org.eclipse.core.internal.localstore.HistoryStore;
18
import org.eclipse.core.internal.resources.Workspace;
19
20
/**
21
 * CheckpointBridge exposes the minimum needed 
22
*/
23
public class CheckpointBridge {
24
	/**
25
	 * Add a checkpoint to the local history manager.
26
	 * <p>
27
	 * The label is user definable. The lastModified timestamp is usually
28
	 * going to be the current time, which you can obtain with a call to
29
	 * System.currentTimeMillis(). A simple default for the label is the string
30
	 * representation of the current date and time.
31
	 * 
32
	 * @param checkpoint new <code>Checkpoint</code> to add to local history
33
	 */
34
	static public void addCheckpoint(Checkpoint checkpoint) {
35
		HistoryStore historyStore = getHistoryStore();
36
		historyStore.addCheckpoint(checkpoint);
37
	}
38
	/**
39
	 * Get the list of valid checkpoints
40
	 * @return a List of <code>Checkpoint</code> objects.
41
	 */
42
	static public List getCheckpoints() {
43
		HistoryStore historyStore = getHistoryStore();
44
		return historyStore.getCheckpoints();
45
	}
46
	
47
	/**
48
	 * Return the <code>IFileState</code>(s) needed to restore (as best as
49
	 * possible) the workspace to its state of the <code>lastModified</code>
50
	 * time. Two sets are returned. The first holds the set of resources that
51
	 * should be restored from the local history. The second holds the set of
52
	 * resources that should be deleted from the workspace.
53
	 * 
54
	 * @param lastModified time of the checkpoint to rollback to.
55
	 * @return an array of <code>Set</code>(s) of size two. Each
56
	 * element type of each Set is an IFileState. Set[0] holds
57
	 * the "restore" set and Set[1] holds the "delete" set.
58
	 */
59
	public static Set[] getRestoreAndDeleteFallbackStates(long lastModified) {
60
		HistoryStore historyStore = getHistoryStore();
61
		Set[] stateSets = historyStore.getRestoreAndDeleteFallbackStates(lastModified);
62
		/* begin debugging
63
		Set restoreStates = stateSets[0]; // IFileState
64
		Set deleteStates = stateSets[1]; // IFile
65
		
66
		Iterator states = restoreStates.iterator();
67
		while (states.hasNext()) {
68
			IFileState state = (IFileState) states.next();
69
			Date date = new Date(state.getModificationTime());
70
			System.out.println("restore: " + date.toString() + "\t" + state.getFullPath());
71
		}
72
		states = deleteStates.iterator();
73
		while (states.hasNext()) {
74
			IFile state = (IFile) states.next();
75
			Date date = new Date(state.getLocalTimeStamp());
76
			System.out.println("delete: " + date.toString() + "\t" + state.getFullPath());
77
		}
78
		end debugging */
79
		return stateSets;
80
	}
81
	
82
	/*
83
	 * Get the current HistoryStore from the workspace.
84
	 */
85
	static private HistoryStore getHistoryStore() {
86
		Workspace workspace = (Workspace) ResourcesPlugin.getWorkspace();
87
		FileSystemResourceManager fmgr = workspace.getFileSystemManager();
88
		return (fmgr == null) ? null : fmgr.getHistoryStore();
89
	}
90
}

Return to bug 36958