From 06694f47344f1f5a1734ccd4211e4567d92f2097 Mon Sep 17 00:00:00 2001 From: Eric Lan Date: Wed, 20 May 2020 10:05:45 +0800 Subject: [PATCH] Implement nif pooling using poolboy This is to speed up by allowing providing a pool of nifs to encrypt/decrypt. Add poolboy 1.5.2 dependency --- README.md | 6 ++++++ rebar.config | 3 +++ rebar.lock | 7 ++++++- src/bcrypt.app.src | 10 +++++++--- src/bcrypt_nif_pool_sup.erl | 27 +++++++++++++++++++++++++++ src/bcrypt_nif_worker.erl | 21 ++++++++++++++------- src/bcrypt_sup.erl | 6 +++--- test/bcrypt_tests.erl | 1 + 8 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 src/bcrypt_nif_pool_sup.erl diff --git a/README.md b/README.md index 77dc5c4..01509ad 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,12 @@ application's environment: `pool_size` Specifies the size of the port program pool. Defaults to ``4``. +`nif_pool_size` + Specifies the size of the nif program pool. Defaults to ``4``. + +`nif_pool_max_overflow` + Specifies the max workers to overflow of the nif program pool. Defaults to ``10``. + Original authors ---------------- diff --git a/rebar.config b/rebar.config index 55a9959..3c4e4ac 100644 --- a/rebar.config +++ b/rebar.config @@ -12,3 +12,6 @@ {post_hooks, [{"(linux|darwin|solaris)", clean, "make -C c_src clean"}, {"(freebsd)", clean, "gmake -C c_src clean"}]}. +{deps, [ + {poolboy, "1.5.2"} +]}. \ No newline at end of file diff --git a/rebar.lock b/rebar.lock index 57afcca..6dabcf6 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1 +1,6 @@ -[]. +{"1.1.0", +[{<<"poolboy">>,{pkg,<<"poolboy">>,<<"1.5.2">>},0}]}. +[ +{pkg_hash,[ + {<<"poolboy">>, <<"392B007A1693A64540CEAD79830443ABF5762F5D30CF50BC95CB2C1AAAFA006B">>}]} +]. diff --git a/src/bcrypt.app.src b/src/bcrypt.app.src index 5b9ad9c..155fb24 100644 --- a/src/bcrypt.app.src +++ b/src/bcrypt.app.src @@ -2,9 +2,9 @@ {application, bcrypt, [ {description, "An Erlang wrapper (NIF or port program) for the OpenBSD password scheme, bcrypt."}, {vsn, "git"}, - {registered, [bcrypt_sup, bcrypt_nif_worker, bcrypt_port_sup, bcrypt_pool]}, + {registered, [bcrypt_sup, bcrypt_port_sup, bcrypt_pool]}, {mod, {bcrypt_app, []}}, - {applications, [kernel, stdlib, crypto]}, + {applications, [kernel, stdlib, crypto, poolboy]}, {env, [ % Default number of 'rounds', defining the hashing complexity {default_log_rounds, 12}, @@ -13,7 +13,11 @@ {mechanism, nif}, % Size of port program pool - {pool_size, 4} + {pool_size, 4}, + + {nif_pool_size, 4}, + {nif_pool_max_overflow, 10} + ]}, {maintainers, ["Hunter Morris", "Mrinal Wadhwa", "ErlangPack"]}, {licenses, ["MIT"]}, diff --git a/src/bcrypt_nif_pool_sup.erl b/src/bcrypt_nif_pool_sup.erl new file mode 100644 index 0000000..ee84ba8 --- /dev/null +++ b/src/bcrypt_nif_pool_sup.erl @@ -0,0 +1,27 @@ +%% Copyright (c) 2011 Hunter Morris +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_nif_pool_sup). + +-behaviour(supervisor). + +-export([start_link/0, start_child/0, init/1]). + +start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). +start_child() -> supervisor:start_child(?MODULE, []). + +init([]) -> + {ok, PoolSize} = application:get_env(bcrypt, nif_pool_size), + {ok, MaxOverFlow} = application:get_env(bcrypt, nif_pool_max_overflow), + + PoolArgs = [ + {name, {local, nif_pool}}, + {nif_pool_size, PoolSize}, + {nif_pool_max_overflow, MaxOverFlow}, + {worker_module, bcrypt_nif_worker} + ], + + PoolSpecs = [ + poolboy:child_spec(nif_pool, PoolArgs, []) + ], + + {ok, {{one_for_one, 10, 10}, PoolSpecs}}. \ No newline at end of file diff --git a/src/bcrypt_nif_worker.erl b/src/bcrypt_nif_worker.erl index aca6bc0..ed1286f 100644 --- a/src/bcrypt_nif_worker.erl +++ b/src/bcrypt_nif_worker.erl @@ -5,7 +5,7 @@ -behaviour(gen_server). --export([start_link/0]). +-export([start_link/1]). -export([gen_salt/0, gen_salt/1]). -export([hashpw/2]). @@ -18,19 +18,26 @@ context }). -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). +start_link(Args) -> gen_server:start_link(?MODULE, Args, []). -gen_salt() -> - gen_server:call(?MODULE, gen_salt, infinity). +gen_salt() -> + poolboy:transaction(nif_pool, fun(Worker) -> + gen_server:call(Worker, gen_salt, infinity) + end). gen_salt(Rounds) -> - gen_server:call(?MODULE, {gen_salt, Rounds}, infinity). + poolboy:transaction(nif_pool, fun(Worker) -> + gen_server:call(Worker, {gen_salt, Rounds}, infinity) + end). + hashpw(Password, Salt) -> - gen_server:call(?MODULE, {hashpw, Password, Salt}, infinity). + poolboy:transaction(nif_pool, fun(Worker) -> + gen_server:call(Worker, {hashpw, Password, Salt}, infinity) + end). init([]) -> + process_flag(trap_exit, true), {ok, Default} = application:get_env(bcrypt, default_log_rounds), Ctx = bcrypt_nif:create_ctx(), {ok, #state{default_log_rounds = Default, context = Ctx}}. diff --git a/src/bcrypt_sup.erl b/src/bcrypt_sup.erl index 714bed1..f39966a 100644 --- a/src/bcrypt_sup.erl +++ b/src/bcrypt_sup.erl @@ -16,10 +16,10 @@ init([]) -> {bcrypt_pool, {bcrypt_pool, start_link, []}, permanent, 16#ffffffff, worker, [bcrypt_pool]}], NifChildren - = [{bcrypt_nif_worker, {bcrypt_nif_worker, start_link, []}, permanent, - 16#ffffffff, worker, [bcrypt_nif_worker]}], + = [{bcrypt_nif_pool_sup, {bcrypt_nif_pool_sup, start_link, []}, permanent, + 16#ffffffff, supervisor, [bcrypt_nif_pool_sup]}], case application:get_env(bcrypt, mechanism) of undefined -> {stop, no_mechanism_defined}; - {ok, nif} -> {ok, {{one_for_all, 1, 1}, NifChildren}}; + {ok, nif} -> {ok, {{one_for_all, 15, 60}, NifChildren}}; {ok, port} -> {ok, {{one_for_all, 15, 60}, PortChildren}} end. diff --git a/test/bcrypt_tests.erl b/test/bcrypt_tests.erl index 1487bc4..c445b72 100644 --- a/test/bcrypt_tests.erl +++ b/test/bcrypt_tests.erl @@ -84,6 +84,7 @@ start_with(Mechanism) when Mechanism =:= nif; Mechanism =:= port -> application:start(crypto), + application:start(poolboy), case application:load(bcrypt) of {error, {already_loaded, bcrypt}} -> ok; ok -> ok