/// <summary> /// Renders RulerIntervals to the sequence of marks ready to be painted on the screen /// </summary> public static IEnumerable <TimeRulerMark> GenerateTimeRulerMarks(TimeRulerIntervals intervals, DateRange range) { RulerIntervalInternal major = new RulerIntervalInternal(intervals.Major); RulerIntervalInternal minor = new RulerIntervalInternal(intervals.Minor); DateTime lastMajor = DateTime.MaxValue; for (DateTime d = major.StickToIntervalBounds(range.Begin); d < range.End; d = minor.MoveDate(d)) { if (d < range.Begin) { continue; } if (!major.IsHiddenWhenMajor) { DateTime tmp = major.StickToIntervalBounds(d); if (tmp >= range.Begin && tmp != lastMajor) { yield return(new TimeRulerMark(tmp, true, major.Component)); lastMajor = tmp; if (tmp == d) { continue; } } yield return(new TimeRulerMark(d, false, minor.Component)); } else { yield return(new TimeRulerMark(d, true, minor.Component)); } } }
async Task <ResultCode> FindGaps(DateRange range, TimeSpan threshold, int?maxGapsCount, List <TimeGap> ret) { using (trace.NewFrame) { trace.Info("threshold={0}", threshold.ToString()); if (threshold.Ticks == 0) { trace.Warning("threshold is empty"); return(ResultCode.None); } ResultCode resultCode = ResultCode.None; Helper helper = new Helper(this); // Below is the actual algorithm of finding the gaps: // - we start from the begin of the range (d = range.Begin). // On the first iteration we find the positions of the messages // that have the date less than d. // - on the next iterations we are finding out if there are messages // with the date less than (d + threshold) with position different from // the current positions. If yes, then there is no gap on // interval (d, d + threshold). // - If no messages are found on the interval then we encountered with // a time gap. The end of the gap is located by searching for the // first message that is greated than d. TimeSpan cumulativeGapsLen = new TimeSpan(); for (DateTime d = range.Begin; d < range.End;) { trace.Info("moving to the lower bound of {0}", d); if (IsStopOrInvalidate(resultCode = await helper.MoveToDateBound(d, reversedMode: true))) { return(resultCode); } if (resultCode == ResultCode.Ok) { trace.Info("moved successfully. The lower bound is {0}.", helper.CurrentDate); d = helper.CurrentDate.Advance(threshold).ToLocalDateTime(); } else { var gapBegin = helper.CurrentDate.ToLocalDateTime(); // A tick is needed here becuase CurrentDate is a date of an existing message. // The gap begins right after this date. This tick matters when // we are comparing gap's date range with a date range of messages. // Do not forget: date ranges use the idea that DateRange.End doesn't belong // to the range. gapBegin = gapBegin.AddTicks(1); trace.Info("no readers advanced. It's time gap starting at {0}", gapBegin); trace.Info("moving to the date greater than {0}", d); if (IsStopOrInvalidate(resultCode = await helper.MoveToDateBound(d, reversedMode: false))) { return(resultCode); } DateTime gapEnd = helper.CurrentDate.ToLocalDateTime(); trace.Info("the end of the gap: {0}", gapEnd); if (MessageTimestamp.Compare(helper.CurrentDate, MessageTimestamp.MaxValue) != 0) { d = helper.CurrentDate.Advance(threshold).ToLocalDateTime(); } else { d = DateTime.MaxValue; } var gap = new TimeGap(new DateRange(gapBegin, gapEnd)); trace.Info("creating new gap {0}", gap); ret.Add(gap); if (maxGapsCount.HasValue && ret.Count > maxGapsCount.Value) { throw new TooManyGapsException(); } cumulativeGapsLen += gap.Range.Length; } } trace.Info("returning {0} gaps", ret.Count); return(ResultCode.None); } }
public TimeGap(DateRange r) { this.range = r; }
public LifetimeBar(DateRange lifetime, string label) { Lifetime = lifetime; Label = label; }
async Task <bool> UpdateAvailableTime(bool incrementalMode) { bool itIsFirstUpdate = firstUpdateFlag; firstUpdateFlag = false; UpdateBoundsStatus status = reader.UpdateAvailableBounds(incrementalMode); if (status == UpdateBoundsStatus.NothingUpdated && incrementalMode) { return(false); } if (status == UpdateBoundsStatus.OldMessagesAreInvalid) { incrementalMode = false; } // Get new boundary values into temporary variables IMessage newFirst, newLast; PositionedMessagesUtils.GetBoundaryMessages(reader, null, out newFirst, out newLast); if (firstMessage != null) { if (newFirst == null || MessageTimestamp.Compare(newFirst.Time, firstMessage.Time) != 0) { // The first message we've just read differs from the cached one. // This means that the log was overwritten. Fall to non-incremental mode. incrementalMode = false; } } if (!incrementalMode) { if (!itIsFirstUpdate) { // Reset everything that has been loaded so far await InvalidateEverythingThatHasBeenLoaded(); } firstMessage = null; } // Try to get the dates range for new boundary messages DateRange newAvailTime = GetAvailableDateRangeHelper(newFirst, newLast); firstMessage = newFirst; // Getting here means that the boundaries changed. // Fire the notification. var positionsRange = new FileRange.Range(reader.BeginPosition, reader.EndPosition); if (!incrementalMode) { readerContentsEtag = reader.GetContentsEtag(); } int contentsEtag = readerContentsEtag ^ positionsRange.Begin.GetHashCode() ^ positionsRange.End.GetHashCode(); StatsTransaction(stats => { stats.AvailableTime = newAvailTime; LogProviderStatsFlag f = LogProviderStatsFlag.AvailableTime; if (incrementalMode) { f |= LogProviderStatsFlag.AvailableTimeUpdatedIncrementallyFlag; } stats.TotalBytes = CalcTotalBytesStats(reader); f |= LogProviderStatsFlag.BytesCount; stats.PositionsRange = positionsRange; f |= LogProviderStatsFlag.PositionsRange; stats.PositionsRangeUpdatesCount++; if (stats.ContentsEtag == null || contentsEtag != stats.ContentsEtag.Value) { stats.ContentsEtag = contentsEtag; f |= LogProviderStatsFlag.ContentsEtag; } return(f); }); return(true); }