Skip to content

Commit

Permalink
Replace manually sorted list with SortedDictionary
Browse files Browse the repository at this point in the history
  • Loading branch information
ilabutin committed Jun 30, 2017
1 parent e87435c commit 8a17736
Showing 1 changed file with 27 additions and 77 deletions.
104 changes: 27 additions & 77 deletions src/TraceEvent/TraceUtilities/HistoryDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal class HistoryDictionary<T>
{
public HistoryDictionary(int initialSize)
{
entries = new Dictionary<long, HistoryValue>(initialSize);
entries = new Dictionary<long, SortedDictionary<long, T>>(initialSize);
}
/// <summary>
/// Adds the association that 'id' has the value 'value' from 'startTime100ns' ONWARD until
Expand All @@ -25,80 +25,48 @@ public HistoryDictionary(int initialSize)
/// </summary>
public void Add(Address id, long startTime, T value, bool isEndRundown = false)
{
HistoryValue entry;
SortedDictionary<long, T> entry;
if (!entries.TryGetValue((long)id, out entry))
{
// rundown events are 'last chance' events that we only add if we don't already have an entry for it.
if (isEndRundown)
startTime = 0;
entries.Add((long)id, new HistoryValue(startTime, id, value));
var newEntry = new SortedDictionary<long, T>();
newEntry.Add(startTime, value);
entries.Add((long)id, newEntry);
count++;
}
else
{
Debug.Assert(entry != null);
var firstEntry = entry;

// See if we can jump ahead. Currently we only do this of the first entry,
// But you could imagine using some of the other nodes's skipAhead entries.
if (firstEntry.skipAhead != null && firstEntry.skipAhead.startTime < startTime)
entry = firstEntry.skipAhead;

for (; ; )
T val;
if (!entry.TryGetValue(startTime, out val))
{
if (entry.next == null)
{
entry.next = new HistoryValue(startTime, id, value);
break;
}

// We sort the entries from smallest to largest time.
if (startTime < entry.startTime)
{
// This entry belongs in front of this entry.
// Insert it before the current entry by moving the current entry after it.
HistoryValue newEntry = new HistoryValue(entry);
entry.startTime = startTime;
entry.value = value;
entry.next = newEntry;
Debug.Assert(entry.startTime <= entry.next.startTime);
break;
}
entry = entry.next;
entry.Add(startTime, value);
count++;
}
firstEntry.skipAhead = entry.next;
}
count++;
}
// TryGetValue will return the value associated with an id that was placed in the stream
// at time100ns OR BEFORE.
public bool TryGetValue(Address id, long time, out T value)
{
HistoryValue entry;
SortedDictionary<long, T> entry;
if (entries.TryGetValue((long)id, out entry))
{
// The entries are sorted smallest to largest.
// We want the last entry that is smaller (or equal) to the target time)

var firstEntry = entry;
// See if we can jump ahead. Currently we only do this of the first entry,
// But you could imagine using some of the other nodes's skipAhead entries.
if (firstEntry.skipAhead != null && firstEntry.skipAhead.startTime < time)
entry = firstEntry.skipAhead;

HistoryValue last = null;
for (; ; )
long? lastStart = null;
var keys = entry.Keys;
foreach (var t in keys)
{
if (time < entry.startTime)
break;
last = entry;
entry = entry.next;
if (entry == null)
if (time < t)
break;
lastStart = t;
}
if (last != null)
if (lastStart != null)
{
value = last.value;
firstEntry.skipAhead = last;
value = entry[lastStart.Value];
return true;
}
}
Expand All @@ -112,16 +80,16 @@ public IEnumerable<HistoryValue> Entries
#if DEBUG
int ctr = 0;
#endif
foreach (HistoryValue entry in entries.Values)
foreach (var entry in entries)
{
HistoryValue list = entry;
while (list != null)
SortedDictionary<long, T> e = entry.Value;
long id = entry.Key;
foreach (var v in e)
{
#if DEBUG
ctr++;
ctr++;
#endif
yield return list;
list = list.next;
yield return new HistoryValue(v.Key, (ulong)id, v.Value);
}
}
#if DEBUG
Expand All @@ -135,16 +103,10 @@ public IEnumerable<HistoryValue> Entries
/// </summary>
public void Remove(Address id)
{
HistoryValue entry;
SortedDictionary<long, T> entry;
if (entries.TryGetValue((long)id, out entry))
{
// Fix up the count by the number of entries we remove.
while (entry != null)
{
entry.skipAhead = null; // Throw away optimization data.
--count;
entry = entry.next;
}
count -= entry.Count;
entries.Remove((long)id);
}
}
Expand All @@ -155,13 +117,6 @@ public class HistoryValue
public long StartTime { get { return startTime; } }
public T Value { get { return value; } }
#region private
internal HistoryValue(HistoryValue entry)
{
this.key = entry.key;
this.startTime = entry.startTime;
this.value = entry.value;
this.next = entry.next;
}
internal HistoryValue(long startTime100ns, Address key, T value)
{
this.key = key;
Expand All @@ -172,15 +127,10 @@ internal HistoryValue(long startTime100ns, Address key, T value)
internal Address key;
internal long startTime;
internal T value;
internal HistoryValue next;
// To improve getting to the end quickly, we allow nodes to store values that 'skip ahead'.
// Today we only use this field for the first node to skip to the end (for fast append)
// The only strong invarient for this field is that it point further up the same list.
internal HistoryValue skipAhead;
#endregion
}
#region private
Dictionary<long, HistoryValue> entries;
Dictionary<long, SortedDictionary<long, T>> entries;
int count;
#endregion
}
Expand Down

0 comments on commit 8a17736

Please sign in to comment.