controller: use a lock for accessing Repositories. Fixes rare crashes when multiple threads want access

This commit is contained in:
Hylke Bons 2012-02-18 01:52:17 +01:00
parent aa610c818e
commit 35a7c13422

View file

@ -34,7 +34,7 @@ namespace SparkleShare {
public abstract class SparkleControllerBase { public abstract class SparkleControllerBase {
public List <SparkleRepoBase> Repositories; public List<SparkleRepoBase> Repositories = new List<SparkleRepoBase> ();
public readonly string SparklePath = SparkleConfig.DefaultConfig.FoldersPath; public readonly string SparklePath = SparkleConfig.DefaultConfig.FoldersPath;
public double ProgressPercentage = 0.0; public double ProgressPercentage = 0.0;
@ -93,6 +93,7 @@ namespace SparkleShare {
private List<string> failed_avatars = new List<string> (); private List<string> failed_avatars = new List<string> ();
private Object avatar_lock = new Object (); private Object avatar_lock = new Object ();
private Object repo_lock = new Object ();
// Short alias for the translations // Short alias for the translations
@ -200,10 +201,12 @@ namespace SparkleShare {
get { get {
List<string> unsynced_folders = new List<string> (); List<string> unsynced_folders = new List<string> ();
foreach (SparkleRepoBase repo in Repositories) { lock (this.repo_lock) {
if (repo.HasUnsyncedChanges) foreach (SparkleRepoBase repo in Repositories) {
unsynced_folders.Add (repo.Name); if (repo.HasUnsyncedChanges)
} unsynced_folders.Add (repo.Name);
}
}
return unsynced_folders; return unsynced_folders;
} }
@ -236,13 +239,15 @@ namespace SparkleShare {
{ {
List<SparkleChangeSet> list = new List<SparkleChangeSet> (); List<SparkleChangeSet> list = new List<SparkleChangeSet> ();
foreach (SparkleRepoBase repo in Repositories) { lock (this.repo_lock) {
List<SparkleChangeSet> change_sets = repo.GetChangeSets (30); foreach (SparkleRepoBase repo in Repositories) {
List<SparkleChangeSet> change_sets = repo.GetChangeSets (30);
if (change_sets != null)
list.AddRange (change_sets); if (change_sets != null)
else list.AddRange (change_sets);
SparkleHelpers.DebugInfo ("Log", "Could not create log for " + repo.Name); else
SparkleHelpers.DebugInfo ("Log", "Could not create log for " + repo.Name);
}
} }
list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp))); list.Sort ((x, y) => (x.Timestamp.CompareTo (y.Timestamp)));
@ -262,10 +267,12 @@ namespace SparkleShare {
string path = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, name); string path = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, name);
int log_size = 50; int log_size = 50;
foreach (SparkleRepoBase repo in Repositories) { lock (this.repo_lock) {
if (repo.LocalPath.Equals (path)) foreach (SparkleRepoBase repo in Repositories) {
return repo.GetChangeSets (log_size); if (repo.LocalPath.Equals (path))
return repo.GetChangeSets (log_size);
}
} }
return null; return null;
@ -553,19 +560,20 @@ namespace SparkleShare {
bool has_syncing_repos = false; bool has_syncing_repos = false;
bool has_unsynced_repos = false; bool has_unsynced_repos = false;
foreach (SparkleRepoBase repo in Repositories) { lock (this.repo_lock) {
if (repo.Status == SyncStatus.SyncDown || foreach (SparkleRepoBase repo in Repositories) {
repo.Status == SyncStatus.SyncUp || if (repo.Status == SyncStatus.SyncDown ||
repo.IsBuffering) { repo.Status == SyncStatus.SyncUp ||
repo.IsBuffering) {
has_syncing_repos = true;
has_syncing_repos = true;
} else if (repo.HasUnsyncedChanges) {
has_unsynced_repos = true; } else if (repo.HasUnsyncedChanges) {
has_unsynced_repos = true;
}
} }
} }
if (has_syncing_repos) { if (has_syncing_repos) {
if (OnSyncing != null) if (OnSyncing != null)
OnSyncing (); OnSyncing ();
@ -646,7 +654,10 @@ namespace SparkleShare {
}; };
Repositories.Add (repo); lock (this.repo_lock) {
Repositories.Add (repo);
}
repo.Initialize (); repo.Initialize ();
} }
@ -657,14 +668,16 @@ namespace SparkleShare {
{ {
string folder_name = Path.GetFileName (folder_path); string folder_name = Path.GetFileName (folder_path);
for (int i = 0; i < Repositories.Count; i++) { lock (this.repo_lock) {
SparkleRepoBase repo = Repositories [i]; for (int i = 0; i < Repositories.Count; i++) {
SparkleRepoBase repo = Repositories [i];
if (repo.Name.Equals (folder_name)) {
repo.Dispose (); if (repo.Name.Equals (folder_name)) {
Repositories.Remove (repo); repo.Dispose ();
repo = null; Repositories.Remove (repo);
break; repo = null;
break;
}
} }
} }
} }
@ -674,8 +687,6 @@ namespace SparkleShare {
// folders in the SparkleShare folder // folders in the SparkleShare folder
private void PopulateRepositories () private void PopulateRepositories ()
{ {
Repositories = new List<SparkleRepoBase> ();
foreach (string folder_name in SparkleConfig.DefaultConfig.Folders) { foreach (string folder_name in SparkleConfig.DefaultConfig.Folders) {
string folder_path = new SparkleFolder (folder_name).FullPath; string folder_path = new SparkleFolder (folder_name).FullPath;
@ -1077,12 +1088,14 @@ namespace SparkleShare {
// quits if safe // quits if safe
public void TryQuit () public void TryQuit ()
{ {
foreach (SparkleRepoBase repo in Repositories) { lock (this.repo_lock) {
if (repo.Status == SyncStatus.SyncUp || foreach (SparkleRepoBase repo in Repositories) {
repo.Status == SyncStatus.SyncDown || if (repo.Status == SyncStatus.SyncUp ||
repo.IsBuffering) { repo.Status == SyncStatus.SyncDown ||
repo.IsBuffering) {
return;
return;
}
} }
} }
@ -1092,8 +1105,10 @@ namespace SparkleShare {
public void Quit () public void Quit ()
{ {
foreach (SparkleRepoBase repo in Repositories) lock (this.repo_lock) {
repo.Dispose (); foreach (SparkleRepoBase repo in Repositories)
repo.Dispose ();
}
Environment.Exit (0); Environment.Exit (0);
} }
@ -1104,9 +1119,11 @@ namespace SparkleShare {
folder_name = folder_name.Replace ("%20", " "); folder_name = folder_name.Replace ("%20", " ");
note = note.Replace ("%20", " "); note = note.Replace ("%20", " ");
foreach (SparkleRepoBase repo in Repositories) { lock (this.repo_lock) {
if (repo.Name.Equals (folder_name)) foreach (SparkleRepoBase repo in Repositories) {
repo.AddNote (revision, note); if (repo.Name.Equals (folder_name))
repo.AddNote (revision, note);
}
} }
} }