2016-12-21 12:53:16 +01:00
|
|
|
|
/// 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,
|
|
|
|
|
/// as published by the Free Software Foundation.
|
|
|
|
|
///
|
|
|
|
|
/// This program is distributed in the hope that it will be useful,
|
|
|
|
|
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
|
|
|
/// GNU Affero General Public License for more details.
|
|
|
|
|
///
|
|
|
|
|
/// You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
|
|
|
|
///
|
|
|
|
|
/// Consult LICENSE file for details
|
|
|
|
|
|
|
|
|
|
using Acacia.Features;
|
2017-02-08 18:05:42 +01:00
|
|
|
|
using Acacia.Features.DebugSupport;
|
2016-12-21 12:53:16 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
2017-02-08 18:05:42 +01:00
|
|
|
|
using System.Threading;
|
2016-12-21 12:53:16 +01:00
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
namespace Acacia.Utils
|
|
|
|
|
{
|
|
|
|
|
public class AcaciaTask
|
|
|
|
|
{
|
2017-02-23 17:07:39 +01:00
|
|
|
|
private readonly CompletionTracker _completion;
|
2016-12-21 12:53:16 +01:00
|
|
|
|
public readonly Feature Owner;
|
|
|
|
|
public readonly string Name;
|
|
|
|
|
public readonly Action Action;
|
|
|
|
|
|
2018-10-02 14:01:52 +02:00
|
|
|
|
public long TaskId
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
internal set;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-23 17:07:39 +01:00
|
|
|
|
public AcaciaTask(CompletionTracker completion, Feature owner, string name, Action action)
|
2016-12-21 12:53:16 +01:00
|
|
|
|
{
|
2017-02-23 17:07:39 +01:00
|
|
|
|
this._completion = completion;
|
|
|
|
|
completion?.Begin();
|
2016-12-21 12:53:16 +01:00
|
|
|
|
Owner = owner;
|
|
|
|
|
Name = name;
|
|
|
|
|
Action = action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Id
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2018-10-02 14:01:52 +02:00
|
|
|
|
string suffix = "";
|
|
|
|
|
if (TaskId != 0)
|
|
|
|
|
suffix = ":" + TaskId;
|
|
|
|
|
|
2016-12-21 12:53:16 +01:00
|
|
|
|
if (Owner != null)
|
2018-10-02 14:01:52 +02:00
|
|
|
|
return Owner.Name + "." + Name + suffix;
|
|
|
|
|
return Name + suffix;
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Executes the task.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool Execute()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Action();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Logger.Instance.Error(Owner, "Exception in task {0}: {1}", Name, e);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-02-23 17:07:39 +01:00
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_completion?.End();
|
|
|
|
|
}
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-25 11:28:26 +02:00
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return Id;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-08 18:05:42 +01:00
|
|
|
|
public abstract class TaskExecutor
|
2016-12-21 12:53:16 +01:00
|
|
|
|
{
|
2018-10-02 14:01:52 +02:00
|
|
|
|
internal TasksTracer Tracer;
|
|
|
|
|
|
2017-02-08 18:05:42 +01:00
|
|
|
|
public abstract string Name { get; }
|
|
|
|
|
|
|
|
|
|
public void AddTask(AcaciaTask task)
|
|
|
|
|
{
|
|
|
|
|
Interlocked.Increment(ref Statistics.StartedTasks);
|
2018-10-02 14:01:52 +02:00
|
|
|
|
Tracer?.OnTaskAdding(task);
|
2017-02-08 18:05:42 +01:00
|
|
|
|
EnqueueTask(task);
|
2018-10-02 14:01:52 +02:00
|
|
|
|
Tracer?.OnTaskAdded(task);
|
2017-02-08 18:05:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
abstract protected void EnqueueTask(AcaciaTask task);
|
|
|
|
|
|
|
|
|
|
protected void PerformTask(AcaciaTask task)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-10-02 14:01:52 +02:00
|
|
|
|
Tracer?.OnTaskExecuting(task);
|
2017-02-08 18:05:42 +01:00
|
|
|
|
task.Execute();
|
|
|
|
|
}
|
2018-10-02 14:01:52 +02:00
|
|
|
|
catch(Exception e)
|
|
|
|
|
{
|
|
|
|
|
Tracer?.OnTaskFailed(task, e);
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
2017-02-08 18:05:42 +01:00
|
|
|
|
finally
|
|
|
|
|
{
|
2018-10-02 14:01:52 +02:00
|
|
|
|
Tracer?.OnTaskExecuted(task);
|
2017-02-08 18:05:42 +01:00
|
|
|
|
Interlocked.Increment(ref Statistics.FinishedTasks);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class Tasks
|
|
|
|
|
{
|
|
|
|
|
private static TaskExecutor _executor;
|
2018-10-02 14:01:52 +02:00
|
|
|
|
private static TasksTracer _tracer;
|
|
|
|
|
private static long _taskId;
|
2016-12-21 12:53:16 +01:00
|
|
|
|
|
|
|
|
|
public static TaskExecutor Executor
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_executor == null)
|
|
|
|
|
{
|
|
|
|
|
switch(GlobalOptions.INSTANCE.Threading)
|
|
|
|
|
{
|
|
|
|
|
case DebugOptions.Threading.MainThread:
|
|
|
|
|
_executor = new TasksMainThread();
|
|
|
|
|
break;
|
|
|
|
|
case DebugOptions.Threading.Synchronous:
|
|
|
|
|
_executor = new TasksSynchronous();
|
|
|
|
|
break;
|
|
|
|
|
case DebugOptions.Threading.Background:
|
|
|
|
|
_executor = new TasksBackground();
|
|
|
|
|
break;
|
2019-04-17 12:37:27 +02:00
|
|
|
|
case DebugOptions.Threading.BackgroundRespawn:
|
2021-03-10 11:14:17 +01:00
|
|
|
|
_executor = new TasksBackgroundRespawn(GlobalOptions.INSTANCE.ThreadingRespawnTimeout);
|
2019-04-17 12:37:27 +02:00
|
|
|
|
break;
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
2018-10-02 14:01:52 +02:00
|
|
|
|
|
|
|
|
|
if (GlobalOptions.INSTANCE.TaskTrace)
|
|
|
|
|
{
|
|
|
|
|
// Create a tracer
|
|
|
|
|
_tracer = new TasksTracer();
|
|
|
|
|
_executor.Tracer = _tracer;
|
|
|
|
|
}
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
return _executor;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_executor = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-02 14:01:52 +02:00
|
|
|
|
public static TasksTracer Tracer
|
|
|
|
|
{
|
|
|
|
|
get { return _tracer; }
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-23 17:07:39 +01:00
|
|
|
|
public static void Task(CompletionTracker completion, Feature owner, string name, Action action)
|
2016-12-21 12:53:16 +01:00
|
|
|
|
{
|
2017-02-23 17:07:39 +01:00
|
|
|
|
Task(new AcaciaTask(completion, owner, name, action));
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-17 16:35:05 +02:00
|
|
|
|
public static void Task(AcaciaTask task, bool synchronous = false)
|
2016-12-21 12:53:16 +01:00
|
|
|
|
{
|
2018-10-02 14:01:52 +02:00
|
|
|
|
task.TaskId = Interlocked.Increment(ref _taskId);
|
|
|
|
|
|
2018-09-25 12:11:52 +02:00
|
|
|
|
Logger.Instance.Trace(typeof(Tasks), "TASK added: {0}", task);
|
2017-05-17 16:35:05 +02:00
|
|
|
|
if (synchronous)
|
2018-09-25 11:28:26 +02:00
|
|
|
|
{
|
2018-09-25 12:11:52 +02:00
|
|
|
|
Logger.Instance.Trace(typeof(Tasks), "TASK exec synchronous 1: {0}", task);
|
2017-05-17 16:35:05 +02:00
|
|
|
|
task.Execute();
|
2018-09-25 12:11:52 +02:00
|
|
|
|
Logger.Instance.Trace(typeof(Tasks), "TASK exec synchronous 2: {0}", task);
|
2018-09-25 11:28:26 +02:00
|
|
|
|
}
|
2017-05-17 16:35:05 +02:00
|
|
|
|
else
|
2018-09-25 12:11:52 +02:00
|
|
|
|
{
|
2017-05-17 16:35:05 +02:00
|
|
|
|
Executor.AddTask(task);
|
2018-09-25 12:11:52 +02:00
|
|
|
|
}
|
2016-12-21 12:53:16 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|