Skip to content

Commit

Permalink
update time on read
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Peck committed Jun 8, 2024
1 parent 747e198 commit 3b30b74
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 26 deletions.
8 changes: 4 additions & 4 deletions BitFaster.Caching/Lfu/ConcurrentLfuCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ private bool TryGetImpl(K key, [MaybeNullWhen(false)] out V value)
{
TryScheduleDrain();
}
this.policy.OnRead(node);
value = node.Value;
return true;
}
Expand Down Expand Up @@ -366,6 +367,7 @@ public bool TryUpdate(K key, V value)
// and we will just lose ordering/hit count, but not orphan the node.
this.writeBuffer.TryAdd(node);
TryScheduleDrain();
this.policy.OnWrite(node);
return true;
}

Expand Down Expand Up @@ -525,8 +527,6 @@ private bool Maintenance(N? droppedWrite = null)
{
this.drainStatus.VolatileWrite(DrainStatus.ProcessingToIdle);

policy.AdvanceTime();

// Note: this is only Span on .NET Core 3.1+, else this is no-op and it is still an array
var buffer = this.drainBuffer.AsSpanOrArray();

Expand Down Expand Up @@ -601,7 +601,7 @@ private void OnAccess(N node)
break;
}

policy.OnRead(node);
policy.AfterRead(node);
}

private void OnWrite(N node)
Expand Down Expand Up @@ -650,7 +650,7 @@ private void OnWrite(N node)
break;
}

policy.OnWrite(node);
policy.AfterWrite(node);
}

private void PromoteProbation(LfuNode<K, V> node)
Expand Down
49 changes: 27 additions & 22 deletions BitFaster.Caching/Lfu/NodePolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ internal interface INodePolicy<K, V, N>
{
N Create(K key, V value);
bool IsExpired(N node);
void AdvanceTime();
void OnRead(N node);
void OnWrite(N node);
void AfterRead(N node);
void AfterWrite(N node);
void OnEvict(N node);
void ExpireEntries<P>(ref ConcurrentLfuCore<K, V, N, P> cache) where P : struct, INodePolicy<K, V, N>;
bool IsReadDrainDelayable();
Expand All @@ -34,17 +35,22 @@ public bool IsExpired(AccessOrderNode<K, V> node)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AdvanceTime()
public void OnRead(AccessOrderNode<K, V> node)
{
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnRead(AccessOrderNode<K, V> node)
public void OnWrite(AccessOrderNode<K, V> node)
{
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnWrite(AccessOrderNode<K, V> node)
public void AfterRead(AccessOrderNode<K, V> node)
{
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AfterWrite(AccessOrderNode<K, V> node)
{
}

Expand Down Expand Up @@ -88,29 +94,33 @@ public TimeOrderNode<K, V> Create(K key, V value)

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsExpired(TimeOrderNode<K, V> node)
{
return node.TimeToExpire < Duration.SinceEpoch();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AdvanceTime()
{
current = Duration.SinceEpoch();
return node.TimeToExpire < current;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnRead(TimeOrderNode<K, V> node)
{
var oldTte = node.TimeToExpire;
// we know IsExpired is always called immediate before OnRead, so piggyback on the current time
node.TimeToExpire = current + expiryCalculator.GetExpireAfterRead(node.Key, node.Value, node.TimeToExpire - current);
if (oldTte.raw != node.TimeToExpire.raw)
{
wheel.Reschedule(node);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnWrite(TimeOrderNode<K, V> node)
{
var current = Duration.SinceEpoch();
node.TimeToExpire = current + expiryCalculator.GetExpireAfterUpdate(node.Key, node.Value, node.TimeToExpire - current);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AfterRead(TimeOrderNode<K, V> node)
{
wheel.Reschedule(node);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AfterWrite(TimeOrderNode<K, V> node)
{
// if the node is not yet scheduled, it is being created
// the time is set on create in case it is read before the buffer is processed
Expand All @@ -120,12 +130,7 @@ public void OnWrite(TimeOrderNode<K, V> node)
}
else
{
var oldTte = node.TimeToExpire;
node.TimeToExpire = current + expiryCalculator.GetExpireAfterUpdate(node.Key, node.Value, node.TimeToExpire - current);
if (oldTte.raw != node.TimeToExpire.raw)
{
wheel.Reschedule(node);
}
wheel.Reschedule(node);
}
}

Expand All @@ -138,7 +143,7 @@ public void OnEvict(TimeOrderNode<K, V> node)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ExpireEntries<P>(ref ConcurrentLfuCore<K, V, TimeOrderNode<K, V>, P> cache) where P : struct, INodePolicy<K, V, TimeOrderNode<K, V>>
{
wheel.Advance(ref cache, current);
wheel.Advance(ref cache, Duration.SinceEpoch());
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down

0 comments on commit 3b30b74

Please sign in to comment.