feat: add mergePool and score to eviction
This commit is contained in:
1 parent
d3fe77badb
commit
bcd5503f80
1 file changed
+102
@@ -155,3 +155,105 @@ defmodule Excache.Eviction do
|
|||||||
{sampled, randState} = config.sampler.(remaining, config.sampleSize, config.randState)
|
{sampled, randState} = config.sampler.(remaining, config.sampleSize, config.randState)
|
||||||
config = %{config | randState: randState}
|
config = %{config | randState: randState}
|
||||||
|
|
||||||
|
if random?(config.policy) do
|
||||||
|
{hd(sampled), pool, config}
|
||||||
|
else
|
||||||
|
metadata = config.metaFun.(Enum.map(sampled, & &1.key), config.now)
|
||||||
|
|
||||||
|
scored =
|
||||||
|
Enum.map(sampled, fn candidate ->
|
||||||
|
{score(config.policy, candidate, Map.get(metadata, candidate.key), config.now),
|
||||||
|
candidate}
|
||||||
|
end)
|
||||||
|
|
||||||
|
[{_score, victim} | rest] = mergePool(pool, scored, config.poolSize)
|
||||||
|
{victim, rest, config}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp mergePool(pool, scored, poolSize) do
|
||||||
|
(scored ++ pool)
|
||||||
|
|> Enum.uniq_by(fn {_score, candidate} -> candidate.key end)
|
||||||
|
|> Enum.sort_by(fn {candidateScore, _candidate} -> candidateScore end, :desc)
|
||||||
|
|> Enum.take(poolSize)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp score(policy, _candidate, meta, now) when policy in @lruPolicies, do: lruScore(meta, now)
|
||||||
|
|
||||||
|
defp score(policy, _candidate, meta, _now) when policy in @lfuPolicies,
|
||||||
|
do: @lfuMaxCounter - counterOf(meta)
|
||||||
|
|
||||||
|
defp score(:volatileTtl, candidate, _meta, _now), do: -candidate.expiresAt
|
||||||
|
|
||||||
|
defp lruScore(nil, _now), do: {1, 0}
|
||||||
|
defp lruScore(meta, now), do: {0, max(now - meta.lastAccess, 0)}
|
||||||
|
|
||||||
|
defp counterOf(nil), do: 0
|
||||||
|
defp counterOf(meta), do: meta.counter
|
||||||
|
|
||||||
|
defp eligible?(_candidate, :noeviction), do: false
|
||||||
|
|
||||||
|
defp eligible?(candidate, policy) do
|
||||||
|
if volatile?(policy), do: candidate.expiresAt != nil, else: true
|
||||||
|
end
|
||||||
|
|
||||||
|
defp emptyReason(policy) do
|
||||||
|
if volatile?(policy), do: :noVolatileKeys, else: :noCandidates
|
||||||
|
end
|
||||||
|
|
||||||
|
defp configure(opts) do
|
||||||
|
%{
|
||||||
|
policy: Keyword.fetch!(opts, :policy),
|
||||||
|
maxmemory: Keyword.get(opts, :maxmemory, 0),
|
||||||
|
now: Keyword.get_lazy(opts, :now, fn -> System.system_time(:millisecond) end),
|
||||||
|
sampleSize: Keyword.get(opts, :sampleSize, @defaultSampleSize),
|
||||||
|
poolSize: Keyword.get(opts, :poolSize, @defaultPoolSize),
|
||||||
|
sampler: Keyword.get(opts, :sampler, &sampleRandom/3),
|
||||||
|
randState: :rand.seed_s(:exsss, Keyword.get(opts, :seed, @defaultSeed)),
|
||||||
|
tracker: Keyword.get(opts, :tracker),
|
||||||
|
metaFun: metaFun(opts)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp metaFun(opts) do
|
||||||
|
cond do
|
||||||
|
Keyword.has_key?(opts, :metadata) ->
|
||||||
|
metadata = Keyword.fetch!(opts, :metadata)
|
||||||
|
fn keys, _now -> Map.take(metadata, keys) end
|
||||||
|
|
||||||
|
Keyword.has_key?(opts, :tracker) ->
|
||||||
|
tracker = Keyword.fetch!(opts, :tracker)
|
||||||
|
fn keys, now -> Tracker.metadata(tracker, keys, now) end
|
||||||
|
|
||||||
|
true ->
|
||||||
|
fn _keys, _now -> %{} end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sampleRandom(pool, count, randState) when length(pool) <= count, do: {pool, randState}
|
||||||
|
|
||||||
|
defp sampleRandom(pool, count, randState) do
|
||||||
|
{taken, _rest, _size, nextState} =
|
||||||
|
Enum.reduce(1..count, {[], pool, length(pool), randState}, fn _index,
|
||||||
|
{acc, left, size, state} ->
|
||||||
|
{index, drawn} = :rand.uniform_s(size, state)
|
||||||
|
{picked, rest} = List.pop_at(left, index - 1)
|
||||||
|
{[picked | acc], rest, size - 1, drawn}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{Enum.reverse(taken), nextState}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp report(config, acc, reason) do
|
||||||
|
%{
|
||||||
|
reason: reason,
|
||||||
|
policy: config.policy,
|
||||||
|
maxmemory: config.maxmemory,
|
||||||
|
usedMemory: acc.used,
|
||||||
|
freedBytes: acc.freed,
|
||||||
|
evicted: Enum.reverse(acc.evicted),
|
||||||
|
evictedCount: length(acc.evicted),
|
||||||
|
passes: acc.passes
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in new issue
Block a user