diff --git a/MP.Data/Controllers/MpSpecController.cs b/MP.Data/Controllers/MpSpecController.cs index cb420ac9..47117287 100644 --- a/MP.Data/Controllers/MpSpecController.cs +++ b/MP.Data/Controllers/MpSpecController.cs @@ -4,15 +4,12 @@ using Microsoft.Extensions.Configuration; using MP.Data.DatabaseModels; using MP.Data.DTO; using NLog; -using NLog.LayoutRenderers; using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices; using System.Threading.Tasks; -using ZXing; using static EgwCoreLib.Utils.DtUtils; namespace MP.Data.Controllers @@ -551,32 +548,35 @@ namespace MP.Data.Controllers /// /// /// - /// - public async Task FluxLogDataRedux(string idxMaccSel, List fluxList, Periodo currPeriodo, Enum.ValSelection valMode, Enum.DataInterval intReq) + /// + /// Restitusice list dei record statistiche raccolti (da integrare a quelli rpesenti in Redis...) + /// + public async Task> FluxLogDataRedux(string idxMaccSel, List fluxList, Periodo currPeriodo, Enum.ValSelection valMode, Enum.DataInterval intReq, int maxItem) { + List procStats = new List(); Log.Info($"Inizio FluxLogDataRedux | idxMaccSel: {idxMaccSel} | periodo: {currPeriodo.Inizio} --> {currPeriodo.Fine}"); - bool fatto = false; TimeSpan step = TimeSpan.FromHours(1); switch (intReq) { case Enum.DataInterval.minute: - step = TimeSpan.FromMinutes(1); + step = TimeSpan.FromMinutes(1.00 / maxItem); break; + case Enum.DataInterval.hour: - step = TimeSpan.FromHours(1); + step = TimeSpan.FromHours(1.00 / maxItem); break; + case Enum.DataInterval.day: - step = TimeSpan.FromDays(1); + step = TimeSpan.FromDays(1.00 / maxItem); break; + default: break; } - List procStats = new List(); // setup parametri costanti x stored var pIdxMacchina = new SqlParameter("@IdxMacchina", idxMaccSel); var pOnlyTest = new SqlParameter("@OnlyTest", false); - var pDoReIndex = new SqlParameter("@DoReIndex", false); // sarà cambiato solo alla fine x avere un reindex finale x macchina // processo 1:1 ogni flusso foreach (var item in fluxList) @@ -591,10 +591,11 @@ namespace MP.Data.Controllers DateTime dtCursStart = currPeriodo.Inizio; DateTime dtCursEnd = dtCursStart.Add(step); bool setCompleted = false; - // dbCOntext x ogni singolo flusso + // dbContext x ogni singolo flusso using (var dbCtx = new MoonProContext(_configuration)) { - // li processo per intervallo richiesto, cercando dati nel periodo e selezionando VC + // li processo per intervallo richiesto, cercando dati nel periodo e + // selezionando VC while (!setCompleted) { // ora recupero TUTTI i dati della macchina @@ -605,7 +606,7 @@ namespace MP.Data.Controllers int numRec = currFlux.Count; numRecProc += numRec; - if (numRec > 1) + if (numRec > maxItem) { if (dtCursStart > currPeriodo.Fine) { @@ -613,7 +614,6 @@ namespace MP.Data.Controllers } List listPeriodi = new List(); - switch (valMode) { case Enum.ValSelection.First: @@ -622,18 +622,33 @@ namespace MP.Data.Controllers // salvo periodo! listPeriodi.Add(new Periodo(recStart.dtEvento, dtCursEnd)); break; + case Enum.ValSelection.Last: // recupero ultimo item var recEnd = currFlux.LastOrDefault(); // salvo periodo! listPeriodi.Add(new Periodo(dtCursStart, recEnd.dtEvento)); break; + case Enum.ValSelection.Center: - var recCent = currFlux.Skip(numRec / 2).FirstOrDefault(); - // salvo 2 periodi! + int idx = 1; + // per iniziare mi metto a 1/(n+1) rec come step + var recCent = currFlux.Skip(idx / (maxItem + 1)).FirstOrDefault(); listPeriodi.Add(new Periodo(dtCursStart, recCent.dtEvento)); + // salvo restanti periodi (se > 1)! + if (maxItem > 1) + { + for (int i = 2; i < maxItem; i++) + { + DateTime dtInizio = recCent.dtEvento; + recCent = currFlux.Skip(i / (maxItem + 1)).FirstOrDefault(); + listPeriodi.Add(new Periodo(dtInizio, recCent.dtEvento)); + } + } + // aggiungo ultimo... listPeriodi.Add(new Periodo(recCent.dtEvento.AddSeconds(1), dtCursEnd)); break; + default: break; } @@ -646,7 +661,7 @@ namespace MP.Data.Controllers var pDtEnd = new SqlParameter("@DtEnd", slot.Fine); var dbResult = dbCtx .Database - .ExecuteSqlRaw("EXEC man.stp_ReduceFluxLog @IdxMacchina, @CodFlux, @DtStart, @DtEnd, @OnlyTest, @DoReIndex", pIdxMacchina, pCodFlux, pDtStart, pDtEnd, pOnlyTest, pDoReIndex); + .ExecuteSqlRaw("EXEC man.stp_ReduceFluxLog @IdxMacchina, @CodFlux, @DtStart, @DtEnd, @OnlyTest", pIdxMacchina, pCodFlux, pDtStart, pDtEnd, pOnlyTest); } } @@ -657,44 +672,19 @@ namespace MP.Data.Controllers } // fermo cronometro e salvo su DB... sw.Stop(); - LogFLDedupModel currStat = new LogFLDedupModel() + StatDedupDTO currStat = new StatDedupDTO() { IdxMacchina = idxMaccSel, CodFlux = item, - DtRif = DateTime.Now, + Interval = intReq, + Num4Int = maxItem, NumRec = numRecProc, ProcTime = sw.Elapsed.TotalSeconds }; procStats.Add(currStat); } - - // salvo le statistiche di processing... - fatto = LogFLDedupInsert(procStats); Log.Info($"FINE FluxLogDataRedux | idxMaccSel: {idxMaccSel} | periodo: {currPeriodo.Inizio} --> {currPeriodo.Fine}"); - return fatto; - } - /// - /// Inserimento record risultati deduplica FluxLog - /// - /// - /// - protected bool LogFLDedupInsert(List rec2ins) - { - bool fatto = false; - using (var dbCtx = new MoonProContext(_configuration)) - { - try - { - dbCtx.DbSetLogFLDedup.AddRange(rec2ins); - var res = dbCtx.SaveChanges(); - fatto = res != 0; - } - catch (Exception exc) - { - Log.Error($"Errore in fase inserimento log dedup x FL{Environment.NewLine}{exc}"); - } - } - return fatto; + return procStats; } /// @@ -722,6 +712,39 @@ namespace MP.Data.Controllers return dbResult; } + /// + /// Stored manutenzione del DB + /// + /// Esegue realmente il task + /// Aggiornamento statistiche + /// Salvataggio + /// def: 1000 + /// def: 10 + /// def: 50 + /// + public async Task ForceDbMaint(bool doExec, bool doUpdStat, bool doSave, int minPgCnt, int minAvgFrag, int maxAvgFragReb) + { + Log.Info($"Inizio ForceDbMaint"); + bool fatto = false; + using (var dbCtx = new MoonProContext(_configuration)) + { + var pFlgExec = new SqlParameter("@FlgExec", doExec ? "Y" : "N"); + var pFlgUpdStat = new SqlParameter("@FlgUpdStat", doUpdStat ? "Y" : "N"); + var pFlgSave = new SqlParameter("@FlgSave", doSave ? "Y" : "N"); + var pMinPgCnt = new SqlParameter("@min_page_count", minPgCnt); + var pMinAvgFrag = new SqlParameter("@min_avg_fragmentation_in_percent", minAvgFrag); + var pMaxAvgFrag = new SqlParameter("@max_avg_fragmentation_per_rebuild", maxAvgFragReb); + + var dbResult = await dbCtx + .Database + .ExecuteSqlRawAsync("EXEC man.stp_Utility_Maintanance"); + //.ExecuteSqlRaw("EXEC man.stp_Utility_Maintanance @FlgExec, @FlgUpdStat, @FlgSave, @min_page_count, @min_avg_fragmentation_in_percent, @max_avg_fragmentation_per_rebuild", pFlgExec, pFlgUpdStat, pFlgSave, pMinPgCnt, pMinAvgFrag, pMaxAvgFrag); + fatto = true; + } + Log.Info($"FINE ForceDbMaint"); + return fatto; + } + /// /// Elenco giacenze /// diff --git a/MP.Data/DTO/StatDedupDTO.cs b/MP.Data/DTO/StatDedupDTO.cs new file mode 100644 index 00000000..076aca72 --- /dev/null +++ b/MP.Data/DTO/StatDedupDTO.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace MP.Data.DTO +{ + public class StatDedupDTO + { + /// + /// Macchina + /// + public string IdxMacchina { get; set; } = ""; + + /// + /// Cod Flusso interessato + /// + public string CodFlux { get; set; } = ""; + + /// + /// Tipo di intervallo richiesto + /// + public Enum.DataInterval Interval { get; set; } = Enum.DataInterval.hour; + + /// + /// num max di item per intervallo + /// + public int Num4Int { get; set; } = 1; + + /// + /// Num record processati (iniziali) + /// + public int NumRec { get; set; } = 1; + + /// + /// Tempo processing (secondi) + /// + public double ProcTime { get; set; } = 1; + + /// + /// Tempo processing atteso in ms per record + /// + [NotMapped] + public double ProcTimeMs + { + get => (ProcTime * 1000) / (NumRec > 1 ? NumRec : 1); + } + } +} diff --git a/MP.Data/DatabaseModels/LogFLDedupModel.cs b/MP.Data/DatabaseModels/LogFLDedupModel.cs deleted file mode 100644 index 4e3ffee1..00000000 --- a/MP.Data/DatabaseModels/LogFLDedupModel.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - - -#nullable disable -// -// This is here so CodeMaid doesn't reorganize this document -// -namespace MP.Data.DatabaseModels -{ - [Table("LogFLDedup")] - public partial class LogFLDedupModel - { - #region Public Properties - - [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int DedupIdx { get; set; } = 0; - - [MaxLength(50)] - public string IdxMacchina { get; set; } = ""; - - [MaxLength(50)] - public string CodFlux { get; set; } = ""; - - public DateTime DtRif { get; set; }=DateTime.Now; - - /// - /// Num record processati - /// - public int NumRec { get; set; } = 0; - - /// - /// Tempo processing (secondi) - /// - public double ProcTime { get; set; } = 1; - - #endregion Public Properties - } -} \ No newline at end of file diff --git a/MP.Data/Enum.cs b/MP.Data/Enum.cs index 3e1c6a41..3a5afa29 100644 --- a/MP.Data/Enum.cs +++ b/MP.Data/Enum.cs @@ -18,13 +18,13 @@ namespace MP.Data /// First, /// - /// Selezione ULTIMO valore del set - /// - Last, - /// /// Selezione Moda (norma) = elemento centrale /// - Center + Center, + /// + /// Selezione ULTIMO valore del set + /// + Last } /// /// Intervallo dati (es per definizione quanti dati FluxLog tenere x intervallo diff --git a/MP.Data/MoonProContext.cs b/MP.Data/MoonProContext.cs index 54fd7757..43503dc5 100644 --- a/MP.Data/MoonProContext.cs +++ b/MP.Data/MoonProContext.cs @@ -89,10 +89,7 @@ namespace MP.Data public virtual DbSet DbSetStTemplateRows { get; set; } public virtual DbSet DbSetCommenti { get; set; } - public virtual DbSet DbSetFNQ { get; set; } - public virtual DbSet DbSetLogFLDedup { get; set; } - - + public virtual DbSet DbSetFNQ { get; set; } public virtual DbSet DbSetVSEB { get; set; } public virtual DbSet DbSetVSODL { get; set; } diff --git a/MP.Data/Utils.cs b/MP.Data/Utils.cs index 4a4efbaf..5b89a344 100644 --- a/MP.Data/Utils.cs +++ b/MP.Data/Utils.cs @@ -232,6 +232,7 @@ namespace MP.Data public const string redisConfKey = redisBaseAddr + "Cache:Config"; public const string redisAKVKey = redisBaseAddr + "Cache:AKV"; public const string redisParetoFLKey = redisBaseAddr + "Cache:ParetoFL"; + public const string redisStatsProcFL = redisBaseAddr + "Stats:ProcessFL"; public const string redisDossByMac = redisBaseAddr + "Cache:DossByMac"; public const string redisFluxByMac = redisBaseAddr + "Cache:FluxByMac"; public const string redisFluxLogFilt = redisBaseAddr + "Cache:FluxLogFilt"; diff --git a/MP.SPEC/Components/FLStatusList.razor.cs b/MP.SPEC/Components/FLStatusList.razor.cs index cf06f3a1..f25e8b8c 100644 --- a/MP.SPEC/Components/FLStatusList.razor.cs +++ b/MP.SPEC/Components/FLStatusList.razor.cs @@ -18,6 +18,8 @@ namespace MP.SPEC.Components [Parameter] public EventCallback E_TotalCount { get; set; } + [Parameter] + public EventCallback E_TotalRec { get; set; } [Parameter] public string IdxMaccSel { get; set; } = ""; @@ -80,6 +82,18 @@ namespace MP.SPEC.Components } } } + protected int TotalRecords + { + get => totRecords; + set + { + if (totRecords != value) + { + totRecords = value; + E_TotalRec.InvokeAsync(value).ConfigureAwait(false); + } + } + } #endregion Protected Properties @@ -104,6 +118,7 @@ namespace MP.SPEC.Components lastPeriodo = CurrPeriodo; ListComplete = await MDataServ.ParetoFluxLog(IdxMaccSel, CurrPeriodo.Inizio, CurrPeriodo.Fine); TotalCount = ListComplete.Count; + TotalRecords = ListComplete.Sum(x => x.Qty); FluxList = ListComplete.Select(x => x.CodFlux).ToList(); } // esegue paginazione @@ -133,6 +148,7 @@ namespace MP.SPEC.Components private string idxMaccLast = ""; private bool isProcessing = false; private int totalCount = 0; + private int totRecords = 0; #endregion Private Fields diff --git a/MP.SPEC/Data/MpDataService.cs b/MP.SPEC/Data/MpDataService.cs index 64ceb227..17cf0722 100644 --- a/MP.SPEC/Data/MpDataService.cs +++ b/MP.SPEC/Data/MpDataService.cs @@ -691,6 +691,24 @@ namespace MP.SPEC.Data return answ; } + /// + /// Funzione di Data Reduction x FluxLog + /// + /// Macchina + /// Elenco FL da processare + /// Periodo + /// modalità sel valore + /// intervallo di analisi + /// max num per intervallo + /// + public async Task FluxLogDataRedux(string idxMaccSel, List fluxList, DtUtils.Periodo currPeriodo, ValSelection valMode, DataInterval intReq, int maxItem) + { + List procStats = await dbController.FluxLogDataRedux(idxMaccSel, fluxList, currPeriodo, valMode, intReq, maxItem); + // effettuo merge statistiche... + ProcStatMerge(procStats); + await FlushCacheFluxLog(); + } + public List FluxLogDtoGetByFlux(string Valore) { List answ = new List(); @@ -760,6 +778,22 @@ namespace MP.SPEC.Data return result; } + /// + /// Stored manutenzione del DB + /// + /// Esegue realmente il task + /// Aggiornamento statistiche + /// Salvataggio + /// def: 1000 + /// def: 10 + /// def: 50 + /// + public async Task ForceDbMaint(bool doExec = true, bool doUpdStat = true, bool doSave = true, int minPgCnt = 1000, int minAvgFrag = 10, int maxAvgFragReb = 50) + { + await dbController.ForceDbMaint(doExec, doUpdStat, doSave, minPgCnt, minAvgFrag, maxAvgFragReb); + await FlushCacheFluxLog(); + } + /// /// Init ricetta /// @@ -1416,6 +1450,27 @@ namespace MP.SPEC.Data return dbResult; } + /// + /// Restituisce le statistiche di processo correnti x depluplica FluxLog + /// + /// + public List ProcFLStats() + { + List actStats = new List(); + string currKey = $"{Utils.redisStatsProcFL}"; + // recupero i record statistiche correnti + RedisValue rawData = redisDb.StringGet(currKey); + if (rawData.HasValue) + { + var rawStats = JsonConvert.DeserializeObject>($"{rawData}"); + if (rawStats != null) + { + actStats = rawStats; + } + } + return actStats; + } + /// /// Ricerca ricetta su MongoDB dato PODL /// @@ -1711,6 +1766,45 @@ namespace MP.SPEC.Data return TimeSpan.FromMinutes(rndValue); } + protected bool ProcStatMerge(List procStats) + { + bool answ = false; + List actStats = ProcFLStats(); + // se fosse vuoto --> add diretto + if (actStats.Count == 0) + { + actStats.AddRange(procStats); + } + else + { + // aggiorno su redis i record statistiche 1:1... + foreach (var recStat in procStats) + { + // cerco se ci fosse x aggiornare + var currRec = actStats.Where(x => x.IdxMacchina == recStat.IdxMacchina + && x.CodFlux == recStat.CodFlux + && x.Interval == recStat.Interval + && x.Num4Int == recStat.Num4Int).FirstOrDefault(); + // se trovato aggiorno + if (currRec != null) + { + currRec.ProcTime += recStat.ProcTime; + currRec.NumRec += recStat.NumRec; + } + // altrimenti aggiungo + else + { + actStats.Add(recStat); + } + } + } + // salvo record statistiche + var rawData = JsonConvert.SerializeObject(actStats); + string currKey = $"{Utils.redisStatsProcFL}"; + redisDb.StringSet(currKey, rawData); + return answ; + } + #endregion Protected Methods #region Private Fields @@ -1772,21 +1866,6 @@ namespace MP.SPEC.Data await RedisFlushPatternAsync(pattern); } - /// - /// Funzione di Data Reduction x FluxLog - /// - /// - /// - /// - /// - /// - /// - public async Task FluxLogDataRedux(string idxMaccSel, List fluxList, DtUtils.Periodo currPeriodo, ValSelection valMode, DataInterval intReq) - { - await dbController.FluxLogDataRedux(idxMaccSel, fluxList, currPeriodo, valMode, intReq); - await FlushCacheFluxLog(); - } - #endregion Private Methods } } \ No newline at end of file diff --git a/MP.SPEC/MP.SPEC.csproj b/MP.SPEC/MP.SPEC.csproj index eefa302b..b90e07e9 100644 --- a/MP.SPEC/MP.SPEC.csproj +++ b/MP.SPEC/MP.SPEC.csproj @@ -5,7 +5,7 @@ enable enable MP.SPEC - 6.16.2310.2112 + 6.16.2310.2320 diff --git a/MP.SPEC/Pages/FluxLogStatus.razor b/MP.SPEC/Pages/FluxLogStatus.razor index 372c0e5a..754ec856 100644 --- a/MP.SPEC/Pages/FluxLogStatus.razor +++ b/MP.SPEC/Pages/FluxLogStatus.razor @@ -3,8 +3,8 @@
-
-

FluxLogStatus

+
+

Status

@@ -25,42 +25,40 @@
-
+
+ @if (isProcessing) { - + + + } + else if (isReindexing) + { } else { - + }