Packages

Plug for full page response caching

Current section

2 Versions

Jump to

Compare versions

6 files changed
+85 additions
-18 deletions
  @@ -1,5 +1,15 @@
1 1 # Changelog
2 2
3 + ## v0.2.0 (2016-03-27)
4 +
5 + - Enhancements
6 + - Agent caches can auto expire keys after configurable seconds
7 + - ETS caches can auto expire keys after configurable seconds
8 +
9 + - Backwards incompatible changes
10 + - Minimum required elixir version is now "~> 1.2"
11 + - Minimum required erlang version is now "~> 18.0"
12 +
3 13 ## v0.1.0 (2016-03-13)
4 14
5 15 - Initial Release
  @@ -23,7 +23,7 @@ Add the plug as a dependency to your `mix.exs` file:
23 23
24 24 ```elixir
25 25 defp deps do
26 - [ { :plug_pagecache, "~> 0.1" } ]
26 + [ { :plug_pagecache, "~> 0.2" } ]
27 27 end
28 28 ```
29 29
  @@ -48,11 +48,13 @@ use Mix.Config
48 48 config :plug_pagecache,
49 49 :caches,
50 50 my_agent_cache: [
51 - adapter: Plug.PageCache.Adapter.Agent
51 + adapter: Plug.PageCache.Adapter.Agent,
52 + auto_expire: 3600
52 53 ],
53 54 my_ets_cache: [
54 - adapter: Plug.PageCache.Adapter.ETS,
55 - table: :my_ets_table
55 + adapter: Plug.PageCache.Adapter.ETS,
56 + auto_expire: 3600,
57 + table: :my_ets_table
56 58 ]
57 59 ```
58 60
  @@ -113,6 +115,8 @@ Uses a plain `GenServer` to serve responses directly from memory (== state).
113 115
114 116 Requires no additional configuration.
115 117
118 + Optionally takes an `:auto_expire` value as entry lifetime in seconds.
119 +
116 120 ### Plug.PageCache.Adapter.ETS
117 121
118 122 Uses an `ets table` to serve reseponses.
  @@ -120,6 +124,8 @@ Uses an `ets table` to serve reseponses.
120 124 Responses are stored in a `:named_table` you have to configure
121 125 using the `:table` key.
122 126
127 + Optionally takes an `:auto_expire` value as entry lifetime in seconds.
128 +
123 129
124 130 ## License
  @@ -1,7 +1,7 @@
1 1 {<<"app">>,<<"plug_pagecache">>}.
2 2 {<<"build_tools">>,[<<"mix">>]}.
3 3 {<<"description">>,<<"Plug for full page response caching">>}.
4 - {<<"elixir">>,<<"~> 1.0">>}.
4 + {<<"elixir">>,<<"~> 1.2">>}.
5 5 {<<"files">>,
6 6 [<<"CHANGELOG.md">>,<<"mix.exs">>,<<"README.md">>,
7 7 <<"lib/plug/pagecache.ex">>,<<"lib/plug/pagecache/adapter.ex">>,
  @@ -22,4 +22,4 @@
22 22 [{<<"app">>,<<"plug">>},
23 23 {<<"optional">>,true},
24 24 {<<"requirement">>,<<"~> 1.0">>}]}]}.
25 - {<<"version">>,<<"0.1.0">>}.
25 + {<<"version">>,<<"0.2.0">>}.
  @@ -5,10 +5,49 @@ defmodule Plug.PageCache.Adapter.Agent do
5 5
6 6 use Plug.PageCache.Adapter
7 7
8 - def init(_opts), do: { :ok, %{} }
9 8
10 - def clean(_state), do: { %{}, :ok }
11 - def load(state, path), do: { state, Map.get(state, path, nil) }
12 - def remove(state, path), do: { Map.delete(state, path), :ok }
13 - def save(state, path, page), do: { Map.put(state, path, page), :ok }
9 + # Adapter lifecycle
10 +
11 + def init(opts) do
12 + { :ok, %{ auto_expire: opts[:auto_expire] || 0,
13 + entries: %{} }}
14 + end
15 +
16 +
17 + # Adapter methods
18 +
19 + def clean(state) do
20 + { %{ state | entries: %{} }, :ok }
21 + end
22 +
23 + def load(state, path) do
24 + { state, load_unexpired(path, state) }
25 + end
26 +
27 + def remove(state, path) do
28 + { %{ state | entries: Map.delete(state.entries, path) }, :ok }
29 + end
30 +
31 + def save(state, path, page) do
32 + entry = { page, :os.system_time(:seconds) + state.auto_expire }
33 +
34 + { %{ state | entries: Map.put(state.entries, path, entry) }, :ok }
35 + end
36 +
37 +
38 + # Internal methods
39 +
40 + defp load_unexpired(path, %{ auto_expire: 0 } = state) do
41 + { page, _ } = Map.get(state.entries, path, { nil, 0 })
42 + page
43 + end
44 +
45 + defp load_unexpired(path, state) do
46 + { page, expire_after } = Map.get(state.entries, path, { nil, 0 })
47 +
48 + case :os.system_time(:seconds) <= expire_after do
49 + true -> page
50 + false -> nil
51 + end
52 + end
14 53 end
  @@ -7,6 +7,9 @@ defmodule Plug.PageCache.Adapter.ETS do
7 7
8 8 require Logger
9 9
10 +
11 + # Adapter lifecycle
12 +
10 13 def init(opts) do
11 14 ets_tid = case opts[:table] do
12 15 nil ->
  @@ -17,10 +20,13 @@ defmodule Plug.PageCache.Adapter.ETS do
17 20 table -> :ets.new(table, [ :protected, :named_table, :set ])
18 21 end
19 22
20 - { :ok, %{ ets_tid: ets_tid }}
23 + { :ok, %{ auto_expire: opts[:auto_expire] || 0,
24 + ets_tid: ets_tid }}
21 25 end
22 26
23 27
28 + # Adapter methods
29 +
24 30 def clean(state) do
25 31 _ = :ets.delete_all_objects(state.ets_tid)
26 32
  @@ -29,8 +35,13 @@ defmodule Plug.PageCache.Adapter.ETS do
29 35
30 36 def load(state, path) do
31 37 case :ets.lookup(state.ets_tid, path) do
32 - [{ ^path, page }] -> { state, page }
33 - _ -> { state, nil }
38 + [{ ^path, page, expire_after }] ->
39 + case :os.system_time(:seconds) <= expire_after do
40 + true -> { state, page }
41 + false -> { state, nil }
42 + end
43 +
44 + _ -> { state, nil }
34 45 end
35 46 end
36 47
  @@ -41,7 +52,8 @@ defmodule Plug.PageCache.Adapter.ETS do
41 52 end
42 53
43 54 def save(state, path, page) do
44 - _ = :ets.insert(state.ets_tid, { path, page })
55 + expire_after = :os.system_time(:seconds) + state.auto_expire
56 + _ = :ets.insert(state.ets_tid, { path, page, expire_after })
45 57
46 58 { state, :ok }
47 59 end
Loading more files…