Current section

Files

Jump to
localize lib localize locale cache_sweeper.ex
Raw

lib/localize/locale/cache_sweeper.ex

defmodule Localize.Locale.CacheSweeper do
@moduledoc false
use GenServer
@table :localize_locale_cache
@sweep_interval_ms 10_000
# Top 50 languages by native speaker population (lowercase
# canonical form matching the ETS cache key format). These
# entries are never evicted during cache sweeps.
@never_evict MapSet.new([
"zh",
"es",
"en",
"hi",
"ar",
"bn",
"pt",
"ru",
"ja",
"pa",
"de",
"jv",
"ko",
"fr",
"te",
"mr",
"tr",
"ta",
"vi",
"ur",
"it",
"th",
"gu",
"pl",
"uk",
"ml",
"kn",
"or",
"my",
"sw",
"su",
"ro",
"nl",
"ha",
"az",
"si",
"hu",
"zu",
"cs",
"el",
"sv",
"be",
"da",
"fi",
"sk",
"no",
"he",
"id",
"ms",
"fil"
])
def start_link(_options) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
@impl true
def init([]) do
schedule_sweep()
{:ok, []}
end
@impl true
def handle_info(:sweep, state) do
sweep()
schedule_sweep()
{:noreply, state}
end
defp schedule_sweep do
Process.send_after(self(), :sweep, @sweep_interval_ms)
end
defp sweep do
if :ets.whereis(@table) != :undefined do
max_entries = Application.get_env(:localize, :locale_cache_max_entries, 1_000)
size = :ets.info(@table, :size)
if size > max_entries do
evict_random(size - max_entries)
end
end
end
defp evict_random(count) when count <= 0, do: :ok
defp evict_random(count) do
key = :ets.first(@table)
evict_random(key, count)
end
defp evict_random(:"$end_of_table", _remaining), do: :ok
defp evict_random(_key, 0), do: :ok
defp evict_random(key, remaining) do
next_key = :ets.next(@table, key)
if key in @never_evict do
evict_random(next_key, remaining)
else
if :rand.uniform() < 0.5 do
:ets.delete(@table, key)
evict_random(next_key, remaining - 1)
else
evict_random(next_key, remaining)
end
end
end
end