public Message( long position, long endPosition, IThread t, MessageTimestamp time, StringSlice text, SeverityFlag s, StringSlice rawText = new StringSlice(), int?maxLineLen = null ) { if (endPosition < position) { throw new ArgumentException("bad message positions"); } this.thread = t; this.time = time; this.position = position; this.endPosition = endPosition; this.text = text; this.rawText = rawText; this.flags = (MessageFlag)s; if (maxLineLen != null) { this.rawText = this.rawText.Wrap(maxLineLen.Value); this.text = this.text.Wrap(maxLineLen.Value); } }
void LoadBookmarks() { using (new ScopedGuard(() => loadingLogSourceInfoFromStorageEntry = true, () => loadingLogSourceInfoFromStorageEntry = false)) using (var section = logSourceSpecificStorageEntry.OpenXMLSection("bookmarks", Persistence.StorageSectionOpenFlag.ReadOnly)) { var root = section.Data.Element("bookmarks"); if (root == null) { return; } foreach (var elt in root.Elements("bookmark")) { var time = elt.Attribute("time"); var thread = elt.Attribute("thread-id"); var name = elt.Attribute("display-name"); var position = elt.Attribute("position"); var lineIndex = elt.Attribute("line-index"); if (time != null && thread != null && name != null && position != null) { bookmarks.ToggleBookmark(bookmarks.Factory.CreateBookmark( MessageTimestamp.ParseFromLoselessFormat(time.Value), logSourceThreads.GetThread(new StringSlice(thread.Value)), name.Value, long.Parse(position.Value), (lineIndex != null) ? int.Parse(lineIndex.Value) : 0 )); } } } }
internal Bookmark(MessageTimestamp time, IThread thread, string logSourceConnectionId, string displayName, long position, int lineIndex) { this.time = time; this.thread = thread; this.displayName = displayName; this.position = position; this.logSourceConnectionId = logSourceConnectionId; this.lineIndex = lineIndex; }
public static async Task <long> LocateDateBound(IPositionedMessagesReader reader, DateTime date, ValueBound bound, CancellationToken cancellation) { var d = new MessageTimestamp(date); long begin = reader.BeginPosition; long end = reader.EndPosition; long pos = begin; long count = end - begin; for (; 0 < count;) { long count2 = count / 2; MessageTimestamp d2 = (await ReadNearestMessageTimestamp(reader, pos + count2)).GetValueOrDefault(MessageTimestamp.MaxValue); bool moveRight = false; switch (bound) { case ValueBound.Lower: case ValueBound.UpperReversed: moveRight = d2 < d; break; case ValueBound.Upper: case ValueBound.LowerReversed: moveRight = d2 <= d; break; } if (moveRight) { pos += count2 + 1; count -= count2 + 1; } else { count = count2; } cancellation.ThrowIfCancellationRequested(); } if (bound == ValueBound.LowerReversed || bound == ValueBound.UpperReversed) { long?tmp = await FindPrevMessagePosition(reader, pos); if (tmp == null) { return(begin - 1); } pos = tmp.Value; } return(pos); }
internal static bool EqualStrict(MessageTimestamp t1, MessageTimestamp t2) { DateTime d1 = t1.data; DateTime d2 = t2.data; if (d1.Kind != d2.Kind) { return(false); } return(d1 == d2); }
public MessageBase(long position, long endPosition, IThread t, MessageTimestamp time, StringSlice rawText = new StringSlice()) { if (endPosition < position) { throw new ArgumentException("bad message positions"); } this.thread = t; this.time = time; this.position = position; this.endPosition = endPosition; this.rawText = rawText; }
void MoveRangeToTime(MessageTimestamp time) { begin = end; while (begin < items.Count && items[begin].Time < time) { ++begin; } current = begin < items.Count ? items[begin].Time : MessageTimestamp.MaxValue; end = begin; while (end < items.Count && MessageTimestamp.Compare(items[end].Time, current) == 0) { ++end; } }
static public int Compare(IMessage m1, IMessage m2, bool ignoreConnectionIds = false) { int sign = MessageTimestamp.Compare(m1.Time, m2.Time); if (sign == 0) { sign = ignoreConnectionIds ? 0 : CompareLogSourceConnectionIds(m1.GetConnectionId(), m2.GetConnectionId()); if (sign == 0) { sign = Math.Sign(m1.Position - m2.Position); } } return(sign); }
public static bool TryParse(string str, out ITimeOffsets value) { value = null; if (str == null) { return(false); } var entries = new List <Entry>(); bool firstPart = true; foreach (var part in str.Split(',')) { var entry = new Entry(); if (firstPart) { firstPart = false; if (!TimeSpan.TryParseExact(part, "c", null, out entry.offset)) { return(false); } entry.at = DateTime.MinValue; } else { var components = part.Split('='); if (components.Length != 2) { return(false); } if (!TimeSpan.TryParseExact(components[1], "c", null, out entry.offset)) { return(false); } entry.at = MessageTimestamp.ParseFromLoselessFormat(components[0]).ToUnspecifiedTime(); } entries.Add(entry); } if (entries.Count == 0) { return(false); } entries.Sort((e1, e2) => Math.Sign(e2.at.Ticks - e1.at.Ticks)); value = new TimeOffsets(entries); return(true); }
static public int Compare(IBookmark b1, IBookmark b2, bool ignoreConnectionIds = false) { int sign = MessageTimestamp.Compare(b1.Time, b2.Time); if (sign == 0) { sign = ignoreConnectionIds ? 0 : CompareLogSourceConnectionIds(b1.LogSourceConnectionId, b2.LogSourceConnectionId); if (sign == 0) { sign = Math.Sign(b1.Position - b2.Position); if (sign == 0) { sign = Math.Sign(b1.LineIndex - b2.LineIndex); } } } return(sign); }
public int Compare(LogPart x, LogPart y) { int tmp; tmp = MessageTimestamp.Compare(x.FirstMessageTime, y.FirstMessageTime); if (tmp != 0) { return(tmp); } tmp = string.Compare(x.FileName, y.FileName, true); if (tmp != 0) { return(tmp); } return(tmp); }
public static int Compare(MessageTimestamp t1, MessageTimestamp t2) { DateTime d1 = t1.data; DateTime d2 = t2.data; DateTimeKind k1 = d1.Kind; DateTimeKind k2 = d2.Kind; if (NormalizeKindForComparision(k1) == NormalizeKindForComparision(k2)) { return(DateTime.Compare(d1, d2)); } if (k1 == DateTimeKind.Utc) { d1 = t1.ToLocalDateTime(); } else { d2 = t2.ToLocalDateTime(); } return(DateTime.Compare(d1, d2)); }
int IComparer <Entry> .Compare(Entry e1, Entry e2) { int cmpResult; long idxDiff = e1.index - e2.index; if (Math.Abs(idxDiff) > bufferSize) { return(Math.Sign(idxDiff)); } var x = e1.data; var y = e2.data; cmpResult = inversionFlag * MessageTimestamp.Compare(x.Message.Time, y.Message.Time); if (cmpResult != 0) { return(cmpResult); } cmpResult = inversionFlag * Math.Sign(x.Message.Position - y.Message.Position); return(cmpResult); }
bool HandleResponse(DateBoundPositionResponseData res, bool reversedMode) { using (trace.NewFrame) { Predicate <MessageTimestamp> shouldAdvanceDate = d => reversedMode ? d > currentDate : d < currentDate; bool readerAdvanced = false; trace.Info("reader returned ({0}, {1})", res.Position, res.Message?.Time); trace.Info("reader's current position: {0}", currentPosition); bool advancePosition = true; if (reversedMode) { if (res.IsBeforeBeginPosition) { trace.Info("it's invalid position (before begin)"); advancePosition = false; } } else { if (res.IsEndPosition) { trace.Info("it's invalid position (end)"); advancePosition = false; } } if (advancePosition && res.Position > currentPosition) { trace.Info("reader has advanced its position: {0}", res.Position); readerAdvanced = true; currentPosition = res.Position; } bool advanceDate; if (res.Message == null) { advanceDate = false; } else { advanceDate = shouldAdvanceDate(res.Message.Time); } if (advanceDate) { trace.Info("reader might need to advance the current date from {0} to {1}. Getting writer lock to make final decision...", currentDate, res.Message.Time); if (shouldAdvanceDate(res.Message.Time)) { trace.Info("reader is really advancing the current date from {0} to {1}", currentDate, res.Message.Time); currentDate = res.Message.Time; } else { trace.Info("false alarm: reader is not advancing the current date because it has been already advanced to {0} by some other reader", currentDate); } } return(readerAdvanced); } }
IBookmark IBookmarksFactory.CreateBookmark(MessageTimestamp time) { return(new Bookmark(time)); }
public Bookmark(MessageTimestamp time) : this(time, null, null, null, 0, 0) { }
public Bookmark(MessageTimestamp time, string sourceConnectionId, long position, int lineIndex) : this(time, null, sourceConnectionId, "", "", position, lineIndex) { }
public Bookmark(MessageTimestamp time, IThread thread, string displayName, string messageText, long position, int lineIndex) : this(time, thread, thread != null && !thread.IsDisposed && thread.LogSource != null ? thread.LogSource.Provider.ConnectionId : "", displayName, messageText, position, lineIndex) { }
IBookmark IBookmarksFactory.CreateBookmark(MessageTimestamp time, IThread thread, string displayName, long position, int lineIndex) { return(new Bookmark(time, thread, displayName, position, lineIndex)); }
IBookmark IBookmarksFactory.CreateBookmark(MessageTimestamp time, string sourceConnectionId, long position, int lineIndex) { return(new Bookmark(time, sourceConnectionId, position, lineIndex)); }
public async Task <ResultCode> MoveToDateBound(DateTime d, bool reversedMode) { using (trace.NewFrame) { trace.Info("Moving to the date {0} than '{1}' by sending 'get {2} bound' request to all readers", reversedMode ? "less (or eq)" : "greater (or eq)", d, reversedMode ? "lower (rev)" : "lower"); ResultCode resultCode; if (reversedMode) { currentDate = MessageTimestamp.MinValue; } else { currentDate = MessageTimestamp.MaxValue; } Task <DateBoundPositionResponseData> getBoundsTask = null; for (int iteration = 0; ; ++iteration) { trace.Info("it's iteration {0} of trying to send the 'get date bound' request to reader", iteration); var modelThreadCall = invoke.Invoke(() => { // This code must be executing in the model thread using (trace.NewFrame) { if (source.IsDisposed) { trace.Warning("reader is disposed"); // This TimeGapsDetector is probably disposed too or will be soon. // Returning null will make the main algorithm wait. // During waiting it'll detect stop condition. return(null); } trace.Info("the reader is idling. Getting date bound."); return(source.GetDateBoundPosition(d, reversedMode ? ValueBound.LowerReversed : ValueBound.Lower, CancellationToken.None )); // todo: cancellation } }); trace.Info("waiting the completion of 'get date bound' request scheduler"); if (IsStopOrInvalidate(resultCode = await owner.WaitEvents(Timeout.Infinite, modelThreadCall))) { return(resultCode); } getBoundsTask = await modelThreadCall; if (getBoundsTask != null) { trace.Info("the 'get date bound' request was successfully sent to reader."); break; } trace.Info("reader is not handled. Waiting..."); if (IsStopOrInvalidate(resultCode = await owner.WaitEvents(1000, null))) { return(resultCode); } } trace.Info("waiting for the response from the reader"); if (IsStopOrInvalidate(resultCode = await owner.WaitEvents(30000, getBoundsTask))) { return(resultCode); } if (resultCode != ResultCode.UserEvent) { trace.Warning("reader didn't respond. Giving up by invalidating current progress."); return(ResultCode.Invalidate); } bool ret = HandleResponse(await getBoundsTask, reversedMode); trace.Info("returning {0}", ret); return(ret ? ResultCode.Ok : ResultCode.None); } }
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 InvalidateEverythingThatHasBeenLoaded(); } firstMessage = null; } // Try to get the dates range for new bounday messages DateRange newAvailTime = GetAvailableDateRangeHelper(newFirst, newLast); firstMessage = newFirst; // Getting here means that the boundaries changed. // Fire the notfication. 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 = reader.SizeInBytes; 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); }
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 greater 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 because 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); } }