FIXED - task 559: Deadlock between autosave thread and history code
http://code.google.com/p/google-refine/issues/detail?id=559 git-svn-id: http://google-refine.googlecode.com/svn/trunk@2538 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
ba89daec1c
commit
9b54a8f29e
@ -127,22 +127,29 @@ public class History implements Jsonizable {
|
|||||||
* Adding a new entry clears all currently held future histories
|
* Adding a new entry clears all currently held future histories
|
||||||
* @param entry
|
* @param entry
|
||||||
*/
|
*/
|
||||||
synchronized public void addEntry(HistoryEntry entry) {
|
public void addEntry(HistoryEntry entry) {
|
||||||
entry.apply(ProjectManager.singleton.getProject(_projectID));
|
Project project = ProjectManager.singleton.getProject(_projectID);
|
||||||
_pastEntries.add(entry);
|
synchronized (project) {
|
||||||
|
// NOTE: project lock must be acquired *first* to prevent deadlocks, so we use a
|
||||||
|
// synchronized block instead of synchronizing the entire method.
|
||||||
|
synchronized (this) {
|
||||||
|
entry.apply(project);
|
||||||
|
_pastEntries.add(entry);
|
||||||
|
|
||||||
setModified();
|
setModified();
|
||||||
|
|
||||||
// Any new change will clear all future entries.
|
// Any new change will clear all future entries.
|
||||||
List<HistoryEntry> futureEntries = _futureEntries;
|
List<HistoryEntry> futureEntries = _futureEntries;
|
||||||
_futureEntries = new ArrayList<HistoryEntry>();
|
_futureEntries = new ArrayList<HistoryEntry>();
|
||||||
|
|
||||||
for (HistoryEntry entry2 : futureEntries) {
|
for (HistoryEntry entry2 : futureEntries) {
|
||||||
try {
|
try {
|
||||||
// remove residual data on disk
|
// remove residual data on disk
|
||||||
entry2.delete();
|
entry2.delete();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,6 +280,12 @@ public class History implements Jsonizable {
|
|||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: this method is called from the autosave thread with the Project
|
||||||
|
* lock already held, so no other synchronized method here can aquire that
|
||||||
|
* Project lock or a deadlock will result.be careful of thread synchronization to avoid
|
||||||
|
* deadlocks.
|
||||||
|
*/
|
||||||
synchronized public void save(Writer writer, Properties options) throws IOException {
|
synchronized public void save(Writer writer, Properties options) throws IOException {
|
||||||
writer.write("pastEntryCount="); writer.write(Integer.toString(_pastEntries.size())); writer.write('\n');
|
writer.write("pastEntryCount="); writer.write(Integer.toString(_pastEntries.size())); writer.write('\n');
|
||||||
for (HistoryEntry entry : _pastEntries) {
|
for (HistoryEntry entry : _pastEntries) {
|
||||||
|
@ -119,6 +119,12 @@ public class HistoryEntry implements Jsonizable {
|
|||||||
_manager.save(this, writer, options);
|
_manager.save(this, writer, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a change to a project. In most cases you should already hold the Project lock
|
||||||
|
* before calling this method to prevent deadlocks.
|
||||||
|
*
|
||||||
|
* @param project the project the change should be applied to
|
||||||
|
*/
|
||||||
public void apply(Project project) {
|
public void apply(Project project) {
|
||||||
if (getChange() == null) {
|
if (getChange() == null) {
|
||||||
ProjectManager.singleton.getHistoryEntryManager().loadChange(this);
|
ProjectManager.singleton.getHistoryEntryManager().loadChange(this);
|
||||||
|
Loading…
Reference in New Issue
Block a user