Skip to content

Commit

Permalink
Change node filters to use a concurrent list instead of a dictionary (#…
Browse files Browse the repository at this point in the history
…698)

* Change node filters to use a list instead of a dictionary so insert order can be maintained.

* Fix code review issue

* Add optimization for enumerator creation.

* Better locking around getting the enumerator

* Fix GetEnumerator
  • Loading branch information
mikedennis authored and NicolasDorier committed Jun 4, 2019
1 parent 54aa8fd commit a8854dc
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 1 deletion.
2 changes: 1 addition & 1 deletion NBitcoin/Protocol/Filters/NodeFiltersCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace NBitcoin.Protocol.Filters
{
public class NodeFiltersCollection : ThreadSafeCollection<INodeFilter>
public class NodeFiltersCollection : ThreadSafeList<INodeFilter>
{
public IDisposable Add(Action<IncomingMessage, Action> onReceiving, Action<Node, Payload, Action> onSending = null)
{
Expand Down
123 changes: 123 additions & 0 deletions NBitcoin/Utils/ThreadSafeList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NBitcoin
{
public class ThreadSafeList<T> : IEnumerable<T>
{
private List<T> _Behaviors;
private object _lock = new object();

private List<T> _EnumeratorList = null;

public ThreadSafeList()
{
lock (_lock)
_Behaviors = new List<T>();
}

/// <summary>
/// Add an item to the collection
/// </summary>
/// <param name="item"></param>
/// <returns>When disposed, the item is removed</returns>
public IDisposable Add(T item)
{
if (item == null)
throw new ArgumentNullException(nameof(item));
OnAdding(item);
lock (_lock)
{
_Behaviors.Add(item);
_EnumeratorList = null;
}
return new ActionDisposable(() =>
{
}, () => Remove(item));
}

protected virtual void OnAdding(T obj)
{
}
protected virtual void OnRemoved(T obj)
{
}

public bool Remove(T item)
{
bool removed = false;
lock (_lock)
{
removed = _Behaviors.Remove(item);
_EnumeratorList = null;
}

if (removed)
OnRemoved(item);
return removed;
}

public void Clear()
{
foreach (var behavior in this)
Remove(behavior);
}

public T FindOrCreate<U>() where U : T, new()
{
return FindOrCreate<U>(() => new U());
}
public U FindOrCreate<U>(Func<U> create) where U : T
{
var result = this.OfType<U>().FirstOrDefault();
if (result == null)
{
result = create();
Add(result);
}
return result;
}
public U Find<U>() where U : T
{
return this.OfType<U>().FirstOrDefault();
}

public void Remove<U>() where U : T
{
foreach (var b in this.OfType<U>())
{
Remove(b);
}
}

#region IEnumerable<T> Members

public IEnumerator<T> GetEnumerator()
{
IEnumerator<T> enumerator = _EnumeratorList?.GetEnumerator();
if (enumerator == null)
{
lock (_lock)
{
var behaviorsList = _Behaviors.ToList();
_EnumeratorList = behaviorsList;
enumerator = behaviorsList.GetEnumerator();
}
}
return enumerator;
}

#endregion

#region IEnumerable Members

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

#endregion
}
}

0 comments on commit a8854dc

Please sign in to comment.