HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Buffering of fast changing datapoints or events

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fasteventsdatapointsbufferingchanging

Problem

The following class implements a buffer which captures fast changing datapoints or frequently raised events and dispatches them in batches. It will asynchronously call a processing function for the buffered items under any of the following conditions:

  • A configurable timeout has expired since the last time an item was added



  • A configurable maximum number of items was added



  • The buffer is being disposed



There are several buffering strategies available which control how the items are accumulated.
It was written in times of .NET 3.5 and still needs to work with it.

Looking for general improvements, potential pitfalls I missed, design improvements etc.

A couple if things which annoy me but I never got around changing:

  • Violation of open/closed principle in regards of the accumulation strategies. Hasn't been an issue so far but should be fixed at some point I guess.



  • Using a dedicated processing thread. Putting the main method on the thread pool is not really an option because it's long running. Doing it on a timer callback would be nice but it's a bit tricky with the different signals which can trigger a dispatch of the buffered items.



Code:

```
public class AccumulationBuffer : IDisposable
{
public enum RecordingStrategy
{
AllFifo,
AllLifo,
FirstWins,
LastWins
}

private interface IStorage : IEnumerable>
{
void Add(KeyValuePair pair);
void Clear();
}

private class StorageAllFifo : Queue>, IStorage
{
public StorageAllFifo(int capacity)
: base(capacity)
{
}

public void Add(KeyValuePair pair)
{
Enqueue(pair);
}
}

private class StorageAllLifo : Stack>, IStorage
{
public StorageAllLifo(int capacity)
: base(capacity)
{
}

public void Add(KeyValuePair pair)
{
Push(pair);
}
}

private class StorageMap : Dictionary, ISt

Solution

Also, there isn't much to say (you have already mentioned the flaws) some nitpickings

-
You should be consistent in your coding style

if (_CurrentAccumulationCount >= _MaximumAccumulationCount)
    break;

if (_LastAddedTime != DateTime.MinValue)
{
    wait = _InactivityTime;
}


Sometimes you are using braces {} for single if statements (which i preffer) and sometimes not.

-
I would extract the retrieving of the "timeout TimeSpan" into a separate method,

private TimeSpan GetWaitingTime()
{
     lock (_StorageLock)
     {
         if(_CurrentAccumulationCount >= _MaximumAccumulationCount)
         {
             return TimeSpan.Zero;
         }
         if (_LastAddedTime != DateTime.MinValue)
         {
             return _InactivityTime;
         }
     }
     return TimeSpan.FromMilliseconds(-1);
}


and refactor the while (!timeout && !_Quit) loop to

bool hasTimedOut = false;
while (!hasTimedOut && !_Quit)
{
    TimeSpan waitingTime = GetWaitingTime();
    if(waitingTime == TimeSpan.Zero)
    {
        break;
    }

    hasTimedOut = !_MonitorEvent.WaitOne(waitingTime); // WaitOne returns false if it timed out
}


-
The constructor of StorageAllFifo and StorageAllLifo can be removed, as the base constructor is called anyway.

Code Snippets

if (_CurrentAccumulationCount >= _MaximumAccumulationCount)
    break;

if (_LastAddedTime != DateTime.MinValue)
{
    wait = _InactivityTime;
}
private TimeSpan GetWaitingTime()
{
     lock (_StorageLock)
     {
         if(_CurrentAccumulationCount >= _MaximumAccumulationCount)
         {
             return TimeSpan.Zero;
         }
         if (_LastAddedTime != DateTime.MinValue)
         {
             return _InactivityTime;
         }
     }
     return TimeSpan.FromMilliseconds(-1);
}
bool hasTimedOut = false;
while (!hasTimedOut && !_Quit)
{
    TimeSpan waitingTime = GetWaitingTime();
    if(waitingTime == TimeSpan.Zero)
    {
        break;
    }

    hasTimedOut = !_MonitorEvent.WaitOne(waitingTime); // WaitOne returns false if it timed out
}

Context

StackExchange Code Review Q#66918, answer score: 4

Revisions (0)

No revisions yet.