Skip to content

Commit 31835c7

Browse files
committed
pools connections to the graph
1 parent 226e78d commit 31835c7

File tree

13 files changed

+193
-137
lines changed

13 files changed

+193
-137
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Enhancements
66
- Allows retrieving the shape of a query
7+
- Pools connections to the graph
78
- Uses `:hackney` instead of `:inets`
89

910
- Backwards incompatible changes

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ They only need to be linked to an entry in your `config.exs`:
4545
```elixir
4646
config :my_app, MyApp.MyGraph,
4747
host: "localhost",
48+
pool: [ max_overflow: 0, size: 1 ],
4849
port: 64210
4950
```
5051

config/test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ use Mix.Config
22

33
config :caylir_test, Caylir.TestHelpers.Graph,
44
host: "localhost",
5+
pool: [ max_overflow: 0, size: 1 ],
56
port: 64210

lib/caylir/graph.ex

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,33 @@ defmodule Caylir.Graph do
1515
1616
config :my_application, MyGraph,
1717
host: "localhost",
18+
pool: [ max_overflow: 10, size: 5 ],
1819
port: 64210
1920
"""
2021

2122
use Behaviour
2223

2324
defmacro __using__(otp_app: otp_app) do
2425
quote do
25-
alias Caylir.Graph.Connection
26+
alias Caylir.Graph.Config
27+
alias Caylir.Graph.Pool
2628

2729
@behaviour unquote(__MODULE__)
2830
@otp_app unquote(otp_app)
2931

30-
def child_spec, do: Connection.child_spec(__MODULE__)
31-
def config, do: Connection.Config.config(@otp_app, __MODULE__)
32+
def __pool__, do: __MODULE__.Pool
3233

33-
def delete(quad), do: Connection.delete(__MODULE__, quad)
34-
def query(query), do: Connection.query(__MODULE__, query)
35-
def shape(query), do: Connection.shape(__MODULE__, query)
36-
def write(quad), do: Connection.write(__MODULE__, quad)
34+
def child_spec, do: Pool.Spec.spec(__MODULE__)
35+
def config, do: Config.config(@otp_app, __MODULE__)
36+
37+
def delete(quad), do: send { :delete, quad }
38+
def query(query), do: send { :query, query }
39+
def shape(query), do: send { :shape, query }
40+
def write(quad), do: send { :write, quad }
41+
42+
defp send(request) do
43+
:poolboy.transaction(__pool__, &GenServer.call(&1, request))
44+
end
3745
end
3846
end
3947

@@ -42,17 +50,17 @@ defmodule Caylir.Graph do
4250
@type t_write :: :ok | { :error, String.t }
4351

4452
@doc """
45-
Returns the child specification to start and supervise the graph connection.
53+
Returns the (internal) pool module.
4654
"""
47-
defcallback child_spec :: Supervisor.Spec.spec
55+
defcallback __pool__ :: module
4856

4957
@doc """
50-
Should return the configuration options used to communicate with the graph.
51-
52-
Needed parameters:
58+
Returns a supervisable pool child_spec.
59+
"""
60+
defcallback child_spec :: Supervisor.Spec.spec
5361

54-
- host
55-
- port
62+
@doc """
63+
Returns the connection configuration.
5664
"""
5765
defcallback config :: Keyword.t
5866

lib/caylir/graph/connection/config.ex renamed to lib/caylir/graph/config.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
defmodule Caylir.Graph.Connection.Config do
1+
defmodule Caylir.Graph.Config do
22
@moduledoc """
33
Configuration helper module.
44
"""

lib/caylir/graph/connection.ex

Lines changed: 0 additions & 47 deletions
This file was deleted.

lib/caylir/graph/pool/spec.ex

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
defmodule Caylir.Graph.Pool.Spec do
2+
@moduledoc """
3+
Connection pool specification helper.
4+
"""
5+
6+
alias Caylir.Graph.Pool
7+
8+
@doc """
9+
Returns a supervisable pool child_spec.
10+
"""
11+
@spec spec(conn :: module) :: Supervisor.Spec.spec
12+
def spec(conn) do
13+
{ pool_opts, worker_opts } = get_opts(conn)
14+
15+
:poolboy.child_spec(conn, pool_opts, worker_opts)
16+
end
17+
18+
defp get_opts(conn) do
19+
{ pool_opts,
20+
worker_opts } = Keyword.split(conn.config, [ :size, :max_overflow ])
21+
22+
pool_opts =
23+
pool_opts
24+
|> Keyword.put_new(:max_overflow, 10)
25+
|> Keyword.put_new(:size, 5)
26+
27+
pool_opts =
28+
pool_opts
29+
|> Keyword.put(:name, { :local, conn.__pool__ })
30+
|> Keyword.put(:worker_module, Pool.Worker)
31+
32+
worker_opts = worker_opts |> Keyword.put(:module, conn)
33+
34+
{ pool_opts, worker_opts }
35+
end
36+
end

lib/caylir/graph/pool/worker.ex

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
defmodule Caylir.Graph.Pool.Worker do
2+
@moduledoc """
3+
Pool worker.
4+
"""
5+
6+
alias Caylir.Graph.Request
7+
8+
@behaviour :poolboy_worker
9+
10+
@doc """
11+
Starts the worker process.
12+
"""
13+
@spec start_link(conn :: Keyword.t) :: GenServer.on_start
14+
def start_link(conn) do
15+
GenServer.start_link(__MODULE__, conn)
16+
end
17+
18+
@doc """
19+
Initializes the worker.
20+
"""
21+
@spec init(conn :: Keyword.t) :: { :ok, Keyword.t }
22+
def init(conn), do: { :ok, conn }
23+
24+
25+
# GenServer callbacks
26+
27+
@doc false
28+
def handle_call({ :delete, quad }, _from, conn) do
29+
{ :reply, Request.delete(quad, conn), conn }
30+
end
31+
32+
@doc false
33+
def handle_call({ :query, query }, _from, conn) do
34+
{ :reply, Request.query(query, conn), conn }
35+
end
36+
37+
@doc false
38+
def handle_call({ :shape, query }, _from, conn) do
39+
{ :reply, Request.shape(query, conn), conn }
40+
end
41+
42+
@doc false
43+
def handle_call({ :write, quad }, _from, conn) do
44+
{ :reply, Request.write(quad, conn), conn }
45+
end
46+
end

lib/caylir/graph/request.ex

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,67 @@ defmodule Caylir.Graph.Request do
33
Sends requests to the server.
44
"""
55

6+
alias Caylir.Graph
7+
8+
@doc """
9+
Deletes a quad from the graph.
10+
"""
11+
@spec delete(Keyword.t, Keyword.t) :: Graph.t_delete
12+
def delete(quad, conn) do
13+
url = Graph.URL.delete(conn)
14+
body = [ quad ] |> Poison.encode!
15+
16+
case send(:post, url, body) do
17+
{ :ok, 200, _success } -> :ok
18+
{ :ok, 400, %{ error: reason }} -> { :error, reason }
19+
end
20+
end
21+
22+
@doc """
23+
Queries the graph.
24+
"""
25+
@spec query(String.t, Keyword.t) :: Graph.t_query
26+
def query(query, conn) do
27+
url = Graph.URL.query(conn)
28+
29+
case send(:post, url, query) do
30+
{ :ok, 200, %{ result: result }} -> result
31+
{ :ok, 400, %{ error: reason }} -> { :error, reason }
32+
end
33+
end
34+
35+
636
@doc """
7-
Send a request to the server.
37+
Gets the shape of a query.
838
"""
9-
@spec send({ atom, String.t, String.t }) :: any
10-
def send({ method, url, payload }) do
39+
@spec shape(String.t, Keyword.t) :: Graph.t_query
40+
def shape(query, conn) do
41+
url = Graph.URL.shape(conn)
42+
43+
case send(:post, url, query) do
44+
{ :ok, 200, shape } -> shape
45+
{ :ok, 400, %{ error: reason }} -> { :error, reason }
46+
end
47+
end
48+
49+
@doc """
50+
Writes a quad to the graph.
51+
"""
52+
@spec write(Keyword.t, Keyword.t) :: Graph.t_write
53+
def write(quad, conn) do
54+
url = Graph.URL.write(conn)
55+
body = [ quad ] |> Poison.encode!
56+
57+
case send(:post, url, body) do
58+
{ :ok, 200, _success } -> :ok
59+
{ :ok, 400, %{ error: reason }} -> { :error, reason }
60+
end
61+
end
62+
63+
64+
# Utility methods
65+
66+
defp send(method, url, payload) do
1167
body = payload |> :binary.bin_to_list()
1268
headers = [{ 'Content-Type', 'application/x-www-form-urlencoded' },
1369
{ 'Content-Length', length(body) }]
@@ -18,7 +74,6 @@ defmodule Caylir.Graph.Request do
1874
parse_response(status, response)
1975
end
2076

21-
2277
defp parse_response(status, ''), do: { :ok, status }
2378
defp parse_response(status, body) do
2479
{ :ok, status, Poison.decode!(body, keys: :atoms) }

lib/caylir/graph/worker.ex

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)