diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs index 8b057dc..acd8d91 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs @@ -47,6 +47,76 @@ namespace Acacia.Features.DebugSupport Properties.Refresh(); } + private class DebugCycleInfo + { + private int cycleIndex = 0; + private int cycleCount; + private Timer timer = new Timer(); + private GAB.FeatureGAB gab; + private int zeroCount = 1000; + + public DebugCycleInfo(DebugDialog dlg, GAB.FeatureGAB gab, int count) + { + this.cycleCount = count; + this.gab = gab; + timer.Interval = 1000; + timer.Tick += (a, b) => + { + dlg.Text = string.Format("Cycle {0} of {1}", cycleIndex + 1, cycleCount); + dlg.GarbageCollect(); + + if (((DebugInfo)dlg.Properties.SelectedObject).ActiveTasks == 0) + { + // Make sure the value is stable at zero + ++zeroCount; + if (zeroCount >= 3) + { + zeroCount = 0; + Logger.Instance.Debug(this, "CYCLER"); + ++cycleIndex; + + if (cycleIndex >= cycleCount) + { + timer.Stop(); + dlg.Hide(); + ThisAddIn.Instance.Quit(); + } + else + { + DebugCycle(); + } + } + } + }; + } + + public void Run() + { + timer.Start(); + } + + private void DebugCycle() + { + Tasks.Task(gab, "DebugCycle", () => + { + gab.FullResync(); + }); + } + + } + + private DebugCycleInfo cycle; + + internal void DebugCycle(int count) + { + GAB.FeatureGAB gab = ThisAddIn.Instance.GetFeature(); + if (gab != null) + { + cycle = new DebugCycleInfo(this, gab, count); + cycle.Run(); + } + } + #region Logging private const string INDENT = "+"; @@ -89,6 +159,11 @@ namespace Acacia.Features.DebugSupport private void buttonGC_Click(object sender, EventArgs e) { + GarbageCollect(); + } + + private void GarbageCollect() + { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs index cc11799..e6ddead 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs @@ -32,6 +32,7 @@ namespace Acacia.Features.DebugSupport { Version, Memory, + Tasks, Wrappers, Misc, System, @@ -133,6 +134,25 @@ namespace Acacia.Features.DebugSupport #endregion + #region Tasks + + [DebugCategory(DebugCategory.Tasks)] + public string Threading + { + get { return Tasks.Executor.Name; } + } + + [DebugCategory(DebugCategory.Tasks)] + public long ActiveTasks { get { return Statistics.StartedTasks - Statistics.FinishedTasks; } } + + [DebugCategory(DebugCategory.Tasks)] + public long StartedTasks { get { return Statistics.StartedTasks; } } + + [DebugCategory(DebugCategory.Tasks)] + public long FinishedTasks { get { return Statistics.FinishedTasks; } } + + #endregion + #region Wrappers [DebugCategory(DebugCategory.Wrappers)] @@ -163,12 +183,6 @@ namespace Acacia.Features.DebugSupport } } - [DebugCategory(DebugCategory.Misc)] - public string Threading - { - get { return Tasks.Executor.Name; } - } - [DebugCategory(DebugCategory.Misc)] public bool ZPushSync { @@ -227,7 +241,7 @@ namespace Acacia.Features.DebugSupport #endregion -#region Outlook + #region Outlook [DebugCategory(DebugCategory.System)] public string OutlookVersion @@ -247,7 +261,7 @@ namespace Acacia.Features.DebugSupport } } -#endregion + #endregion #region Helpers diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs index 44315c5..12e43d5 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/FeatureDebugSupport.cs @@ -45,11 +45,19 @@ namespace Acacia.Features.DebugSupport RegisterButton(this, "Settings", false, ShowSettings); } + + public override void AfterStartup() + { + ShowAbout(); + } + #region About dialog - + public void ShowAbout() { - new AboutDialog().ShowDialog(); + DebugDialog dd = new DebugDialog(); + dd.Show(); + dd.DebugCycle(5); } #endregion diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs index a1fcf69..f9d5a9c 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/Statistics.cs @@ -25,6 +25,9 @@ namespace Acacia.Features.DebugSupport { public static class Statistics { + public static long StartedTasks; + public static long FinishedTasks; + public static long CreatedWrappers; public static long DeletedWrappers; public static long DisposedWrappers; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs index 3d0b1b2..32ab950 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Feature.cs @@ -226,6 +226,11 @@ namespace Acacia.Features } + public virtual void AfterStartup() + { + + } + #endregion #region Z-Push channels diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs index 53b1922..e53bf0e 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs @@ -333,10 +333,14 @@ namespace Acacia.Features.GAB } // Do the resync + int remaining = _gabsByDomainName.Count; foreach (GABHandler gab in _gabsByDomainName.Values) { Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName); - Tasks.Task(this, "FullResync", () => gab.FullResync()); + Tasks.Task(this, "FullResync", () => + { + gab.FullResync(); + }); } } finally diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs index 5489474..a581a84 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs @@ -41,6 +41,7 @@ namespace Acacia.Stubs /// Restarts the application /// void Restart(); + void Quit(); void InvokeUI(Action action); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs index 9b81921..444a6af 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs @@ -57,6 +57,11 @@ namespace Acacia.Stubs.OutlookWrappers _app.Quit(); } + public void Quit() + { + _app.Quit(); + } + public event NSOutlook.ApplicationEvents_11_ItemLoadEventHandler ItemLoad { add { _app.ItemLoad += value; } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs index c1fb633..5db7f0d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ThisAddIn.cs @@ -44,9 +44,6 @@ namespace Acacia private set; } - // TODO: remove? - private Control _dispatcher; - #region Features /// @@ -92,10 +89,6 @@ namespace Acacia int lcid = Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI); Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid); - // Create a dispatcher - _dispatcher = new Control(); - _dispatcher.CreateControl(); - // The synchronization context is needed to allow background tasks to jump back to the UI thread. // It's null in older versions of .Net, this fixes that if (SynchronizationContext.Current == null) @@ -142,6 +135,9 @@ namespace Acacia // Done Logger.Instance.Debug(this, "Startup done"); Acacia.Features.DebugSupport.Statistics.StartupTime.Stop(); + foreach (Feature feature in Features) + feature.AfterStartup(); + } catch (System.Exception e) { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs index e616f85..9169b04 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/Tasks.cs @@ -15,9 +15,11 @@ /// Consult LICENSE file for details using Acacia.Features; +using Acacia.Features.DebugSupport; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Threading; using System.Windows.Forms; namespace Acacia.Utils @@ -64,10 +66,29 @@ namespace Acacia.Utils } - public interface TaskExecutor + public abstract class TaskExecutor { - string Name { get; } - void ExecuteTask(AcaciaTask task); + public abstract string Name { get; } + + public void AddTask(AcaciaTask task) + { + Interlocked.Increment(ref Statistics.StartedTasks); + EnqueueTask(task); + } + + abstract protected void EnqueueTask(AcaciaTask task); + + protected void PerformTask(AcaciaTask task) + { + try + { + task.Execute(); + } + finally + { + Interlocked.Increment(ref Statistics.FinishedTasks); + } + } } public static class Tasks @@ -103,12 +124,12 @@ namespace Acacia.Utils public static void Task(Feature owner, string name, Action action) { - Executor.ExecuteTask(new AcaciaTask(owner, name, action)); + Task(new AcaciaTask(owner, name, action)); } public static void Task(AcaciaTask task) { - Executor.ExecuteTask(task); + Executor.AddTask(task); } } } \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs index 94da998..98acf58 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksBackground.cs @@ -1,4 +1,6 @@ -/// Copyright 2016 Kopano b.v. + +using Acacia.Features.DebugSupport; +/// Copyright 2016 Kopano b.v. /// /// This program is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License, version 3, @@ -13,7 +15,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -40,15 +41,15 @@ namespace Acacia.Utils while (!_tasks.IsCompleted) { AcaciaTask task = _tasks.Take(); - task.Execute(); + PerformTask(task); } } - public void ExecuteTask(AcaciaTask task) + protected override void EnqueueTask(AcaciaTask task) { _tasks.Add(task); } - public string Name { get { return "Background"; } } + override public string Name { get { return "Background"; } } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs index 2c91c12..0825f12 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksMainThread.cs @@ -73,7 +73,7 @@ namespace Acacia.Utils { AcaciaTask task = _tasks.Dequeue(); Logger.Instance.Trace(task.Id, "Beginning task"); - task.Execute(); + PerformTask(task); Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds); // Execute another task if available and we haven't taken too long. } while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50); @@ -99,7 +99,7 @@ namespace Acacia.Utils /// /// The name, for debugging and logging. /// The action to execute - public void ExecuteTask(AcaciaTask task) + override protected void EnqueueTask(AcaciaTask task) { if (_init == InitState.Uninitialised) { @@ -112,6 +112,6 @@ namespace Acacia.Utils _tasks.Enqueue(task); } - public string Name { get { return "MainThread"; } } + override public string Name { get { return "MainThread"; } } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs index 15b67ae..075ad5e 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/TasksSynchronous.cs @@ -24,11 +24,11 @@ namespace Acacia.Utils { public class TasksSynchronous : TaskExecutor { - public void ExecuteTask(AcaciaTask task) + protected override void EnqueueTask(AcaciaTask task) { - task.Execute(); + PerformTask(task); } - public string Name { get { return "Synchronous"; } } + override public string Name { get { return "Synchronous"; } } } }