Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortherzok <marius.ungureanu@xamarin.com>2016-04-15 14:18:35 +0300
committertherzok <marius.ungureanu@xamarin.com>2016-04-30 10:15:08 +0300
commitd3ded856c30d90550a8493ce341b7bf7b66a1c58 (patch)
treec9dfb9cdd9d5fdcf4878c1fef10e1eef6acdfcab /main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop
parent143d00a55b4efbd7d204c3b4c7ad13ae88a84677 (diff)
[Ide] Reduce concurrency on RecentFiles modifications.
Bug 40375 - Dozens of threads stuck trying to update the 'recent files' file
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentFileStorage.cs80
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs40
2 files changed, 73 insertions, 47 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentFileStorage.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentFileStorage.cs
index 73a404030d..8ff55275fb 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentFileStorage.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentFileStorage.cs
@@ -40,6 +40,7 @@ using System.Threading;
using System.Xml;
using System.Linq;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Desktop
{
@@ -66,6 +67,13 @@ namespace MonoDevelop.Ide.Desktop
public RecentFileStorage (string filePath)
{
this.filePath = filePath;
+
+ // Kick off loading the filepath in the background.
+ AcquireFileExclusive (filePath).ContinueWith (t => {
+ var stream = t.Result;
+ cachedItemList = ReadStore (stream);
+ cachedItemList.Sort ();
+ });
}
void EnableWatching ()
@@ -98,12 +106,12 @@ namespace MonoDevelop.Ide.Desktop
void FileChanged (object sender, FileSystemEventArgs e)
{
- OnRecentFilesChanged (null);
+ OnRecentFilesChanged (cachedItemList);
}
void HandleWatcherRenamed (object sender, RenamedEventArgs e)
{
- OnRecentFilesChanged (null);
+ OnRecentFilesChanged (cachedItemList);
}
public bool RemoveItem (string uri)
@@ -144,15 +152,8 @@ namespace MonoDevelop.Ide.Desktop
if (!File.Exists (filePath)) {
return new RecentItem[0];
}
-
- var c = cachedItemList;
- if (c == null) {
- using (var fs = AcquireFileExclusive (filePath)) {
- c = cachedItemList = ReadStore (fs);
- }
- }
- c.Sort ();
- return c.Where (item => item.IsInGroup (group)).ToArray ();
+
+ return cachedItemList.Where (item => item.IsInGroup (group)).ToArray ();
}
public void RemoveMissingFiles (params string[] groups)
@@ -208,23 +209,54 @@ namespace MonoDevelop.Ide.Desktop
}
return modified;
}
-
+
+ Task recentSaveTask;
+ List<Func<List<RecentItem>, bool>> modifyList = new List<Func<List<RecentItem>, bool>> ();
bool ModifyStore (Func<List<RecentItem>,bool> modify)
{
- List<RecentItem> list;
- using (var fs = AcquireFileExclusive (filePath)) {
- list = ReadStore (fs);
- if (!modify (list)) {
- return false;
+ lock (modifyList) {
+ modifyList.Add (modify);
+
+ // This makes recent file changed event to happen as late as possible, but it shouldn't be a problem.
+ // We keep both multiple-instance concurrency via AcquireFileExclusive lock
+ // And we batch as many modifications as possible in a 1 second window.
+ if (recentSaveTask == null) {
+ recentSaveTask = Task.Delay (1000).ContinueWith (async t => await SaveRecentFiles ());
}
- fs.Position = 0;
- fs.SetLength (0);
- WriteStore (fs, list);
}
- //TODO: can we suppress duplicate event from the FSW?
- OnRecentFilesChanged (list);
return true;
}
+
+ async Task SaveRecentFiles ()
+ {
+ List<Func<List<RecentItem>, bool>> localModifyList;
+
+ lock (modifyList) {
+ localModifyList = new List<Func<List<RecentItem>, bool>> (modifyList);
+ modifyList.Clear ();
+ recentSaveTask = null;
+ }
+
+ using (var fs = await AcquireFileExclusive (filePath)) {
+ cachedItemList = ReadStore (fs);
+ bool modified = false;
+
+ foreach (var modify in localModifyList) {
+ if (!modify (cachedItemList)) {
+ continue;
+ }
+
+ modified = true;
+ }
+
+ if (modified) {
+ fs.Position = 0;
+ fs.SetLength (0);
+ WriteStore (fs, cachedItemList);
+ OnRecentFilesChanged (cachedItemList);
+ }
+ }
+ }
static List<RecentItem> ReadStore (FileStream file)
{
@@ -267,7 +299,7 @@ namespace MonoDevelop.Ide.Desktop
}
//FIXME: should we P/Invoke lockf on POSIX or is Mono's FileShare.None sufficient?
- static FileStream AcquireFileExclusive (string filePath)
+ static async Task<FileStream> AcquireFileExclusive (string filePath)
{
const int MAX_WAIT_TIME = 1000;
const int RETRY_WAIT = 50;
@@ -280,7 +312,7 @@ namespace MonoDevelop.Ide.Desktop
} catch (Exception ex) {
//FIXME: will it work on Mono if we check that it's an access conflict, i.e. HResult is 0x80070020?
if (ex is IOException && remainingTries > 0) {
- Thread.Sleep (RETRY_WAIT);
+ await Task.Delay (RETRY_WAIT);
remainingTries--;
continue;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs
index 7675e92b7c..939b9dcd10 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/RecentOpen.cs
@@ -118,37 +118,31 @@ namespace MonoDevelop.Ide.Desktop
void Add (string grp, string fileName, string displayName)
{
var mime = DesktopService.GetMimeTypeForUri (fileName);
- System.Threading.ThreadPool.QueueUserWorkItem (_ => {
- try {
- var uri = RecentFileStorage.ToUri (fileName);
- var recentItem = new RecentItem (uri, mime, grp) { Private = displayName };
- recentFiles.AddWithLimit (recentItem, grp, ItemLimit);
- } catch (Exception e) {
- LoggingService.LogError ("Failed to add item to recent files list.", e);
- }
- });
+ try {
+ var uri = RecentFileStorage.ToUri (fileName);
+ var recentItem = new RecentItem (uri, mime, grp) { Private = displayName };
+ recentFiles.AddWithLimit (recentItem, grp, ItemLimit);
+ } catch (Exception e) {
+ LoggingService.LogError ("Failed to add item to recent files list.", e);
+ }
}
public override void NotifyFileRemoved (string fileName)
{
- System.Threading.ThreadPool.QueueUserWorkItem (_ => {
- try {
- recentFiles.RemoveItem (RecentFileStorage.ToUri (fileName));
- } catch (Exception e) {
- LoggingService.LogError ("Can't remove from recent files list.", e);
- }
- });
+ try {
+ recentFiles.RemoveItem (RecentFileStorage.ToUri (fileName));
+ } catch (Exception e) {
+ LoggingService.LogError ("Can't remove from recent files list.", e);
+ }
}
public override void NotifyFileRenamed (string oldName, string newName)
{
- System.Threading.ThreadPool.QueueUserWorkItem (_ => {
- try {
- recentFiles.RenameItem (RecentFileStorage.ToUri (oldName), RecentFileStorage.ToUri (newName));
- } catch (Exception e) {
- LoggingService.LogError ("Can't rename file in recent files list.", e);
- }
- });
+ try {
+ recentFiles.RenameItem (RecentFileStorage.ToUri (oldName), RecentFileStorage.ToUri (newName));
+ } catch (Exception e) {
+ LoggingService.LogError ("Can't rename file in recent files list.", e);
+ }
}
public void Dispose ()