Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some features have been implemented #105

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Source/TailBlazer.Domain/FileHandling/EmptyLineProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ namespace TailBlazer.Domain.FileHandling
public class EmptyLineProvider: ILineProvider
{
public int Count { get; } = 0;

public ILineProvider Previous { get; } = null;
public ILineProvider Next { get; set; } = null;
public int NumberOfPreviousProvider { get; } = 0;

public IEnumerable<Line> ReadLines(ScrollRequest scroll)
{
yield break;
Expand Down
2 changes: 1 addition & 1 deletion Source/TailBlazer.Domain/FileHandling/FileNotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
if (obj.GetType() != GetType()) return false;
return Equals((FileNotification) obj);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public enum FileNotificationType
CreatedOrOpened,
Changed,
Missing,
Error,
Error
}
}
1 change: 0 additions & 1 deletion Source/TailBlazer.Domain/FileHandling/FileSearchEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using TailBlazer.Domain.FileHandling.Search;

namespace TailBlazer.Domain.FileHandling
{
Expand Down
248 changes: 169 additions & 79 deletions Source/TailBlazer.Domain/FileHandling/FileSearchResult.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using DynamicData;
using DynamicData.Kernel;
using TailBlazer.Domain.FileHandling.Search;

namespace TailBlazer.Domain.FileHandling
{
Expand All @@ -15,25 +16,11 @@ public interface IProgressInfo
bool IsSearching { get; }
}

public class FileSearchResult: ILineProvider, IEquatable<FileSearchResult>, IHasLimitationOfLines, IProgressInfo
public class FileSearchResult : ILineProvider, IEquatable<FileSearchResult>, IHasLimitationOfLines, IProgressInfo
{
public static readonly FileSearchResult None = new FileSearchResult();
public long[] Matches { get; }
public int Count => Matches.Length;
public int SegmentsCompleted { get; }
public int Segments { get; }
public bool IsSearching { get; }
public bool HasReachedLimit { get; }
public int Maximum { get; }

private readonly IDictionary<FileSegmentKey, FileSegmentSearch> _allSearches;

private FileSegmentSearch LastSearch { get; }
private FileInfo Info { get; }
private Encoding Encoding { get; }
private TailInfo TailInfo { get; }
private long Size { get; }

public FileSearchResult(FileSegmentSearch initial,
FileInfo info,
Encoding encoding,
Expand All @@ -57,7 +44,7 @@ public FileSearchResult(FileSegmentSearch initial,
HasReachedLimit = false;
}

public FileSearchResult(FileSearchResult previous,
public FileSearchResult(FileSearchResult previous,
FileSegmentSearch current,
FileInfo info,
Encoding encoding,
Expand All @@ -73,28 +60,67 @@ public FileSearchResult(FileSearchResult previous,
var lastTail = _allSearches.Lookup(FileSegmentKey.Tail);
if (current.Segment.Type == FileSegmentType.Tail)
{
TailInfo = lastTail.HasValue
? new TailInfo(lastTail.Value.Segment.End)
: new TailInfo(current.Segment.End);
TailInfo = lastTail.HasValue
? new TailInfo(lastTail.Value.Segment.End)
: new TailInfo(current.Segment.End);
}
else
{
TailInfo = lastTail.HasValue
? previous.TailInfo
: TailInfo.None;
TailInfo = lastTail.HasValue
? previous.TailInfo
: TailInfo.None;
}

_allSearches[current.Key] = current;
var all = _allSearches.Values.ToArray();

IsSearching = all.Any(s => s.Segment.Type == FileSegmentType.Head && s.Status != FileSegmentSearchStatus.Complete);
IsSearching =
all.Any(s => s.Segment.Type == FileSegmentType.Head && s.Status != FileSegmentSearchStatus.Complete);
Segments = all.Length;
SegmentsCompleted = all.Count(s => s.Segment.Type == FileSegmentType.Head && s.Status == FileSegmentSearchStatus.Complete);
SegmentsCompleted =
all.Count(s => s.Segment.Type == FileSegmentType.Head && s.Status == FileSegmentSearchStatus.Complete);
Size = all.Last().Segment.End;

//For large sets this could be very inefficient
Matches = all.SelectMany(s => s.Lines).OrderBy(l=>l).ToArray();
Matches = all.SelectMany(s => s.Lines).OrderBy(l => l).ToArray();
HasReachedLimit = Matches.Length >= limit;

//skip the same file in here, because we do not want to store in the list.
if (previous.Info.FullName != info.FullName)
{
var prevPointer = previous;
//seek to the end of the linked list
while (prevPointer?.Next != null)
{
prevPointer = prevPointer.Next as FileSearchResult;
}
var lastPrevPointer = default(FileSearchResult);
//find the modified file and replace from the list
while (prevPointer != null)
{
if (prevPointer.Info.FullName == Info.FullName && prevPointer.Count != Count)
{
Next = prevPointer.Next;
Previous = prevPointer.Previous;
if (lastPrevPointer != null)
{
lastPrevPointer.Previous = this;
}
prevPointer.Previous = null;
prevPointer.Next = null;
NumberOfPreviousProvider = prevPointer.NumberOfPreviousProvider;
return;
}
lastPrevPointer = prevPointer;
prevPointer = prevPointer.Previous as FileSearchResult;
}

//build the linked list in here
Previous = previous;
previous.Next = this;
NumberOfPreviousProvider = previous.NumberOfPreviousProvider + 1;
}

}

private FileSearchResult()
Expand All @@ -103,80 +129,142 @@ private FileSearchResult()
HasReachedLimit = false;
}

public long[] Matches { get; }
private FileSegmentSearch LastSearch { get; }
private FileInfo Info { get; }
private Encoding Encoding { get; }
private TailInfo TailInfo { get; }
private long Size { get; }
public bool IsEmpty => this == None;
public bool HasReachedLimit { get; }
public int Maximum { get; }
public int Count => Matches.Length;
public ILineProvider Previous { get; set; }
public ILineProvider Next { get; set; }
public int NumberOfPreviousProvider { get; }

public IEnumerable<Line> ReadLines(ScrollRequest scroll)
{


var page = GetPage(scroll);

var current = ReverseLinking(this);
var page = GetPage(scroll, this);
var lastValueWrapper = new LastValueWrapper();
if (page.Size == 0) yield break;

using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read,FileShare.Delete | FileShare.ReadWrite))
while (current != null)
{

using (var reader = new StreamReaderExtended(stream, Encoding, false))
using (
var stream = File.Open(current.Info.FullName, FileMode.Open, FileAccess.Read,
FileShare.Delete | FileShare.ReadWrite))
{
if (page.Size == 0) yield break;

foreach (var i in Enumerable.Range(page.Start, page.Size))
using (var reader = new StreamReaderExtended(stream, current.Encoding, false))
{
if (i > Count - 1) continue;

var start = Matches[i];
var startPosition = reader.AbsolutePosition();
if (page.Size == 0) yield break;

if (startPosition != start)
if (lastValueWrapper.LastPageIndex == page.Start + page.Size)
{
reader.DiscardBufferedData();
reader.BaseStream.Seek(start, SeekOrigin.Begin);
yield break;
}
var counter = 0;
long lastEndPos = 0;
foreach (
var i in
Enumerable.Range(
lastValueWrapper.LastPageIndex > 0 ? lastValueWrapper.LastPageIndex : page.Start,
page.Size - counter))
{
if (i == page.Start + page.Size)
{
yield break;
}
if (i - lastValueWrapper.LastMatchesSize > current.Count - 1)
{
lastValueWrapper.LastEndPosition += lastEndPos + 1;
lastValueWrapper.LastMatchesSize += current.Count;
break;
}

var start = current.Matches[i - lastValueWrapper.LastMatchesSize];
var startPosition = reader.AbsolutePosition();

if (startPosition != start)
{
reader.DiscardBufferedData();
reader.BaseStream.Seek(start, SeekOrigin.Begin);
}

startPosition = reader.AbsolutePosition();

var line = reader.ReadLine();
var endPosition = reader.AbsolutePosition();
var info = new LineInfo(i + 1, i, startPosition + lastValueWrapper.LastEndPosition,
endPosition + lastValueWrapper.LastEndPosition);

var ontail = endPosition >= TailInfo.TailStartsAt &&
DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds < 1
? DateTime.Now
: (DateTime?) null;

yield return new Line(info, line, ontail);

lastValueWrapper.LastPageIndex = i + 1;
counter++;
lastEndPos = endPosition;

if (reader.EndOfStream)
{
lastValueWrapper.LastEndPosition += endPosition + 1;
lastValueWrapper.LastMatchesSize += current.Count;
break;
}
}

startPosition = reader.AbsolutePosition();

var line = reader.ReadLine();
var endPosition = reader.AbsolutePosition();
var info = new LineInfo(i + 1, i, startPosition, endPosition);

var ontail = endPosition >= TailInfo.TailStartsAt && DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds<1
? DateTime.Now
: (DateTime?)null;

yield return new Line(info, line, ontail);
}
}
current = current.Next as FileSearchResult;
}
}


private Page GetPage(ScrollRequest scroll)
private FileSearchResult ReverseLinking(FileSearchResult fsr)
{
int first;
if (scroll.SpecifiedByPosition)
//reverse link of list
var current = fsr;
while (current?.NumberOfPreviousProvider != 0)
{
//get line number fro
first = IndexOf(scroll.Position);
if (current?.Previous != null)
{
current.Previous.Next = current;
}
current = current?.Previous as FileSearchResult;
}
else
return current;
}

public int SegmentsCompleted { get; }
public int Segments { get; }
public bool IsSearching { get; }

private Page GetPage(ScrollRequest scroll, FileSearchResult fileSearchResult)
{
var first = scroll.SpecifiedByPosition ? IndexOf(scroll.Position) : scroll.FirstIndex;
var chainSize = 0;
while (fileSearchResult != null)
{
first = scroll.FirstIndex;
chainSize += fileSearchResult.Count;
fileSearchResult = fileSearchResult.Previous as FileSearchResult;
}
int size = scroll.PageSize;

var size = scroll.PageSize;

if (scroll.Mode == ScrollReason.Tail)
{
first = size > Count ? 0 : Count - size;
first = size > chainSize ? 0 : chainSize - size;
}
else
{
if (scroll.FirstIndex + size >= Count)
first = Count - size;
if (scroll.FirstIndex + size >= chainSize)
first = chainSize - size;
}

first = Math.Max(0, first);
size = Math.Min(size, Count);
size = Math.Min(size, chainSize);

return new Page(first, size);
}
Expand All @@ -190,20 +278,28 @@ private int IndexOf(long value)
return -1;
}

public override string ToString()
{
return this == None
? "<None>"
: $"Count: {Count}, Segments: {Segments}, Size: {Size}, Previous: {NumberOfPreviousProvider}";
}

#region Equality

public bool Equals(FileSearchResult other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(Matches, other.Matches) && SegmentsCompleted == other.SegmentsCompleted && Segments == other.Segments && IsSearching == other.IsSearching;
return Equals(Matches, other.Matches) && SegmentsCompleted == other.SegmentsCompleted &&
Segments == other.Segments && IsSearching == other.IsSearching;
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
if (obj.GetType() != GetType()) return false;
return Equals((FileSearchResult) obj);
}

Expand All @@ -230,11 +326,5 @@ public override int GetHashCode()
}

#endregion

public override string ToString()
{
return this == None ? "<None>" : $"Count: {Count}, Segments: {Segments}, Size: {Size}";
}

}
}
Loading