public async Task <List <HistoryValueElement> > GetComponentStatusValues(ComponentStatusFilter filter, CancellationToken cancellationToken) { var result = new List <HistoryValueElement>(); await _lock.EnterAsync(cancellationToken).ConfigureAwait(false); try { var rootPath = BuildComponentStatusPath(filter.ComponentUid, filter.StatusUid); var dayPaths = BuildDayPaths(filter.RangeStart, filter.RangeEnd); foreach (var dayPath in dayPaths) { var path = Path.Combine(rootPath, dayPath.Path, ValuesFilename); if (!File.Exists(path)) { continue; } using (var fileStream = File.OpenRead(path)) { var valueStream = new HistoryValuesStream(fileStream); HistoryValueElement currentElement = null; while (await valueStream.MoveNextAsync()) { if (valueStream.CurrentToken is BeginToken beginToken) { currentElement = new HistoryValueElement { Begin = new DateTime( dayPath.Year, dayPath.Month, dayPath.Day, beginToken.Value.Hours, beginToken.Value.Minutes, beginToken.Value.Seconds, beginToken.Value.Milliseconds, DateTimeKind.Utc) }; } else if (valueStream.CurrentToken is ValueToken valueToken) { currentElement.Value = valueToken.Value; } else if (valueStream.CurrentToken is EndToken endToken) { currentElement.End = new DateTime( dayPath.Year, dayPath.Month, dayPath.Day, endToken.Value.Hours, endToken.Value.Minutes, endToken.Value.Seconds, endToken.Value.Milliseconds, DateTimeKind.Utc); result.Add(currentElement); } } } } } finally { _lock.Exit(); } return(result); }
public async Task Update(HistoryUpdate update, CancellationToken cancellationToken) { if (update is null) { throw new ArgumentNullException(nameof(update)); } await _lock.EnterAsync(cancellationToken).ConfigureAwait(false); try { var path = Path.Combine( _storageService.DataPath, "History", update.Path, BuildDayPath(update.Timestamp)); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } path = Path.Combine(path, ValuesFilename); using (var valuesStream = new HistoryValuesStream(new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))) { valuesStream.SeekEnd(); var createNewValue = true; if (await valuesStream.MovePreviousAsync(cancellationToken).ConfigureAwait(false)) { var endToken = (EndToken)valuesStream.CurrentToken; var valueIsExpired = update.Timestamp.TimeOfDay - endToken.Value > ComponentStatusOutdatedTimeout; if (!valueIsExpired) { await valuesStream.MovePreviousAsync(cancellationToken).ConfigureAwait(false); var valueToken = (ValueToken)valuesStream.CurrentToken; await valuesStream.MoveNextAsync().ConfigureAwait(false); // Move back to end token. if (string.Equals(valueToken.Value, update.Value, StringComparison.Ordinal)) { createNewValue = false; } // The end date is moved to the same value (-1 ms) as the new beginning value to fill small gaps. // The 1 ms is removed to avoid wrong comparisons when begin is exactly the same as end (which is the correct value?). var newEndTimestamp = update.Timestamp.TimeOfDay.Subtract(TimeSpan.FromMilliseconds(1)); await valuesStream.WriteTokenAsync(new EndToken(newEndTimestamp), cancellationToken).ConfigureAwait(false); await valuesStream.MoveNextAsync().ConfigureAwait(false); } } if (createNewValue) { await valuesStream.WriteTokenAsync(new BeginToken(update.Timestamp.TimeOfDay), cancellationToken).ConfigureAwait(false); await valuesStream.WriteTokenAsync(new ValueToken(update.Value), cancellationToken).ConfigureAwait(false); await valuesStream.WriteTokenAsync(new EndToken(update.Timestamp.TimeOfDay), cancellationToken).ConfigureAwait(false); } } } finally { _lock.Exit(); } }
public async Task <List <HistoryValueElement> > Read(HistoryReadOperation readOperation, CancellationToken cancellationToken) { if (readOperation is null) { throw new ArgumentNullException(nameof(readOperation)); } var result = new List <HistoryValueElement>(); var dayPaths = BuildDayPaths(readOperation.RangeStart, readOperation.RangeEnd); await _lock.EnterAsync(cancellationToken).ConfigureAwait(false); try { foreach (var dayPath in dayPaths) { var path = Path.Combine(readOperation.Path, dayPath.Path, ValuesFilename); if (!File.Exists(path)) { continue; } using (var fileStream = File.OpenRead(path)) { using (var valueStream = new HistoryValuesStream(fileStream)) { HistoryValueElement currentElement = null; while (await valueStream.MoveNextAsync().ConfigureAwait(false)) { if (valueStream.CurrentToken is BeginToken beginToken) { currentElement = new HistoryValueElement { Begin = new DateTime( dayPath.Year, dayPath.Month, dayPath.Day, beginToken.Value.Hours, beginToken.Value.Minutes, beginToken.Value.Seconds, beginToken.Value.Milliseconds, DateTimeKind.Utc) }; } else if (valueStream.CurrentToken is ValueToken valueToken) { currentElement.Value = valueToken.Value; } else if (valueStream.CurrentToken is EndToken endToken) { currentElement.End = new DateTime( dayPath.Year, dayPath.Month, dayPath.Day, endToken.Value.Hours, endToken.Value.Minutes, endToken.Value.Seconds, endToken.Value.Milliseconds, DateTimeKind.Utc); result.Add(currentElement); } } } } } } finally { _lock.Exit(); } return(result); }