Class TimeoutDictionary<TKey, TValue>
- Namespace
- VpnHood.Net.Toolkit.Collections
- Assembly
- VpnHood.Net.Toolkit.dll
A concurrent dictionary whose values expire after Timeout of no use and are disposed by the dictionary when evicted, replaced or drained. Ordinary operations take no dictionary-wide application lock (the gated cleanup sweep is the only locked path). Expiry is checked on access and by the sweeps the operations try, with no timer of its own, against a cached clock of about one second's precision. Ownership contract: a value the dictionary adds (or a factory creates) is owned and disposed by the dictionary. One TryAdd returns false for stays the caller's, as it came; one AddOrUpdate rejects because the dictionary is already disposed stays the caller's. A factory may run more than once under contention and must return a fresh instance each time; losing instances are disposed. A returned value may be disposed by a concurrent eviction right after retrieval, so callers must tolerate IsDisposed values and value Dispose must be idempotent. A value's Dispose should not throw: one that does is logged as an error, and the dictionary goes on with the rest.
public sealed class TimeoutDictionary<TKey, TValue> : IDisposable where TKey : notnull where TValue : class, ITimeoutItem
Type Parameters
TKeyThe type of the keys.
TValueThe type of the values.
- Inheritance
-
TimeoutDictionary<TKey, TValue>
- Implements
- Inherited Members
- Extension Methods
Constructors
TimeoutDictionary(TimeSpan?)
A concurrent dictionary whose values expire after Timeout of no use and are disposed by the dictionary when evicted, replaced or drained. Ordinary operations take no dictionary-wide application lock (the gated cleanup sweep is the only locked path). Expiry is checked on access and by the sweeps the operations try, with no timer of its own, against a cached clock of about one second's precision. Ownership contract: a value the dictionary adds (or a factory creates) is owned and disposed by the dictionary. One TryAdd returns false for stays the caller's, as it came; one AddOrUpdate rejects because the dictionary is already disposed stays the caller's. A factory may run more than once under contention and must return a fresh instance each time; losing instances are disposed. A returned value may be disposed by a concurrent eviction right after retrieval, so callers must tolerate IsDisposed values and value Dispose must be idempotent. A value's Dispose should not throw: one that does is logged as an error, and the dictionary goes on with the rest.
public TimeoutDictionary(TimeSpan? timeout = null)
Parameters
timeoutTimeSpan?How long a value may go unused before it expires, or null for no expiry by disuse; a disposed value still counts as expired on access.
Properties
AutoCleanup
Gets a value indicating whether an add or a lookup first tries a sweep of the expired values, which runs at most once per a third of Timeout; removals and disposal do not. The default is true.
public bool AutoCleanup { get; init; }
Property Value
Count
Gets the number of values, expired ones not swept out yet included; with AutoCleanup, it tries a sweep first.
public int Count { get; }
Property Value
Timeout
Gets how long a value may go unused before it expires, or null for no expiry by disuse; a disposed value still counts as expired on access.
public TimeSpan? Timeout { get; init; }
Property Value
Methods
AddOrUpdate(TKey, TValue)
Adds a value, or replaces a key's value and disposes the replaced one.
public TValue AddOrUpdate(TKey key, TValue value)
Parameters
keyTKeyThe key.
valueTValueThe value, which the dictionary owns once added; when the dictionary is already disposed, it throws and the caller keeps the value, and a disposal during the add disposes it.
Returns
- TValue
The value.
Exceptions
- ObjectDisposedException
The dictionary is disposed.
- ArgumentNullException
keyis null.
Cleanup(bool)
Removes and disposes the expired values. It does nothing without a Timeout, or when the dictionary is disposed.
public void Cleanup(bool force = false)
Parameters
forcebooltrue to sweep now; false to skip the sweep when the last one was within a third of Timeout.
Dispose()
Removes and disposes every value; later adds throw or fail. Calling it again does nothing.
public void Dispose()
GetOrAdd(TKey, Func<TKey, TValue>)
Gets a key's live value, refreshing its last-used time, or adds the value a factory creates, in place of an expired one, which is disposed.
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
Parameters
keyTKeyThe key.
valueFactoryFunc<TKey, TValue>Creates the value to add.
Returns
- TValue
The key's value, which the dictionary owns.
Remarks
Under contention the factory may run more than once; it must return a new instance each time, and the instances that lose are disposed.
Exceptions
- ObjectDisposedException
The dictionary is disposed.
- ArgumentNullException
keyis null.
GetOrAdd(TKey, Func<TKey, TValue>, out bool)
Gets a key's live value, refreshing its last-used time, or adds the value a factory creates, in place of an expired one, which is disposed; says which it did.
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory, out bool added)
Parameters
keyTKeyThe key.
valueFactoryFunc<TKey, TValue>Creates the value to add.
addedbooltrue if this call added the value, in place of an expired one too; false if the key had a live value.
Returns
- TValue
The key's value, which the dictionary owns.
Remarks
Under contention the factory may run more than once; it must return a new instance each time, and the instances
that lose are disposed. Code that acts once per new key reads added: a flag set in the
factory is set by a losing instance too, and a factory that captures one makes an object on every call.
Exceptions
- ObjectDisposedException
The dictionary is disposed.
- ArgumentNullException
keyis null.
RemoveAll()
Removes and disposes the values, in one pass; a value added or replaced during the pass may stay.
public void RemoveAll()
TryAdd(TKey, TValue)
Adds a value unless the key has a live one; an expired one is replaced and disposed.
public bool TryAdd(TKey key, TValue value)
Parameters
keyTKeyThe key.
valueTValueThe value, which the dictionary owns when it is added, with its last-used time set then.
Returns
- bool
true if the value was added; false if the key has a live value or the dictionary is disposed, and the caller keeps the value.
Exceptions
- ArgumentNullException
keyis null.
TryGetValue(TKey, out TValue)
Gets a key's live value, refreshing its last-used time. An expired value is removed and disposed.
public bool TryGetValue(TKey key, out TValue value)
Parameters
keyTKeyThe key.
valueTValueThe value, when found; it stays the dictionary's.
Returns
Exceptions
- ArgumentNullException
keyis null.
TryRemove(TKey, out TValue?)
Removes a key's value and disposes it.
public bool TryRemove(TKey key, out TValue? value)
Parameters
keyTKeyThe key.
valueTValueThe removed value, already disposed, when found.
Returns
Exceptions
- ArgumentNullException
keyis null.