first commit
This commit is contained in:
232
F4SD-Cockpit-ServerCore/SuccessorCache.cs
Normal file
232
F4SD-Cockpit-ServerCore/SuccessorCache.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using C4IT.FASD.Base;
|
||||
using C4IT.Logging;
|
||||
|
||||
using static C4IT.Logging.cLogManager;
|
||||
using static C4IT.FASD.Base.cF4SDHealthCardRawData;
|
||||
using System.Threading;
|
||||
|
||||
namespace C4IT.DataHistoryProvider
|
||||
{
|
||||
public class cSuccessorJob
|
||||
{
|
||||
public List<string> Tables = new List<string>();
|
||||
public cF4SDHealthCardRawData data = null;
|
||||
public Task<bool> task = null;
|
||||
public CancellationToken Token = CancellationToken.None;
|
||||
public bool Finished = false;
|
||||
public DateTime FinishedTime;
|
||||
public List<Int64> Usage = null;
|
||||
}
|
||||
|
||||
public class SuccessorEntry : List<cSuccessorJob>
|
||||
{
|
||||
public List<Int64> UsageInfo = null;
|
||||
}
|
||||
|
||||
public static class SuccessorCache
|
||||
{
|
||||
private static Timer _timerCache = new Timer(callbackTimerCache, null, 1000, 10000);
|
||||
|
||||
private static void callbackTimerCache(object state)
|
||||
{
|
||||
var myNow = DateTime.UtcNow;
|
||||
lock (Cache)
|
||||
{
|
||||
var lstIds = new List<Guid>();
|
||||
|
||||
foreach (var Entry in Cache)
|
||||
{
|
||||
var lstJobs = new List<cSuccessorJob>();
|
||||
foreach (var Job in Entry.Value)
|
||||
{
|
||||
if (Job.Finished && (myNow - Job.FinishedTime) > TimeSpan.FromSeconds(60))
|
||||
lstJobs.Add(Job);
|
||||
}
|
||||
|
||||
foreach (var Job in lstJobs)
|
||||
Entry.Value.Remove(Job);
|
||||
|
||||
if (Entry.Value.Count == 0)
|
||||
lstIds.Add(Entry.Key);
|
||||
}
|
||||
|
||||
foreach (var id in lstIds)
|
||||
Cache.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<Guid, SuccessorEntry> Cache = new Dictionary<Guid, SuccessorEntry>();
|
||||
|
||||
|
||||
public static bool AddTask(Guid Id, List<string> Tables, Task<List<cF4SDHealthCardRawData.cHealthCardTable>> task, List<Int64> UsageInfo, CancellationToken Token)
|
||||
{
|
||||
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
||||
try
|
||||
{
|
||||
var Job = new cSuccessorJob();
|
||||
lock (Cache)
|
||||
{
|
||||
if (!Cache.TryGetValue(Id, out var lst))
|
||||
{
|
||||
lst = new SuccessorEntry() { Job };
|
||||
Cache.Add(Id, lst);
|
||||
}
|
||||
else
|
||||
lst.Add(Job);
|
||||
|
||||
if (UsageInfo != null)
|
||||
lst.UsageInfo = UsageInfo;
|
||||
}
|
||||
|
||||
Job.Tables = Tables;
|
||||
Job.task = Task.Run<bool>(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = await task;
|
||||
Dictionary<string, cHealthCardTable> tbls = null;
|
||||
if (res != null)
|
||||
tbls = res.ToDictionary(x => x.Name, x => x);
|
||||
lock (Cache)
|
||||
{
|
||||
Job.task = null;
|
||||
Job.data = new cF4SDHealthCardRawData()
|
||||
{
|
||||
Id = Id,
|
||||
Tables = tbls
|
||||
};
|
||||
Job.Finished = true;
|
||||
Job.FinishedTime = DateTime.UtcNow;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
return false;
|
||||
}, Token);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (CM != null) LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async Task<cF4SDHealthCardRawData> GetNextResult(cDataHistoryCollector Collector, Guid Id, bool noAwait, cF4sdWebRequestInfo requestInfo, int LogDeep)
|
||||
{
|
||||
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
|
||||
if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); }
|
||||
var _startTime = DateTime.UtcNow;
|
||||
|
||||
try
|
||||
{
|
||||
var lstResults = new SuccessorEntry();
|
||||
var lstTasks = new SuccessorEntry();
|
||||
var lstWaitingTables = new List<string>();
|
||||
lock (Cache)
|
||||
{
|
||||
if (!Cache.TryGetValue(Id, out var lstObj))
|
||||
return null;
|
||||
|
||||
foreach (var Entry in lstObj)
|
||||
{
|
||||
if (Entry.Finished)
|
||||
lstResults.Add(Entry);
|
||||
else
|
||||
{
|
||||
lstTasks.Add(Entry);
|
||||
lstWaitingTables.AddRange(Entry.Tables);
|
||||
}
|
||||
}
|
||||
foreach (var Entry in lstResults)
|
||||
lstObj.Remove(Entry);
|
||||
}
|
||||
|
||||
if (lstTasks.Count == 0)
|
||||
Cache.Remove(Id);
|
||||
|
||||
if (lstResults.Count > 0)
|
||||
{
|
||||
var RetVal = lstResults[0];
|
||||
for (int i = 1; i < lstResults.Count; i++)
|
||||
{
|
||||
var res = lstResults[i];
|
||||
if (res?.data?.Tables != null)
|
||||
{
|
||||
foreach (var Entry in res.data.Tables)
|
||||
{
|
||||
if (RetVal?.data?.Tables != null)
|
||||
RetVal.data.Tables[Entry.Key] = Entry.Value;
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
foreach (var Table in lstWaitingTables)
|
||||
{
|
||||
var tbl = new cF4SDHealthCardRawData.cHealthCardTable()
|
||||
{
|
||||
Name = Table,
|
||||
IsIncomplete = true,
|
||||
};
|
||||
if (RetVal?.data?.Tables != null)
|
||||
RetVal.data.Tables[Table] = tbl;
|
||||
}
|
||||
|
||||
// correct the result due to usage information
|
||||
if (RetVal.data != null && lstTasks.UsageInfo != null)
|
||||
cDataHistoryCollector.CorrectUsage(Collector, RetVal.data, lstTasks.UsageInfo);
|
||||
|
||||
return RetVal.data;
|
||||
}
|
||||
|
||||
if (noAwait)
|
||||
return null;
|
||||
|
||||
var arrTask = new Task<bool>[lstTasks.Count];
|
||||
for (int i = 0; i < lstTasks.Count; i++)
|
||||
arrTask[i] = lstTasks[i].task;
|
||||
|
||||
var tskFinished = await Task.WhenAny(arrTask);
|
||||
|
||||
return await GetNextResult(Collector, Id, true, requestInfo, LogDeep+1);
|
||||
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); }
|
||||
if (CM != null) LogMethodEnd(CM);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user