Skip to content

Commit

Permalink
Revert "Replace manually sorted list with SortedDictionary"
Browse files Browse the repository at this point in the history
This reverts commit 8a17736.
  • Loading branch information
ilabutin committed Jul 11, 2017
1 parent f661ba7 commit da91db8
Showing 1 changed file with 86 additions and 31 deletions.
117 changes: 86 additions & 31 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, SortedDictionary<long, T>>(initialSize);
entries = new Dictionary<long, HistoryValue>(initialSize);
}
/// <summary>
/// Adds the association that 'id' has the value 'value' from 'startTime100ns' ONWARD until
Expand All @@ -25,52 +25,89 @@ public HistoryDictionary(int initialSize)
/// </summary>
public void Add(Address id, long startTime, T value, bool isEndRundown = false)
{
SortedDictionary<long, T> entry;
HistoryValue 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;
var newEntry = new SortedDictionary<long, T>();
newEntry.Add(startTime, value);
entries.Add((long)id, newEntry);
count++;
entries.Add((long)id, new HistoryValue(startTime, id, value));
}
else
{
Debug.Assert(entry != null);
T val;
if (!entry.TryGetValue(startTime, out val))
{
entry.Add(startTime, value);
count++;
}
else
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 (; ; )
{
entry[startTime] = value;
// We found exact match
if (startTime == entry.StartTime)
{
// Just update the value and exit immediately as there is no need to
// update skipAhead or increment count
entry.value = value;
return;
}

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;
}
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)
{
SortedDictionary<long, T> entry;
HistoryValue 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)
long? lastStart = null;
var keys = entry.Keys;
foreach (var t in keys)

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 (; ; )
{
if (time < t)
if (time < entry.startTime)
break;
last = entry;
entry = entry.next;
if (entry == null)
break;
lastStart = t;
}
if (lastStart != null)
if (last != null)
{
value = entry[lastStart.Value];
value = last.value;
firstEntry.skipAhead = last;
return true;
}
}
Expand All @@ -84,16 +121,16 @@ public IEnumerable<HistoryValue> Entries
#if DEBUG
int ctr = 0;
#endif
foreach (var entry in entries)
foreach (HistoryValue entry in entries.Values)
{
SortedDictionary<long, T> e = entry.Value;
long id = entry.Key;
foreach (var v in e)
HistoryValue list = entry;
while (list != null)
{
#if DEBUG
ctr++;
ctr++;
#endif
yield return new HistoryValue(v.Key, (ulong)id, v.Value);
yield return list;
list = list.next;
}
}
#if DEBUG
Expand All @@ -107,10 +144,16 @@ public IEnumerable<HistoryValue> Entries
/// </summary>
public void Remove(Address id)
{
SortedDictionary<long, T> entry;
HistoryValue entry;
if (entries.TryGetValue((long)id, out entry))
{
count -= entry.Count;
// 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;
}
entries.Remove((long)id);
}
}
Expand All @@ -121,6 +164,13 @@ 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 @@ -131,10 +181,15 @@ 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, SortedDictionary<long, T>> entries;
Dictionary<long, HistoryValue> entries;
int count;
#endregion
}
Expand Down

0 comments on commit da91db8

Please sign in to comment.