diff --git a/lib/hammer/atomic.ex b/lib/hammer/atomic.ex index 0c67385..780b41c 100644 --- a/lib/hammer/atomic.ex +++ b/lib/hammer/atomic.ex @@ -186,8 +186,14 @@ defmodule Hammer.Atomic do end defp clean(config) do - table = config.table + case config.algorithm_module do + Hammer.Atomic.FixWindow -> clean_fix_window(config) + _ -> clean_bucket(config) + end + end + # FixWindow stores expires_at in milliseconds in slot 2 + defp clean_fix_window(config) do now = now() :ets.foldl( @@ -195,14 +201,35 @@ defmodule Hammer.Atomic do expires_at = :atomics.get(atomic, 2) if now - expires_at > config.key_older_than do - :ets.delete_object(table, term) + :ets.delete_object(config.table, term) + deleted + 1 + else + deleted + end + end, + 0, + config.table + ) + end + + # TokenBucket and LeakyBucket store last_update in seconds in slot 2 + defp clean_bucket(config) do + now = System.system_time(:second) + older_than = now - div(config.key_older_than, 1000) + + :ets.foldl( + fn {_key, atomic} = term, deleted -> + last_update = :atomics.get(atomic, 2) + + if last_update < older_than do + :ets.delete_object(config.table, term) deleted + 1 else deleted end end, 0, - table + config.table ) end diff --git a/lib/hammer/ets/leaky_bucket.ex b/lib/hammer/ets/leaky_bucket.ex index 224533c..c8b0122 100644 --- a/lib/hammer/ets/leaky_bucket.ex +++ b/lib/hammer/ets/leaky_bucket.ex @@ -165,8 +165,8 @@ defmodule Hammer.ETS.LeakyBucket do """ @spec clean(config :: ETS.config()) :: non_neg_integer() def clean(config) do - now = ETS.now() - older_than = now - config.key_older_than + now = System.system_time(:second) + older_than = now - div(config.key_older_than, 1000) match_spec = [{{:_, :_, :"$1"}, [], [{:<, :"$1", {:const, older_than}}]}] :ets.select_delete(config.table, match_spec) diff --git a/lib/hammer/ets/token_bucket.ex b/lib/hammer/ets/token_bucket.ex index b2d1fa8..e06a5ee 100644 --- a/lib/hammer/ets/token_bucket.ex +++ b/lib/hammer/ets/token_bucket.ex @@ -165,8 +165,8 @@ defmodule Hammer.ETS.TokenBucket do """ @spec clean(config :: ETS.config()) :: non_neg_integer() def clean(config) do - now = ETS.now() - older_than = now - config.key_older_than + now = System.system_time(:second) + older_than = now - div(config.key_older_than, 1000) match_spec = [{{:_, :_, :"$1"}, [], [{:<, :"$1", {:const, older_than}}]}] :ets.select_delete(config.table, match_spec) diff --git a/test/hammer/atomic/clean_test.exs b/test/hammer/atomic/clean_test.exs index 62c5f70..0ac3aef 100644 --- a/test/hammer/atomic/clean_test.exs +++ b/test/hammer/atomic/clean_test.exs @@ -51,7 +51,7 @@ defmodule Hammer.Atomic.CleanTest do end test "cleaning works for token bucket" do - start_supervised!({RateAtomicLimitTokenBucket, clean_period: 50, key_older_than: 10}) + start_supervised!({RateAtomicLimitTokenBucket, clean_period: 100, key_older_than: 1000}) key = "key" refill_rate = 1 @@ -68,7 +68,7 @@ defmodule Hammer.Atomic.CleanTest do end test "cleaning works for leaky bucket" do - start_supervised!({RateAtomicLimitLeakyBucket, clean_period: 50, key_older_than: 10}) + start_supervised!({RateAtomicLimitLeakyBucket, clean_period: 100, key_older_than: 1000}) key = "key" leak_rate = 1 diff --git a/test/hammer/ets/clean_test.exs b/test/hammer/ets/clean_test.exs index 0ff462f..e945ff9 100644 --- a/test/hammer/ets/clean_test.exs +++ b/test/hammer/ets/clean_test.exs @@ -72,7 +72,7 @@ defmodule Hammer.ETS.CleanTest do end test "cleaning works for token bucket" do - start_supervised!({RateLimitTokenBucket, clean_period: 100}) + start_supervised!({RateLimitTokenBucket, clean_period: 100, key_older_than: 1000}) key = "key" refill_rate = 1 @@ -89,7 +89,7 @@ defmodule Hammer.ETS.CleanTest do end test "cleaning works for leaky bucket" do - start_supervised!({RateLimitLeakyBucket, clean_period: 100}) + start_supervised!({RateLimitLeakyBucket, clean_period: 100, key_older_than: 1000}) key = "key" leak_rate = 1