/// <summary> /// Gets the trend table from the cache, creating a table if necessary. /// </summary> private TrendTable GetTrendTable(DateTime timestamp) { DateTime tableDate = timestamp.Date; if (currentTable != null && currentTable.TableDate == tableDate) { return(currentTable); } else if (updatedTable != null && updatedTable.TableDate == tableDate) { return(updatedTable); } else { TrendTable trendTable = tableCache.Get(tableDate); if (trendTable == null) { trendTable = new TrendTable(tableDate, writingPeriod) { CnlNumList = cnlNumList }; tableCache.Add(tableDate, trendTable); } return(trendTable); } }
/// <summary> /// Gets the trends of the specified channels. /// </summary> public override TrendBundle GetTrends(TimeRange timeRange, int[] cnlNums) { stopwatch.Restart(); TrendBundle trendBundle; List <TrendBundle> bundles = new List <TrendBundle>(); int totalCapacity = 0; foreach (DateTime date in EnumerateDates(timeRange)) { TrendTable trendTable = GetTrendTable(date); TrendBundle bundle = adapter.ReadTrends(trendTable, timeRange, cnlNums); bundles.Add(bundle); totalCapacity += bundle.Timestamps.Count; } if (bundles.Count <= 0) { trendBundle = new TrendBundle(cnlNums, 0); } else if (bundles.Count == 1) { trendBundle = bundles[0]; } else { // unite bundles trendBundle = new TrendBundle(cnlNums, totalCapacity); foreach (TrendBundle bundle in bundles) { trendBundle.Timestamps.AddRange(bundle.Timestamps); for (int i = 0, trendCnt = trendBundle.Trends.Count; i < trendCnt; i++) { trendBundle.Trends[i].AddRange(bundle.Trends[i]); } } } stopwatch.Stop(); arcLog?.WriteAction(ServerPhrases.ReadingTrendsCompleted, trendBundle.Timestamps.Count, stopwatch.ElapsedMilliseconds); return(trendBundle); }
/// <summary> /// Gets the available timestamps. /// </summary> public override List <DateTime> GetTimestamps(TimeRange timeRange) { stopwatch.Restart(); List <DateTime> resultTimestamps; List <List <DateTime> > listOfTimestamps = new List <List <DateTime> >(); int totalCapacity = 0; foreach (DateTime date in EnumerateDates(timeRange)) { TrendTable trendTable = GetTrendTable(date); List <DateTime> timestamps = adapter.ReadTimestamps(trendTable, timeRange); listOfTimestamps.Add(timestamps); totalCapacity += timestamps.Count; } if (listOfTimestamps.Count <= 0) { resultTimestamps = new List <DateTime>(); } else if (listOfTimestamps.Count == 1) { resultTimestamps = listOfTimestamps[0]; } else { // unite timestamps resultTimestamps = new List <DateTime>(totalCapacity); foreach (List <DateTime> timestamps in listOfTimestamps) { resultTimestamps.AddRange(timestamps); } } stopwatch.Stop(); arcLog?.WriteAction(ServerPhrases.ReadingTimestampsCompleted, resultTimestamps.Count, stopwatch.ElapsedMilliseconds); return(resultTimestamps); }
/// <summary> /// Gets the trend of the specified channel. /// </summary> public override Trend GetTrend(TimeRange timeRange, int cnlNum) { stopwatch.Restart(); Trend resultTrend; List <Trend> trends = new List <Trend>(); int totalCapacity = 0; foreach (DateTime date in EnumerateDates(timeRange)) { TrendTable trendTable = GetTrendTable(date); Trend trend = adapter.ReadTrend(trendTable, timeRange, cnlNum); trends.Add(trend); totalCapacity += trend.Points.Count; } if (trends.Count <= 0) { resultTrend = new Trend(cnlNum, 0); } else if (trends.Count == 1) { resultTrend = trends[0]; } else { // unite trends resultTrend = new Trend(cnlNum, totalCapacity); foreach (Trend trend in trends) { resultTrend.Points.AddRange(trend.Points); } } stopwatch.Stop(); arcLog?.WriteAction(ServerPhrases.ReadingTrendCompleted, resultTrend.Points.Count, stopwatch.ElapsedMilliseconds); return(resultTrend); }
private TrendTable updatedTable; // the trend table that is currently being updated /// <summary> /// Initializes a new instance of the class. /// </summary> public BasicHAL(IArchiveContext archiveContext, ArchiveConfig archiveConfig, int[] cnlNums, ModuleConfig moduleConfig) : base(archiveContext, archiveConfig, cnlNums) { this.moduleConfig = moduleConfig ?? throw new ArgumentNullException(nameof(moduleConfig)); options = new BasicHAO(archiveConfig.CustomOptions); appLog = archiveContext.Log; arcLog = options.LogEnabled ? CreateLog(ModuleUtils.ModuleCode) : null; stopwatch = new Stopwatch(); adapter = new TrendTableAdapter { ArchiveCode = Code, CnlNumCache = new MemoryCache <long, CnlNumList>(ModuleUtils.CacheExpiration, ModuleUtils.CacheCapacity) }; tableCache = new MemoryCache <DateTime, TrendTable>(ModuleUtils.CacheExpiration, ModuleUtils.CacheCapacity); slice = new Slice(DateTime.MinValue, cnlNums); writingPeriod = GetPeriodInSec(options.WritingPeriod, options.WritingUnit); nextWriteTime = DateTime.MinValue; cnlIndexes = null; cnlNumList = new CnlNumList(cnlNums); currentTable = null; updatedTable = null; }
private TrendTable updatedTable; // the trend table that is currently being updated /// <summary> /// Initializes a new instance of the class. /// </summary> public BasicHAL(IArchiveContext archiveContext, ArchiveConfig archiveConfig, int[] cnlNums) : base(archiveContext, archiveConfig, cnlNums) { options = new BasicHAO(archiveConfig.CustomOptions); appLog = archiveContext.Log; arcLog = options.LogEnabled ? CreateLog(ModuleUtils.ModuleCode) : null; stopwatch = new Stopwatch(); adapter = new TrendTableAdapter { ParentDirectory = Path.Combine(archiveContext.AppConfig.PathOptions.GetArcDir(options.IsCopy), Code), ArchiveCode = Code, CnlNumCache = new MemoryCache <long, CnlNumList>(ModuleUtils.CacheExpiration, ModuleUtils.CacheCapacity) }; tableCache = new MemoryCache <DateTime, TrendTable>(ModuleUtils.CacheExpiration, ModuleUtils.CacheCapacity); slice = new Slice(DateTime.MinValue, cnlNums); writingPeriod = GetPeriodInSec(options.WritingPeriod, options.WritingUnit); nextWriteTime = DateTime.MinValue; cnlIndexes = null; cnlNumList = new CnlNumList(cnlNums); currentTable = null; updatedTable = null; }
/// <summary> /// Processes new data. /// </summary> public override bool ProcessData(ICurrentData curData) { if (options.WritingMode == WritingMode.AutoWithPeriod && nextWriteTime <= curData.Timestamp) { DateTime writeTime = GetClosestWriteTime(curData.Timestamp, writingPeriod); nextWriteTime = writeTime.AddSeconds(writingPeriod); stopwatch.Restart(); TrendTable trendTable = GetCurrentTrendTable(writeTime); InitCnlIndexes(curData, ref cnlIndexes); CopyCnlData(curData, slice, cnlIndexes); slice.Timestamp = writeTime; adapter.WriteSlice(trendTable, slice); stopwatch.Stop(); arcLog?.WriteAction(ServerPhrases.WritingSliceCompleted, slice.CnlNums.Length, stopwatch.ElapsedMilliseconds); return(true); } else { return(false); } }
/// <summary> /// Gets the today's trend table, creating it if necessary. /// </summary> private TrendTable GetCurrentTrendTable(DateTime nowDT) { DateTime today = nowDT.Date; if (currentTable == null) { currentTable = new TrendTable(today, writingPeriod) { CnlNumList = cnlNumList }; currentTable.SetDefaultMetadata(); } else if (currentTable.TableDate != today) // current date is changed { tableCache.Add(currentTable.TableDate, currentTable); currentTable = new TrendTable(today, writingPeriod) { CnlNumList = cnlNumList }; currentTable.SetDefaultMetadata(); } return(currentTable); }
/// <summary> /// Checks and updates the today's trend table. /// </summary> private void CheckCurrentTrendTable(DateTime nowDT) { currentTable = GetCurrentTrendTable(nowDT); string tableDir = adapter.GetTablePath(currentTable); string metaFileName = adapter.GetMetaPath(currentTable); if (Directory.Exists(tableDir)) { TrendTableMeta srcTableMeta = adapter.ReadMetadata(metaFileName); if (srcTableMeta == null) { // the existing table is invalid and should be deleted Directory.Delete(tableDir, true); } else if (srcTableMeta.Equals(currentTable.Metadata)) { if (currentTable.GetDataPosition(nowDT, PositionKind.Ceiling, out TrendTablePage page, out _)) { string pageFileName = adapter.GetPagePath(page); CnlNumList srcCnlNums = adapter.ReadCnlNums(pageFileName); if (srcCnlNums == null) { // make sure that there is no page file File.Delete(pageFileName); } else if (srcCnlNums.Equals(cnlNumList)) { // re-create the channel list to use the existing list ID cnlNumList = new CnlNumList(srcCnlNums.ListID, cnlNumList); } else { // update the current page string msg = string.Format(Locale.IsRussian ? "Обновление номеров каналов страницы {0}" : "Update channel numbers of the page {0}", pageFileName); appLog.WriteAction(ServerPhrases.ArchiveMessage, Code, msg); arcLog?.WriteAction(msg); adapter.UpdatePageChannels(page, srcCnlNums); } } } else { // updating the entire table structure would take too long, so just backup the table string msg = string.Format(Locale.IsRussian ? "Резервное копирование таблицы {0}" : "Backup the table {0}", tableDir); appLog.WriteAction(ServerPhrases.ArchiveMessage, Code, msg); arcLog?.WriteAction(msg); adapter.BackupTable(currentTable); } } // create an empty table if it does not exist if (!Directory.Exists(tableDir)) { adapter.WriteMetadata(metaFileName, currentTable.Metadata); currentTable.IsReady = true; } // add the archive channel list to the cache adapter.CnlNumCache.Add(cnlNumList.ListID, cnlNumList); }
/// <summary> /// Completes the update operation. /// </summary> public override void EndUpdate(DateTime timestamp, int deviceNum) { updatedTable = null; stopwatch.Stop(); arcLog?.WriteAction(ServerPhrases.UpdateCompleted, stopwatch.ElapsedMilliseconds); }
/// <summary> /// Maintains performance when data is written one at a time. /// </summary> public override void BeginUpdate(DateTime timestamp, int deviceNum) { stopwatch.Restart(); updatedTable = GetTrendTable(timestamp); }