├── .gitignore ├── Makefile ├── README.rdoc ├── doc ├── README.md ├── edoc-info ├── eredis_pool.md ├── eredis_pool_app.md ├── eredis_pool_sup.md ├── erlang.png └── stylesheet.css ├── rebar ├── rebar.config ├── src ├── eredis_pool.app.src ├── eredis_pool.erl ├── eredis_pool_app.erl └── eredis_pool_sup.erl ├── test.config └── test └── eredis_pool_tests.erl /.gitignore: -------------------------------------------------------------------------------- 1 | *.beam 2 | ebin 3 | .eunit 4 | *~ 5 | erl_crash.dump 6 | db 7 | deps 8 | .DS_Store 9 | eunit.coverage.xml -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ERL=erl 2 | BEAMDIR=./deps/*/ebin ./ebin 3 | REBAR=./rebar 4 | 5 | all: clean get-deps update-deps compile xref 6 | 7 | update-deps: 8 | @$(REBAR) update-deps 9 | 10 | get-deps: 11 | @$(REBAR) get-deps 12 | 13 | compile: 14 | @$(REBAR) compile 15 | 16 | xref: 17 | @$(REBAR) xref skip_deps=true 18 | 19 | clean: 20 | @ $(REBAR) clean 21 | 22 | eunit: 23 | @rm -rf .eunit 24 | @mkdir -p .eunit 25 | @ERL_FLAGS="-config test.config" $(REBAR) skip_deps=true eunit 26 | 27 | test: eunit 28 | 29 | edoc: 30 | @$(REBAR) skip_deps=true doc -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = eredis_pool 2 | 3 | eredis_pool is Pool of Redis clients, using eredis and poolboy. 4 | 5 | eredis: 6 | https://github.com/wooga/eredis 7 | 8 | poolboy: 9 | https://github.com/devinus/poolboy 10 | 11 | ==Setup 12 | 13 | $ git clone git://github.com/hiroeorz/eredis_pool.git 14 | $ cd eredis_pool 15 | $ make get-deps 16 | $ make 17 | 18 | ==Testing 19 | $ make test 20 | 21 | ==Settings 22 | edit src/eredis_pool.app.src 23 | 24 | {application, eredis_pool, 25 | [ 26 | {description, ""}, 27 | {vsn, "1"}, 28 | {registered, []}, 29 | {applications, [ 30 | kernel, 31 | stdlib 32 | ]}, 33 | {mod, { eredis_pool_app, []}}, 34 | {env, [ 35 | {global_or_local, local}, 36 | {pools, [ 37 | {default, [ 38 | {size, 10}, 39 | {max_overflow, 20} 40 | ], [] } 41 | ]} 42 | ]} 43 | ]}. 44 | 45 | add new pools. 46 | {env, [ 47 | {global_or_local, local}, 48 | {pools, [ 49 | {default, [ 50 | {size, 10}, 51 | {max_overflow, 20} 52 | ], []}, 53 | {pool1, [ 54 | {size, 30}, 55 | {max_overflow, 20} 56 | ], [ 57 | {host, "127.0.0.1"}, 58 | {port, 6379} 59 | ]}, 60 | {pool2, [ 61 | {size, 20}, 62 | {max_overflow, 20} 63 | ], [ 64 | {host, "127.0.0.1"}, 65 | {port, 6379}, 66 | {database, "user_db"}, 67 | {password, "abc"}, 68 | {reconnect_sleep, 100} 69 | ]} 70 | ]} 71 | ]} 72 | 73 | 74 | ==Examples 75 | 76 | application start. 77 | eredis_pool:start(). 78 | ok 79 | 80 | key-value set and get 81 | eredis_pool:q({global, dbsrv}, ["SET", "foo", "bar"]). 82 | {ok,<<"OK">>} 83 | 84 | eredis_pool:q({global, dbsrv}, ["GET", "foo"]). 85 | {ok,<<"bar">>} 86 | 87 | Redis Pipeline 88 | Pipeline = [["SET", a, "1"], 89 | ["LPUSH", b, "3"], 90 | ["LPUSH", b, "2"]]. 91 | eredis_pool:qp({global,dbsrv}, Pipeline). 92 | 93 | create new pool with default settings. 94 | eredis_pool:create_pool(pool1, 10). 95 | {ok,<0.64.0>} 96 | 97 | and omissible argments(host, port, database, password reconnect_sleep). 98 | eredis_pool:create_pool(pool1, 10, "127.0.0.1", 6379, 1, "abc", 100). 99 | {ok,<0.64.0>} 100 | 101 | using new pool 102 | eredis_pool:q(pool1, ["GET", "foo"]). 103 | {ok,<<"bar">>} 104 | 105 | delete pool 106 | eredis_pool:delete_pool(pool1). 107 | ok 108 | 109 | 110 | 111 | Other commands is here. 112 | http://redis.io/commands 113 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #The eredis_pool application# 4 | 5 | 6 | ##Modules## 7 | 8 | 9 | 10 | 11 | 12 |
eredis_pool
eredis_pool_app
eredis_pool_sup
13 | 14 | -------------------------------------------------------------------------------- /doc/edoc-info: -------------------------------------------------------------------------------- 1 | {application,eredis_pool}. 2 | {packages,[]}. 3 | {modules,[eredis_pool,eredis_pool_app,eredis_pool_sup]}. 4 | -------------------------------------------------------------------------------- /doc/eredis_pool.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #Module eredis_pool# 4 | * [Description](#description) 5 | * [Function Index](#index) 6 | * [Function Details](#functions) 7 | 8 | 9 | . 10 | 11 | Copyright (c) (C) 2011, Hiroe Shin 12 | 13 | __Authors:__ Hiroe Shin ([`shin@mac-hiroe-orz-17.local`](mailto:shin@mac-hiroe-orz-17.local)). 14 | 15 | ##Function Index## 16 | 17 | 18 |
create_pool/2create new pool.
create_pool/3
create_pool/4
create_pool/5
create_pool/6
create_pool/7
delete_pool/1delet pool and disconnected to Redis.
q/2 19 | Executes the given command in the specified connection.
q/3
start/0
stop/0
transaction/2
20 | 21 | 22 | 23 | 24 | ##Function Details## 25 | 26 | 27 | 28 | ###create_pool/2## 29 | 30 | 31 |
create_pool(PoolName::atom(), Size::integer()) -> {ok, pid()} | {error, {already_started, pid()}}
32 |

33 | 34 | 35 | create new pool. 36 | 37 | ###create_pool/3## 38 | 39 | 40 |
create_pool(PoolName::atom(), Size::integer(), Host::string()) -> {ok, pid()} | {error, {already_started, pid()}}
41 |

42 | 43 | 44 | 45 | 46 | ###create_pool/4## 47 | 48 | 49 |
create_pool(PoolName::atom(), Size::integer(), Host::string(), Port::integer()) -> {ok, pid()} | {error, {already_started, pid()}}
50 |

51 | 52 | 53 | 54 | 55 | ###create_pool/5## 56 | 57 | 58 |
create_pool(PoolName::atom(), Size::integer(), Host::string(), Port::integer(), Database::string()) -> {ok, pid()} | {error, {already_started, pid()}}
59 |

60 | 61 | 62 | 63 | 64 | ###create_pool/6## 65 | 66 | 67 |
create_pool(PoolName::atom(), Size::integer(), Host::string(), Port::integer(), Database::string(), Password::string()) -> {ok, pid()} | {error, {already_started, pid()}}
68 |

69 | 70 | 71 | 72 | 73 | ###create_pool/7## 74 | 75 | 76 |
create_pool(PoolName::atom(), Size::integer(), Host::string(), Port::integer(), Database::string(), Password::string(), ReconnectSleep::integer()) -> {ok, pid()} | {error, {already_started, pid()}}
77 |

78 | 79 | 80 | 81 | 82 | ###delete_pool/1## 83 | 84 | 85 |
delete_pool(PoolName::atom()) -> ok | {error, not_found}
86 |

87 | 88 | 89 | delet pool and disconnected to Redis. 90 | 91 | ###q/2## 92 | 93 | 94 |
q(PoolName::atom(), Command::iolist()) -> {ok, binary() | [binary()]} | {error, Reason::binary()}
95 |

96 | 97 | 98 | 99 | Executes the given command in the specified connection. The 100 | command must be a valid Redis command and may contain arbitrary 101 | data which will be converted to binaries. The returned values will 102 | always be binaries. 103 | 104 | ###q/3## 105 | 106 | 107 |
q(PoolName::atom(), Command::iolist(), Timeout::integer()) -> {ok, binary() | [binary()]} | {error, Reason::binary()}
108 |

109 | 110 | 111 | 112 | 113 | ###start/0## 114 | 115 | 116 | `start() -> any()` 117 | 118 | 119 | 120 | ###stop/0## 121 | 122 | 123 | `stop() -> any()` 124 | 125 | 126 | 127 | ###transaction/2## 128 | 129 | 130 | `transaction(PoolName, Fun) -> any()` 131 | 132 | -------------------------------------------------------------------------------- /doc/eredis_pool_app.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #Module eredis_pool_app# 4 | * [Function Index](#index) 5 | * [Function Details](#functions) 6 | 7 | 8 | __Behaviours:__ [`application`](application.md). 9 | 10 | ##Function Index## 11 | 12 | 13 |
start/2
stop/1
14 | 15 | 16 | 17 | 18 | ##Function Details## 19 | 20 | 21 | 22 | ###start/2## 23 | 24 | 25 | `start(StartType, StartArgs) -> any()` 26 | 27 | 28 | 29 | ###stop/1## 30 | 31 | 32 | `stop(State) -> any()` 33 | 34 | -------------------------------------------------------------------------------- /doc/eredis_pool_sup.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #Module eredis_pool_sup# 4 | * [Function Index](#index) 5 | * [Function Details](#functions) 6 | 7 | 8 | __Behaviours:__ [`supervisor`](supervisor.md). 9 | 10 | ##Function Index## 11 | 12 | 13 |
create_pool/3create new pool.
delete_pool/1delet pool and disconnected to Redis.
init/1
start_link/0
start_link/2
14 | 15 | 16 | 17 | 18 | ##Function Details## 19 | 20 | 21 | 22 | ###create_pool/3## 23 | 24 | 25 |
create_pool(PoolName::atom(), Size::integer(), Options::[tuple()]) -> {ok, pid()} | {error, {already_started, pid()}}
26 |

27 | 28 | 29 | create new pool. 30 | 31 | ###delete_pool/1## 32 | 33 | 34 |
delete_pool(PoolName::atom()) -> ok | {error, not_found}
35 |

36 | 37 | 38 | delet pool and disconnected to Redis. 39 | 40 | ###init/1## 41 | 42 | 43 | `init(X1) -> any()` 44 | 45 | 46 | 47 | ###start_link/0## 48 | 49 | 50 | `start_link() -> any()` 51 | 52 | 53 | 54 | ###start_link/2## 55 | 56 | 57 | `start_link(Pools, GlobalOrLocal) -> any()` 58 | 59 | -------------------------------------------------------------------------------- /doc/erlang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiroeorz/eredis_pool/bc37bcf72afd1e5c69635fadba020ee2a73087d1/doc/erlang.png -------------------------------------------------------------------------------- /doc/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* standard EDoc style sheet */ 2 | body { 3 | font-family: Verdana, Arial, Helvetica, sans-serif; 4 | margin-left: .25in; 5 | margin-right: .2in; 6 | margin-top: 0.2in; 7 | margin-bottom: 0.2in; 8 | color: #000000; 9 | background-color: #ffffff; 10 | } 11 | h1,h2 { 12 | margin-left: -0.2in; 13 | } 14 | div.navbar { 15 | background-color: #add8e6; 16 | padding: 0.2em; 17 | } 18 | h2.indextitle { 19 | padding: 0.4em; 20 | background-color: #add8e6; 21 | } 22 | h3.function,h3.typedecl { 23 | background-color: #add8e6; 24 | padding-left: 1em; 25 | } 26 | div.spec { 27 | margin-left: 2em; 28 | background-color: #eeeeee; 29 | } 30 | a.module,a.package { 31 | text-decoration:none 32 | } 33 | a.module:hover,a.package:hover { 34 | background-color: #eeeeee; 35 | } 36 | ul.definitions { 37 | list-style-type: none; 38 | } 39 | ul.index { 40 | list-style-type: none; 41 | background-color: #eeeeee; 42 | } 43 | 44 | /* 45 | * Minor style tweaks 46 | */ 47 | ul { 48 | list-style-type: square; 49 | } 50 | table { 51 | border-collapse: collapse; 52 | } 53 | td { 54 | padding: 3 55 | } 56 | -------------------------------------------------------------------------------- /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiroeorz/eredis_pool/bc37bcf72afd1e5c69635fadba020ee2a73087d1/rebar -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ts=4 sw=4 ft=erlang et 3 | 4 | {erl_opts, [warnings_as_errors, 5 | warn_export_all]}. 6 | 7 | {xref_checks, [undefined_function_calls]}. 8 | {cover_enabled, true}. 9 | 10 | {edoc_opts, [{doclet, edown_doclet}, 11 | {dialyzer_specs, all}, 12 | {report_missing_type, true}, 13 | {report_type_mismatch, true}, 14 | {pretty_print, erl_pp}, 15 | {preprocess, true}]}. 16 | 17 | {deps, [ 18 | {eredis, 19 | "1.*", 20 | {git, "https://github.com/wooga/eredis.git", 21 | {tag, "v1.0.8"}}}, 22 | 23 | {poolboy, 24 | "1.5.*", 25 | {git, "https://github.com/devinus/poolboy.git", 26 | {tag, "1.5.1"}}} 27 | ]}. 28 | -------------------------------------------------------------------------------- /src/eredis_pool.app.src: -------------------------------------------------------------------------------- 1 | {application, eredis_pool, 2 | [ 3 | {description, ""}, 4 | {vsn, "1.1"}, 5 | {registered, []}, 6 | {applications, [ 7 | kernel, 8 | stdlib 9 | ]}, 10 | {mod, { eredis_pool_app, []}}, 11 | {env, []} 12 | 13 | %% sample configuration. 14 | %% 15 | %% {env, [ 16 | %% {pools, [ 17 | %% {dbsrv, [ 18 | %% {size, 10}, 19 | %% {max_overflow, 30} 20 | %% ]} 21 | %% ]} 22 | %% ]} 23 | %% 24 | 25 | ]}. 26 | -------------------------------------------------------------------------------- /src/eredis_pool.erl: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author Hiroe Shin 3 | %%% @copyright (C) 2011, Hiroe Shin 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : 9 Oct 2011 by Hiroe Shin 8 | %%%------------------------------------------------------------------- 9 | -module(eredis_pool). 10 | 11 | %% Include 12 | -include_lib("eunit/include/eunit.hrl"). 13 | 14 | %% Default timeout for calls to the client gen_server 15 | %% Specified in http://www.erlang.org/doc/man/gen_server.html#call-3 16 | -define(TIMEOUT, 5000). 17 | 18 | %% API 19 | -export([start/0, stop/0]). 20 | -export([q/2, q/3, qp/2, qp/3, transaction/2, 21 | create_pool/2, create_pool/3, create_pool/4, create_pool/5, 22 | create_pool/6, create_pool/7, 23 | delete_pool/1]). 24 | 25 | %%%=================================================================== 26 | %%% API functions 27 | %%%=================================================================== 28 | 29 | start() -> 30 | application:start(?MODULE). 31 | 32 | stop() -> 33 | application:stop(?MODULE). 34 | 35 | %% =================================================================== 36 | %% @doc create new pool. 37 | %% @end 38 | %% =================================================================== 39 | -spec(create_pool(PoolName::atom(), Size::integer()) -> 40 | {ok, pid()} | {error,{already_started, pid()}}). 41 | 42 | create_pool(PoolName, Size) -> 43 | eredis_pool_sup:create_pool(PoolName, Size, []). 44 | 45 | -spec(create_pool(PoolName::atom(), Size::integer(), Host::string()) -> 46 | {ok, pid()} | {error,{already_started, pid()}}). 47 | 48 | create_pool(PoolName, Size, Host) -> 49 | eredis_pool_sup:create_pool(PoolName, Size, [{host, Host}]). 50 | 51 | -spec(create_pool(PoolName::atom(), Size::integer(), 52 | Host::string(), Port::integer()) -> 53 | {ok, pid()} | {error,{already_started, pid()}}). 54 | 55 | create_pool(PoolName, Size, Host, Port) -> 56 | eredis_pool_sup:create_pool(PoolName, Size, [{host, Host}, {port, Port}]). 57 | 58 | -spec(create_pool(PoolName::atom(), Size::integer(), 59 | Host::string(), Port::integer(), Database::string()) -> 60 | {ok, pid()} | {error,{already_started, pid()}}). 61 | 62 | create_pool(PoolName, Size, Host, Port, Database) -> 63 | eredis_pool_sup:create_pool(PoolName, Size, [{host, Host}, {port, Port}, 64 | {database, Database}]). 65 | 66 | -spec(create_pool(PoolName::atom(), Size::integer(), 67 | Host::string(), Port::integer(), 68 | Database::string(), Password::string()) -> 69 | {ok, pid()} | {error,{already_started, pid()}}). 70 | 71 | create_pool(PoolName, Size, Host, Port, Database, Password) -> 72 | eredis_pool_sup:create_pool(PoolName, Size, [{host, Host}, {port, Port}, 73 | {database, Database}, 74 | {password, Password}]). 75 | 76 | -spec(create_pool(PoolName::atom(), Size::integer(), 77 | Host::string(), Port::integer(), 78 | Database::string(), Password::string(), 79 | ReconnectSleep::integer()) -> 80 | {ok, pid()} | {error,{already_started, pid()}}). 81 | 82 | create_pool(PoolName, Size, Host, Port, Database, Password, ReconnectSleep) -> 83 | eredis_pool_sup:create_pool(PoolName, Size, [{host, Host}, {port, Port}, 84 | {database, Database}, 85 | {password, Password}, 86 | {reconnect_sleep, ReconnectSleep}]). 87 | 88 | 89 | %% =================================================================== 90 | %% @doc delet pool and disconnected to Redis. 91 | %% @end 92 | %% =================================================================== 93 | -spec(delete_pool(PoolName::atom()) -> ok | {error,not_found}). 94 | 95 | delete_pool(PoolName) -> 96 | eredis_pool_sup:delete_pool(PoolName). 97 | 98 | %%-------------------------------------------------------------------- 99 | %% @doc 100 | %% Executes the given command in the specified connection. The 101 | %% command must be a valid Redis command and may contain arbitrary 102 | %% data which will be converted to binaries. The returned values will 103 | %% always be binaries. 104 | %% @end 105 | %%-------------------------------------------------------------------- 106 | -spec q(PoolName::atom(), Command::iolist()) -> 107 | {ok, binary() | [binary()]} | {error, Reason::binary()}. 108 | 109 | q(PoolName, Command) -> 110 | q(PoolName, Command, ?TIMEOUT). 111 | 112 | -spec q(PoolName::atom(), Command::iolist(), Timeout::integer()) -> 113 | {ok, binary() | [binary()]} | {error, Reason::binary()}. 114 | 115 | q(PoolName, Command, Timeout) -> 116 | poolboy:transaction(PoolName, fun(Worker) -> 117 | eredis:q(Worker, Command, Timeout) 118 | end). 119 | 120 | -spec qp(PoolName::atom(), Command::iolist(), Timeout::integer()) -> 121 | {ok, binary() | [binary()]} | {error, Reason::binary()}. 122 | 123 | qp(PoolName, Pipeline) -> 124 | qp(PoolName, Pipeline, ?TIMEOUT). 125 | 126 | qp(PoolName, Pipeline, Timeout) -> 127 | poolboy:transaction(PoolName, fun(Worker) -> 128 | eredis:qp(Worker, Pipeline, Timeout) 129 | end). 130 | 131 | 132 | transaction(PoolName, Fun) when is_function(Fun) -> 133 | F = fun(C) -> 134 | try 135 | {ok, <<"OK">>} = eredis:q(C, ["MULTI"]), 136 | Fun(C), 137 | eredis:q(C, ["EXEC"]) 138 | catch Klass:Reason -> 139 | {ok, <<"OK">>} = eredis:q(C, ["DISCARD"]), 140 | io:format("Error in redis transaction. ~p:~p", 141 | [Klass, Reason]), 142 | {Klass, Reason} 143 | end 144 | end, 145 | 146 | poolboy:transaction(PoolName, F). 147 | -------------------------------------------------------------------------------- /src/eredis_pool_app.erl: -------------------------------------------------------------------------------- 1 | -module(eredis_pool_app). 2 | 3 | -behaviour(application). 4 | 5 | %% Application callbacks 6 | -export([start/2, stop/1]). 7 | 8 | %% =================================================================== 9 | %% Application callbacks 10 | %% =================================================================== 11 | 12 | start(_StartType, _StartArgs) -> 13 | eredis_pool_sup:start_link(). 14 | 15 | stop(_State) -> 16 | ok. 17 | -------------------------------------------------------------------------------- /src/eredis_pool_sup.erl: -------------------------------------------------------------------------------- 1 | -module(eredis_pool_sup). 2 | 3 | -behaviour(supervisor). 4 | 5 | %% Include 6 | -include_lib("eunit/include/eunit.hrl"). 7 | 8 | %% API 9 | -export([start_link/0, start_link/2]). 10 | -export([create_pool/3, delete_pool/1]). 11 | 12 | %% Supervisor callbacks 13 | -export([init/1]). 14 | 15 | %% Helper macro for declaring children of supervisor 16 | -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). 17 | 18 | %% =================================================================== 19 | %% API functions 20 | %% =================================================================== 21 | 22 | start_link() -> 23 | {ok, Pools} = application:get_env(eredis_pool, pools), 24 | {ok, GlobalOrLocal} = application:get_env(eredis_pool, global_or_local), 25 | start_link(Pools, GlobalOrLocal). 26 | 27 | start_link(Pools, GlobalOrLocal) -> 28 | supervisor:start_link({local, ?MODULE}, ?MODULE, [Pools, GlobalOrLocal]). 29 | 30 | %% =================================================================== 31 | %% @doc create new pool. 32 | %% @end 33 | %% =================================================================== 34 | -spec(create_pool(PoolName::atom(), Size::integer(), Options::[tuple()]) -> 35 | {ok, pid()} | {error,{already_started, pid()}}). 36 | 37 | create_pool(PoolName, Size, Options) -> 38 | create_pool(local, PoolName, Size, Options). 39 | 40 | %% =================================================================== 41 | %% @doc create new pool, selectable name zone global or local. 42 | %% @end 43 | %% =================================================================== 44 | -spec(create_pool(GlobalOrLocal::atom(), PoolName::atom(), Size::integer(), Options::[tuple()]) -> 45 | {ok, pid()} | {error,{already_started, pid()}}). 46 | 47 | create_pool(GlobalOrLocal, PoolName, Size, Options) 48 | when GlobalOrLocal =:= local; 49 | GlobalOrLocal =:= global -> 50 | 51 | SizeArgs = [{size, Size}, {max_overflow, 10}], 52 | PoolArgs = [{name, {GlobalOrLocal, PoolName}}, {worker_module, eredis}], 53 | PoolSpec = poolboy:child_spec(PoolName, PoolArgs ++ SizeArgs, Options), 54 | 55 | supervisor:start_child(?MODULE, PoolSpec). 56 | 57 | %% =================================================================== 58 | %% @doc delet pool and disconnected to Redis. 59 | %% @end 60 | %% =================================================================== 61 | -spec(delete_pool(PoolName::atom()) -> ok | {error,not_found}). 62 | 63 | delete_pool(PoolName) -> 64 | supervisor:terminate_child(?MODULE, PoolName), 65 | supervisor:delete_child(?MODULE, PoolName). 66 | 67 | %% =================================================================== 68 | %% Supervisor callbacks 69 | %% =================================================================== 70 | 71 | init([Pools, GlobalOrLocal]) -> 72 | RestartStrategy = one_for_one, 73 | MaxRestarts = 10, 74 | MaxSecondsBetweenRestarts = 10, 75 | 76 | SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts}, 77 | 78 | PoolSpecs = lists:map(fun({Name, SizeArgs, WorkerArgs}) -> 79 | PoolArgs = [{name, {GlobalOrLocal, Name}}, 80 | {worker_module, eredis}] ++ SizeArgs, 81 | poolboy:child_spec(Name, PoolArgs, WorkerArgs) 82 | end, Pools), 83 | 84 | {ok, {SupFlags, PoolSpecs}}. 85 | -------------------------------------------------------------------------------- /test.config: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ts=4 sw=4 ft=erlang et 3 | 4 | [{eredis_pool, 5 | [ 6 | {global_or_local, local}, 7 | {pools, [{dbsrv, [ 8 | {size, 10}, 9 | {max_overflow, 30} 10 | ],[] } 11 | ]} 12 | 13 | ] 14 | }]. 15 | -------------------------------------------------------------------------------- /test/eredis_pool_tests.erl: -------------------------------------------------------------------------------- 1 | -module(eredis_pool_tests). 2 | 3 | -include_lib("eunit/include/eunit.hrl"). 4 | 5 | -import(eredis, [create_multibulk/1]). 6 | 7 | -define(Setup, fun() -> application:start(eredis_pool) end). 8 | -define(Clearnup, fun(_) -> application:stop(eredis_pool) end). 9 | -define(DEFAULT, dbsrv). 10 | 11 | transaction_test_() -> 12 | {inparallel, 13 | {setup, ?Setup, ?Clearnup, 14 | [ 15 | 16 | { "transaction", 17 | fun() -> 18 | eredis_pool:q(?DEFAULT, ["DEL", queue1, bar]), 19 | eredis_pool:q(?DEFAULT, ["DEL", queue2, bar]), 20 | 21 | {ok, _} = 22 | eredis_pool:q(?DEFAULT, ["RPUSH", queue1, bar]), 23 | 24 | Fun = 25 | fun(C) -> 26 | {ok, <<"QUEUED">>} = eredis:q(C, ["LREM", 27 | queue1, 1, 28 | bar]), 29 | 30 | {ok, <<"QUEUED">>} = eredis:q(C, ["RPUSH", 31 | queue2, 32 | bar]) 33 | end, 34 | 35 | {ok, [<<"1">>, <<"1">>]} = 36 | eredis_pool:transaction(?DEFAULT, Fun), 37 | 38 | ?assertEqual({ok, <<"0">>}, 39 | eredis_pool:q(?DEFAULT, ["LLEN", queue1])), 40 | ?assertEqual({ok, <<"1">>}, 41 | eredis_pool:q(?DEFAULT, ["LLEN", queue2])) 42 | end 43 | }, 44 | 45 | { "rollback", 46 | fun() -> 47 | eredis_pool:q(?DEFAULT, ["DEL", queue3, bar]), 48 | eredis_pool:q(?DEFAULT, ["DEL", queue4, bar]), 49 | 50 | {ok, _} = 51 | eredis_pool:q(?DEFAULT, ["RPUSH", queue3, bar]), 52 | 53 | Fun = 54 | fun(C) -> 55 | {ok, <<"QUEUED">>} = eredis:q(C, ["LREM", 56 | queue3, 1, 57 | bar]), 58 | throw(normal) 59 | end, 60 | 61 | {throw, normal} = eredis_pool:transaction(?DEFAULT, Fun), 62 | 63 | ?assertEqual({ok, <<"1">>}, 64 | eredis_pool:q(?DEFAULT, ["LLEN", queue3])), 65 | ?assertEqual({ok, <<"0">>}, 66 | eredis_pool:q(?DEFAULT, ["LLEN", queue4])) 67 | end 68 | } 69 | 70 | ] 71 | } 72 | }. 73 | 74 | basic_test_() -> 75 | {inparallel, 76 | 77 | {setup, ?Setup, ?Clearnup, 78 | [ 79 | 80 | { "get and set", 81 | fun() -> 82 | ?assertMatch({ok, _}, eredis_pool:q(?DEFAULT, ["DEL", foo1])), 83 | 84 | ?assertEqual({ok, undefined}, 85 | eredis_pool:q(?DEFAULT, ["GET", foo1])), 86 | 87 | ?assertEqual({ok, <<"OK">>}, 88 | eredis_pool:q(?DEFAULT, ["SET", foo1, bar])), 89 | 90 | ?assertEqual({ok, <<"bar">>}, 91 | eredis_pool:q(?DEFAULT, ["GET", foo1])) 92 | end 93 | }, 94 | 95 | { "delete test", 96 | fun() -> 97 | ?assertMatch({ok, _}, eredis_pool:q(?DEFAULT, ["DEL", foo2])), 98 | 99 | ?assertEqual({ok, <<"OK">>}, 100 | eredis_pool:q(?DEFAULT, ["SET", foo2, bar])), 101 | 102 | ?assertEqual({ok, <<"1">>}, 103 | eredis_pool:q(?DEFAULT, ["DEL", foo2])), 104 | 105 | ?assertEqual({ok, undefined}, 106 | eredis_pool:q(?DEFAULT, ["GET", foo2])) 107 | end 108 | }, 109 | 110 | { "mset and mget", 111 | fun() -> 112 | Keys = lists:seq(1, 1000), 113 | 114 | ?assertMatch({ok, _}, eredis_pool:q(?DEFAULT, ["DEL" | Keys])), 115 | 116 | KeyValuePairs = [[K, K*2] || K <- Keys], 117 | ExpectedResult = 118 | [list_to_binary(integer_to_list(K * 2)) || K <- Keys], 119 | 120 | ?assertEqual({ok, <<"OK">>}, 121 | eredis_pool:q(?DEFAULT, 122 | ["MSET" | lists:flatten(KeyValuePairs)])), 123 | 124 | ?assertEqual({ok, ExpectedResult}, 125 | eredis_pool:q(?DEFAULT, ["MGET" | Keys])), 126 | 127 | ?assertMatch({ok, _}, eredis_pool:q(?DEFAULT, ["DEL" | Keys])) 128 | end 129 | }, 130 | 131 | { "new pool create and delete", 132 | fun() -> 133 | ?assertMatch({ok, _}, 134 | eredis_pool:create_pool(pool1, 10)), 135 | 136 | ?assertMatch({ok, _}, eredis_pool:q(pool1, ["DEL", foo1])), 137 | 138 | ?assertEqual({ok, undefined}, 139 | eredis_pool:q(pool1, ["GET", foo1])), 140 | 141 | ?assertEqual({ok, <<"OK">>}, 142 | eredis_pool:q(pool1, ["SET", foo1, bar])), 143 | 144 | ?assertEqual({ok, <<"bar">>}, 145 | eredis_pool:q(pool1, ["GET", foo1])), 146 | 147 | ?assertEqual(ok, eredis_pool:delete_pool(pool1)) 148 | end 149 | } 150 | 151 | ] 152 | } 153 | }. 154 | --------------------------------------------------------------------------------