Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Manage connections with Poolboy

Instead of single named processes for BossCache and BossDB, use worker
pools managed by Poolboy. This should increase throughput in high-load
systems. Still needs to be tested, and options should be added for
configuring the number of processes in the pools.
  • Loading branch information...
commit fd2df1d00432e5dd1f84495a735fb2285df960b3 1 parent 863ba63
Evan Miller authored
View
6 rebar.config
@@ -3,10 +3,10 @@
{aleppo, ".*", {git, "git://github.com/evanmiller/aleppo.git", {tag, "1caff84da4"}}},
{bson, ".*", {git, "git://github.com/mongodb/bson-erlang.git", {tag, "adce0e94ab"}}},
{epgsql, ".*", {git, "git://github.com/wg/epgsql.git", {tag, "1.4"}}},
- {erlmc, ".*", {git, "git://github.com/bipthelin/erlmc.git", {tag, "0.4"}}},
+ {erlmc, ".*", {git, "git://github.com/bipthelin/erlmc.git", {tag, "HEAD"}}},
{medici, ".*", {git, "git://github.com/evanmiller/medici.git", {branch, "rebarify"}}},
{mongodb, ".*", {git, "git://github.com/mongodb/mongodb-erlang.git", {tag, "e5e20a0cbd"}}},
{mysql, ".*", {git, "git://github.com/dizzyd/erlang-mysql-driver.git", {tag, "16cae84b5e"}}},
- {riakc, "1.1.*", {git, "git://github.com/basho/riak-erlang-client", {tag, "aa5c64a6a04192662d9c"}}},
- {riakpool, "0.1", {git, "git://github.com/dweldon/riakpool", {tag, "HEAD"}}}
+ {poolboy, ".*", {git, "git://github.com/devinus/poolboy.git", {tag, "855802e0cc"}}},
+ {riakc, "1.1.*", {git, "git://github.com/basho/riak-erlang-client", {tag, "aa5c64a6a04192662d9c"}}}
]}.
View
13 src/boss_cache.erl
@@ -3,20 +3,25 @@
-export([stop/0]).
-export([get/2, set/4, delete/2]).
+-define(POOLNAME, boss_cache_pool).
+
start() ->
- start([{adapter, boss_cache_adapter_memcached_bin}, {cache_servers, [{"127.0.0.1", 11211, 1}]}]).
+ Adapter = boss_cache_adapter_memcached_bin,
+ start([{adapter, Adapter}, {cache_servers, [{"127.0.0.1", 11211, 1}]}]).
start(Options) ->
+ Adapter = proplists:get_value(adapter, Options, boss_cache_adapter_memcached_bin),
+ Adapter:init(Options),
boss_cache_sup:start_link(Options).
stop() ->
ok.
set(Prefix, Key, Val, TTL) ->
- gen_server:call(?MODULE, {set, Prefix, Key, Val, TTL}).
+ boss_pool:call(?POOLNAME, {set, Prefix, Key, Val, TTL}).
get(Prefix, Key) ->
- gen_server:call(?MODULE, {get, Prefix, Key}).
+ boss_pool:call(?POOLNAME, {get, Prefix, Key}).
delete(Prefix, Key) ->
- gen_server:call(?MODULE, {delete, Prefix, Key}).
+ boss_pool:call(?POOLNAME, {delete, Prefix, Key}).
View
2  src/boss_cache_adapter.erl
@@ -4,7 +4,7 @@
%% @spec behaviour_info( atom() ) -> [ {Function::atom(), Arity::integer()} ] | undefined
behaviour_info(callbacks) ->
[
- {start, 0}, {start, 1}, {stop, 1},
+ {start, 0}, {start, 1}, {stop, 1}, {init, 1},
{get, 3}, {set, 5}, {delete, 3}
];
behaviour_info(_Other) ->
View
2  src/boss_cache_controller.erl
@@ -15,7 +15,7 @@ start_link() ->
start_link([]).
start_link(Args) ->
- gen_server:start_link({local, boss_cache}, ?MODULE, Args, []).
+ gen_server:start_link(?MODULE, Args, []).
init(Options) ->
AdapterName = proplists:get_value(adapter, Options, memcached_bin),
View
12 src/boss_cache_sup.erl
@@ -14,10 +14,8 @@ start_link(StartArgs) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, StartArgs).
init(StartArgs) ->
- {ok, {{one_for_one, 10, 10}, [
- {cache_controller, {boss_cache_controller, start_link, [StartArgs]},
- permanent,
- 2000,
- worker,
- [boss_cache_controller]}
- ]}}.
+ Args = [{name, {local, boss_cache_pool}},
+ {worker_module, boss_cache_controller},
+ {size, 20}, {max_overflow, 40}|StartArgs],
+ PoolSpec = {cache_controller, {poolboy, start_link, [Args]}, permanent, 2000, worker, [poolboy]},
+ {ok, {{one_for_one, 10, 10}, [PoolSpec]}}.
View
49 src/boss_db.erl
@@ -29,8 +29,24 @@
data_type/2]).
-define(DEFAULT_TIMEOUT, (30 * 1000)).
+-define(POOLNAME, boss_db_pool).
start(Options) ->
+ AdapterName = proplists:get_value(adapter, Options, mock),
+ Adapter = list_to_atom(lists:concat(["boss_db_adapter_", AdapterName])),
+ Adapter:init(Options),
+ lists:foldr(fun(ShardOptions, Acc) ->
+ case proplists:get_value(db_shard_models, ShardOptions, []) of
+ [] -> Acc;
+ _ ->
+ ShardAdapter = case proplists:get_value(db_adapter, ShardOptions) of
+ undefined -> Adapter;
+ ShortName -> list_to_atom(lists:concat(["boss_db_adapter_", ShortName]))
+ end,
+ ShardAdapter:init(ShardOptions ++ Options),
+ Acc
+ end
+ end, [], proplists:get_value(shards, Options, [])),
boss_db_sup:start_link(Options).
stop() ->
@@ -40,7 +56,7 @@ stop() ->
%% @doc Find a BossRecord with the specified `Id'.
find("") -> undefined;
find(Key) when is_list(Key) ->
- gen_server:call(boss_db, {find, Key}, ?DEFAULT_TIMEOUT);
+ boss_pool:call(?POOLNAME, {find, Key}, ?DEFAULT_TIMEOUT);
find(_) ->
{error, invalid_id}.
@@ -82,8 +98,8 @@ find(Type, Conditions, Max, Skip, Sort) ->
%% sort them numerically.
find(Type, Conditions, Max, Skip, Sort, SortOrder) ->
- gen_server:call(boss_db, {find, Type, normalize_conditions(Conditions), Max, Skip, Sort, SortOrder},
- ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, {find, Type, normalize_conditions(Conditions), Max, Skip, Sort, SortOrder},
+ ?DEFAULT_TIMEOUT).
%% @spec count( Type::atom() ) -> integer()
%% @doc Count the number of BossRecords of type `Type' in the database.
@@ -94,14 +110,14 @@ count(Type) ->
%% @doc Count the number of BossRecords of type `Type' in the database matching
%% all of the given `Conditions'.
count(Type, Conditions) ->
- gen_server:call(boss_db, {count, Type, normalize_conditions(Conditions)}, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, {count, Type, normalize_conditions(Conditions)}, ?DEFAULT_TIMEOUT).
%% @spec counter( Id::string() ) -> integer()
%% @doc Treat the record associated with `Id' as a counter and return its value.
%% Returns 0 if the record does not exist, so to reset a counter just use
%% "delete".
counter(Key) ->
- gen_server:call(boss_db, {counter, Key}, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, {counter, Key}, ?DEFAULT_TIMEOUT).
%% @spec incr( Id::string() ) -> integer()
%% @doc Treat the record associated with `Id' as a counter and atomically increment its value by 1.
@@ -111,7 +127,7 @@ incr(Key) ->
%% @spec incr( Id::string(), Increment::integer() ) -> integer()
%% @doc Treat the record associated with `Id' as a counter and atomically increment its value by `Increment'.
incr(Key, Count) ->
- gen_server:call(boss_db, {incr, Key, Count}, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, {incr, Key, Count}, ?DEFAULT_TIMEOUT).
%% @spec delete( Id::string() ) -> ok | {error, Reason}
%% @doc Delete the BossRecord with the given `Id'.
@@ -119,38 +135,39 @@ delete(Key) ->
AboutToDelete = boss_db:find(Key),
case boss_record_lib:run_before_delete_hooks(AboutToDelete) of
ok ->
- case gen_server:call(boss_db, {delete, Key}, ?DEFAULT_TIMEOUT) of
+ Result = boss_pool:call(?POOLNAME, {delete, Key}, ?DEFAULT_TIMEOUT),
+ case Result of
ok ->
boss_news:deleted(Key, AboutToDelete:attributes()),
ok;
- RetVal ->
- RetVal
+ _ ->
+ Result
end;
{error, Reason} ->
{error, Reason}
end.
push() ->
- gen_server:call(boss_db, push, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, push, ?DEFAULT_TIMEOUT).
pop() ->
- gen_server:call(boss_db, pop, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, pop, ?DEFAULT_TIMEOUT).
depth() ->
- gen_server:call(boss_db, depth, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, depth, ?DEFAULT_TIMEOUT).
dump() ->
- gen_server:call(boss_db, depth, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, dump, ?DEFAULT_TIMEOUT).
%% @spec execute( Commands::iolist() ) -> RetVal
%% @doc Execute raw database commands on SQL databases
execute(Commands) ->
- gen_server:call(boss_db, {execute, Commands}, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, {execute, Commands}, ?DEFAULT_TIMEOUT).
%% @spec transaction( TransactionFun::function() ) -> {atomic, Result} | {aborted, Reason}
%% @doc Execute a fun inside a transaction.
transaction(TransactionFun) ->
- gen_server:call(boss_db, {transaction, TransactionFun}, ?DEFAULT_TIMEOUT).
+ boss_pool:call(?POOLNAME, {transaction, TransactionFun}, ?DEFAULT_TIMEOUT).
%% @spec save_record( BossRecord ) -> {ok, SavedBossRecord} | {error, [ErrorMessages]}
%% @doc Save (that is, create or update) the given BossRecord in the database.
@@ -176,7 +193,7 @@ save_record(Record) ->
end,
case HookResult of
{ok, PossiblyModifiedRecord} ->
- case gen_server:call(boss_db, {save_record, PossiblyModifiedRecord}, ?DEFAULT_TIMEOUT) of
+ case boss_pool:call(?POOLNAME, {save_record, PossiblyModifiedRecord}, ?DEFAULT_TIMEOUT) of
{ok, SavedRecord} ->
boss_record_lib:run_after_hooks(OldRecord, SavedRecord, IsNew),
{ok, SavedRecord};
View
2  src/boss_db_adapter.erl
@@ -4,7 +4,7 @@
%% @spec behaviour_info( atom() ) -> [ {Function::atom(), Arity::integer()} ] | undefined
behaviour_info(callbacks) ->
[
- {start, 0}, {start, 1}, {stop, 1},
+ {start, 0}, {start, 1}, {stop, 1}, {init, 1},
{find, 2}, {find, 7}, {count, 3},
{delete, 2}, {counter, 2}, {incr, 3}, {save_record, 2}
];
View
6 src/boss_db_controller.erl
@@ -20,7 +20,7 @@ start_link() ->
start_link([]).
start_link(Args) ->
- gen_server:start_link({local, boss_db}, ?MODULE, Args, []).
+ gen_server:start_link(?MODULE, Args, []).
init(Options) ->
AdapterName = proplists:get_value(adapter, Options, mock),
@@ -51,13 +51,11 @@ init(Options) ->
handle_call({find, Key}, From, #state{ cache_enable = true, cache_prefix = Prefix } = State) ->
case boss_cache:get(Prefix, Key) of
undefined ->
- io:format("Not cached: ~p~n", [Key]),
{reply, Res, _} = handle_call({find, Key}, From, State#state{ cache_enable = false }),
boss_cache:set(Prefix, Key, Res, State#state.cache_ttl),
boss_news:set_watch(Key, lists:concat([Key, ", ", Key, ".*"]), fun boss_db_cache:handle_record_news/3, {Prefix, Key}, State#state.cache_ttl),
{reply, Res, State};
CachedValue ->
- io:format("Cached! ~p~n", [CachedValue]),
boss_news:extend_watch(Key),
{reply, CachedValue, State}
end;
@@ -70,14 +68,12 @@ handle_call({find, Type, Conditions, Max, Skip, Sort, SortOrder} = Cmd, From,
Key = {Type, Conditions, Max, Skip, Sort, SortOrder},
case boss_cache:get(Prefix, Key) of
undefined ->
- io:format("Not cached: ~p~n", [Key]),
{reply, Res, _} = handle_call(Cmd, From, State#state{ cache_enable = false }),
boss_cache:set(Prefix, Key, Res, State#state.cache_ttl),
boss_news:set_watch(Key, lists:concat([inflector:pluralize(atom_to_list(Type)), ", ", Type, "-*.*"]),
fun boss_db_cache:handle_collection_news/3, {Prefix, Key}, State#state.cache_ttl),
{reply, Res, State};
CachedValue ->
- io:format("Cached! ~p~n", [CachedValue]),
boss_news:extend_watch(Key),
{reply, CachedValue, State}
end;
View
12 src/boss_db_sup.erl
@@ -14,10 +14,8 @@ start_link(StartArgs) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, StartArgs).
init(StartArgs) ->
- {ok, {{one_for_one, 10, 10}, [
- {db_controller, {boss_db_controller, start_link, [StartArgs]},
- permanent,
- 2000,
- worker,
- [boss_db_controller]}
- ]}}.
+ Args = [{name, boss_db_pool},
+ {worker_module, boss_db_controller},
+ {size, 5}, {max_overflow, 10}|StartArgs],
+ PoolSpec = {db_controller, {poolboy, start_link, [Args]}, permanent, 2000, worker, [poolboy]},
+ {ok, {{one_for_one, 10, 10}, [PoolSpec]}}.
View
11 src/cache_adapters/boss_cache_adapter_memcached_bin.erl
@@ -1,20 +1,23 @@
-module(boss_cache_adapter_memcached_bin).
-behaviour(boss_cache_adapter).
--export([start/0, start/1, stop/1]).
+-export([init/1, start/0, start/1, stop/1]).
-export([get/3, set/5, delete/3]).
start() ->
start([]).
-start(Options) ->
- CacheServers = proplists:get_value(cache_servers, Options, [{"localhost", 11211, 1}]),
- ok = erlmc:start(CacheServers),
+start(_Options) ->
{ok, undefined}.
stop(_Conn) ->
erlmc:quit().
+init(Options) ->
+ CacheServers = proplists:get_value(cache_servers, Options, [{"localhost", 11211, 1}]),
+ ok = erlmc:start(CacheServers),
+ ok.
+
get(_Conn, Prefix, Key) ->
case erlmc:get(term_to_key(Prefix, Key)) of
<<>> ->
View
9 src/db_adapters/boss_db_adapter_mnesia.erl
@@ -1,24 +1,23 @@
-module(boss_db_adapter_mnesia).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1, find/2, find/7]).
+-export([init/1, start/0, start/1, stop/1, find/2, find/7]).
-export([count/3, counter/2, incr/3, delete/2, save_record/2]).
-export([transaction/2]).
%-define(TRILLION, (1000 * 1000 * 1000 * 1000)).
+init([]) ->
+ application:start(mnesia).
+
% -----
start() ->
-%io:format("==> Start/0 Called~n"),
start([]).
start(_Options) ->
-%io:format("==> Start/1 Called~n"),
- application:start(mnesia),
{ok, undefined}.
% -----
stop(_) ->
-%io:format("==> Stop/0 Called~n"),
application:stop(mnesia).
% -----
View
18 src/db_adapters/boss_db_adapter_mock.erl
@@ -1,22 +1,24 @@
% In-memory database for fast tests and easy setup
-module(boss_db_adapter_mock).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1]).
+-export([init/1, start/0, start/1, stop/1]).
-export([find/2, find/7, count/3, counter/2, incr/3, delete/2, save_record/2]).
-export([push/2, pop/2, dump/1, transaction/2]).
-start() ->
- start([]).
-
-start(Options) ->
+init(Options) ->
case proplists:get_value(is_master_node, Options, true) of
true ->
- {ok, MockSup} = boss_db_mock_sup:start_link(),
- {ok, MockSup};
+ boss_db_mock_sup:start_link();
false ->
- {ok, undefined}
+ ok
end.
+start() ->
+ start([]).
+
+start(_Options) ->
+ {ok, undefined}.
+
stop(undefined) ->
ok;
stop(MockSup) ->
View
5 src/db_adapters/boss_db_adapter_mongodb.erl
@@ -1,6 +1,6 @@
-module(boss_db_adapter_mongodb).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1, find/2, find/7]).
+-export([init/1, start/0, start/1, stop/1, find/2, find/7]).
-export([count/3, counter/2, incr/2, incr/3, delete/2, save_record/2]).
-export([execute/2]).
-export([push/2, pop/2]).
@@ -14,6 +14,8 @@
-define(CONTAINS_FORMAT, "this.~s.indexOf('~s') != -1").
-define(NOT_CONTAINS_FORMAT, "this.~s.indexOf('~s') == -1").
+init(_Options) ->
+ application:start(mongodb).
start() ->
start([]).
@@ -24,7 +26,6 @@ start(Options) ->
Database = proplists:get_value(db_database, Options, test),
WriteMode = proplists:get_value(db_write_mode, Options, safe),
ReadMode = proplists:get_value(db_read_mode, Options, master),
- application:start(mongodb),
{ok, Connection} = mongo:connect({Host, Port}),
% We pass around arguments required by mongo:do/5
{ok, {WriteMode, ReadMode, Connection, Database}}.
View
58 src/db_adapters/boss_db_adapter_mysql.erl
@@ -1,9 +1,12 @@
-module(boss_db_adapter_mysql).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1, find/2, find/7]).
+-export([init/1, start/0, start/1, stop/1, find/2, find/7]).
-export([count/3, counter/2, incr/3, delete/2, save_record/2]).
-export([push/2, pop/2, dump/1, execute/2, transaction/2]).
+init(_) ->
+ ok.
+
start() ->
start([]).
@@ -14,21 +17,15 @@ start(Options) ->
DBPassword = proplists:get_value(db_password, Options, ""),
DBDatabase = proplists:get_value(db_database, Options, "test"),
DBIdentifier = proplists:get_value(db_shard_id, Options, boss_pool),
- Result = mysql:start(DBIdentifier, DBHost, DBPort, DBUsername, DBPassword, DBDatabase, fun(_, _, _, _) -> ok end, utf8),
- case Result of
- {error, {already_started,_}} ->
- mysql:connect(DBIdentifier, DBHost, DBPort, DBUsername, DBPassword, DBDatabase, utf8, true, false);
- _ ->
- ok
- end,
- {ok, DBIdentifier}.
+ Encoding = utf8,
+ mysql_conn:start(DBHost, DBPort, DBUsername, DBPassword, DBDatabase,
+ fun(_, _, _, _) -> ok end, Encoding, DBIdentifier).
stop(_Pid) -> ok.
find(Pid, Id) when is_list(Id) ->
{Type, TableName, TableId} = infer_type_from_id(Id),
- Res = mysql:fetch(Pid, ["SELECT * FROM ", TableName,
- " WHERE id = ", pack_value(TableId)]),
+ Res = fetch(Pid, ["SELECT * FROM ", TableName, " WHERE id = ", pack_value(TableId)]),
case Res of
{data, MysqlRes} ->
case mysql:get_result_rows(MysqlRes) of
@@ -50,7 +47,7 @@ find(Pid, Type, Conditions, Max, Skip, Sort, SortOrder) when is_atom(Type), is_l
case boss_record_lib:ensure_loaded(Type) of
true ->
Query = build_select_query(Type, Conditions, Max, Skip, Sort, SortOrder),
- Res = mysql:fetch(Pid, Query),
+ Res = fetch(Pid, Query),
case Res of
{data, MysqlRes} ->
Columns = mysql:get_result_field_info(MysqlRes),
@@ -73,8 +70,7 @@ find(Pid, Type, Conditions, Max, Skip, Sort, SortOrder) when is_atom(Type), is_l
count(Pid, Type, Conditions) ->
ConditionClause = build_conditions(Conditions),
TableName = type_to_table_name(Type),
- Res = mysql:fetch(Pid, ["SELECT COUNT(*) AS count FROM ", TableName,
- " WHERE ", ConditionClause]),
+ Res = fetch(Pid, ["SELECT COUNT(*) AS count FROM ", TableName, " WHERE ", ConditionClause]),
case Res of
{data, MysqlRes} ->
[[Count]] = mysql:get_result_rows(MysqlRes),
@@ -84,7 +80,7 @@ count(Pid, Type, Conditions) ->
end.
counter(Pid, Id) when is_list(Id) ->
- Res = mysql:fetch(Pid, ["SELECT value FROM counters WHERE name = ", pack_value(Id)]),
+ Res = fetch(Pid, ["SELECT value FROM counters WHERE name = ", pack_value(Id)]),
case Res of
{data, MysqlRes} ->
[[Value]] = mysql:get_result_rows(MysqlRes),
@@ -93,13 +89,13 @@ counter(Pid, Id) when is_list(Id) ->
end.
incr(Pid, Id, Count) ->
- Res = mysql:fetch(Pid, ["UPDATE counters SET value = value + ", pack_value(Count),
+ Res = fetch(Pid, ["UPDATE counters SET value = value + ", pack_value(Count),
" WHERE name = ", pack_value(Id)]),
case Res of
{updated, _} ->
counter(Pid, Id); % race condition
{error, _Reason} ->
- Res1 = mysql:fetch(Pid, ["INSERT INTO counters (name, value) VALUES (",
+ Res1 = fetch(Pid, ["INSERT INTO counters (name, value) VALUES (",
pack_value(Id), ", ", pack_value(Count), ")"]),
case Res1 of
{updated, _} -> counter(Pid, Id); % race condition
@@ -109,11 +105,11 @@ incr(Pid, Id, Count) ->
delete(Pid, Id) when is_list(Id) ->
{_, TableName, TableId} = infer_type_from_id(Id),
- Res = mysql:fetch(Pid, ["DELETE FROM ", TableName, " WHERE id = ",
+ Res = fetch(Pid, ["DELETE FROM ", TableName, " WHERE id = ",
pack_value(TableId)]),
case Res of
{updated, _} ->
- mysql:fetch(Pid, ["DELETE FROM counters WHERE name = ",
+ fetch(Pid, ["DELETE FROM counters WHERE name = ",
pack_value(Id)]),
ok;
{error, MysqlRes} -> {error, mysql:get_result_reason(MysqlRes)}
@@ -124,10 +120,10 @@ save_record(Pid, Record) when is_tuple(Record) ->
id ->
Type = element(1, Record),
Query = build_insert_query(Record),
- Res = mysql:fetch(Pid, Query),
+ Res = fetch(Pid, Query),
case Res of
{updated, _} ->
- Res1 = mysql:fetch(Pid, "SELECT last_insert_id()"),
+ Res1 = fetch(Pid, "SELECT last_insert_id()"),
case Res1 of
{data, MysqlRes} ->
[[Id]] = mysql:get_result_rows(MysqlRes),
@@ -140,7 +136,7 @@ save_record(Pid, Record) when is_tuple(Record) ->
Identifier when is_integer(Identifier) ->
Type = element(1, Record),
Query = build_insert_query(Record),
- Res = mysql:fetch(Pid, Query),
+ Res = fetch(Pid, Query),
case Res of
{updated, _} ->
{ok, Record:set(id, lists:concat([Type, "-", integer_to_list(Identifier)]))};
@@ -148,7 +144,7 @@ save_record(Pid, Record) when is_tuple(Record) ->
end;
Defined when is_list(Defined) ->
Query = build_update_query(Record),
- Res = mysql:fetch(Pid, Query),
+ Res = fetch(Pid, Query),
case Res of
{updated, _} -> {ok, Record};
{error, MysqlRes} -> {error, mysql:get_result_reason(MysqlRes)}
@@ -156,20 +152,20 @@ save_record(Pid, Record) when is_tuple(Record) ->
end.
push(Pid, Depth) ->
- case Depth of 0 -> mysql:fetch(Pid, "BEGIN"); _ -> ok end,
- mysql:fetch(Pid, ["SAVEPOINT savepoint", integer_to_list(Depth)]).
+ case Depth of 0 -> fetch(Pid, "BEGIN"); _ -> ok end,
+ fetch(Pid, ["SAVEPOINT savepoint", integer_to_list(Depth)]).
pop(Pid, Depth) ->
- mysql:fetch(Pid, ["ROLLBACK TO SAVEPOINT savepoint", integer_to_list(Depth - 1)]),
- mysql:fetch(Pid, ["RELEASE SAVEPOINT savepoint", integer_to_list(Depth - 1)]).
+ fetch(Pid, ["ROLLBACK TO SAVEPOINT savepoint", integer_to_list(Depth - 1)]),
+ fetch(Pid, ["RELEASE SAVEPOINT savepoint", integer_to_list(Depth - 1)]).
dump(_Conn) -> "".
execute(Pid, Commands) ->
- mysql:fetch(Pid, Commands).
+ fetch(Pid, Commands).
transaction(Pid, TransactionFun) when is_function(TransactionFun) ->
- mysql:transaction(Pid, TransactionFun).
+ mysql_conn:transaction(Pid, TransactionFun, self()).
% internal
@@ -408,3 +404,7 @@ pack_value(true) ->
"TRUE";
pack_value(false) ->
"FALSE".
+
+fetch(Pid, Query) ->
+ mysql_conn:fetch(Pid, [Query], self()).
+
View
5 src/db_adapters/boss_db_adapter_pgsql.erl
@@ -1,9 +1,12 @@
-module(boss_db_adapter_pgsql).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1, find/2, find/7]).
+-export([init/1, start/0, start/1, stop/1, find/2, find/7]).
-export([count/3, counter/2, incr/3, delete/2, save_record/2]).
-export([push/2, pop/2, dump/1, execute/2, transaction/2]).
+init(_) ->
+ ok.
+
start() ->
start([]).
View
48 src/db_adapters/boss_db_adapter_riak.erl
@@ -1,6 +1,6 @@
-module(boss_db_adapter_riak).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1, find/2, find/7]).
+-export([init/1, start/0, start/1, stop/1, find/2, find/7]).
-export([count/3, counter/2, incr/2, incr/3, delete/2, save_record/2]).
-export([push/2, pop/2]).
@@ -8,26 +8,25 @@
-define(HUGE_INT, 1000 * 1000 * 1000 * 1000).
+init(_Options) ->
+ % TODO: crypto is needed for unique_id_62/0. Remove it when
+ % unique_id_62/0 is not needed.
+ crypto:start().
+
start() ->
start([]).
start(Options) ->
- % TODO: crypto is needed for unique_id_62/0. Remove it when
- % unique_id_62/0 is not needed.
- crypto:start(),
- application:start(riakpool),
Host = proplists:get_value(db_host, Options, "localhost"),
Port = proplists:get_value(db_port, Options, 8087),
- riakpool:start_pool(Host, Port),
- {ok, undefined}.
+ riakc_pb_socket:start_link(Host, Port).
stop(_) ->
- riakpool:stop(),
ok.
-find(_, Id) ->
+find(Conn, Id) ->
{Type, Bucket, Key} = infer_type_from_id(Id),
- case riakpool_client:get(Bucket, Key) of
+ case riakc_pb_socket:get(Conn, Bucket, Key) of
{ok, Value} ->
Data = binary_to_term(Value),
Record = apply(Type, new, lists:map(fun (AttrName) ->
@@ -50,11 +49,8 @@ find_acc(Prefix, [Id | Rest], Acc) ->
end.
% this is a stub just to make the tests runable
-find(_, Type, Conditions, Max, Skip, Sort, SortOrder) ->
- Fun = fun(C) ->
- riakc_pb_socket:search(C, type_to_bucket_name(Type), build_search_query(Conditions))
- end,
- {ok, {ok, Keys}} = riakpool:execute(Fun),
+find(Conn, Type, Conditions, Max, Skip, Sort, SortOrder) ->
+ {ok, Keys} = riakc_pb_socket:search(Conn, type_to_bucket_name(Type), build_search_query(Conditions)),
Records = find_acc(atom_to_list(Type) ++ "-", Keys, []),
Sorted = if
is_atom(Sort) ->
@@ -87,13 +83,13 @@ incr(_Conn, _Id, _Count) ->
{error, notimplemented}.
-delete(_, Id) ->
+delete(Conn, Id) ->
{_Type, Bucket, Key} = infer_type_from_id(Id),
- ok = riakpool_client:delete(Bucket, Key).
+ ok = riakc_pb_socket:delete(Conn, Bucket, Key).
-save_record(_, Record) ->
+save_record(Conn, Record) ->
Type = element(1, Record),
- Bucket = type_to_bucket_name(Type),
+ Bucket = list_to_binary(type_to_bucket_name(Type)),
PropList = [{K, V} || {K, V} <- Record:attributes(), K =/= id],
Key = case Record:id() of
id ->
@@ -104,9 +100,17 @@ save_record(_, Record) ->
[_ | Tail] = string:tokens(DefinedId, "-"),
string:join(Tail, "-")
end,
- ok = riakpool_client:put(list_to_binary(Bucket), list_to_binary(Key),
- term_to_binary(PropList)),
- {ok, Record:set(id, atom_to_list(Type) ++ "-" ++ Key)}.
+ BinKey = list_to_binary(Key),
+ BinVal = term_to_binary(PropList),
+ ok = case riakc_pb_socket:get(Conn, Bucket, BinKey) of
+ {ok, O} ->
+ O2 = riakc_obj:update_value(O, BinVal),
+ riakc_pb_socket:put(Conn, O2);
+ {error, _} ->
+ O = riakc_obj:new(Bucket, BinKey, BinVal),
+ riakc_pb_socket:put(Conn, O)
+ end,
+ {ok, Record:set(id, lists:concat([Type, "-", Key]))}.
% These 2 functions are not part of the behaviour but are required for
% tests to pass
View
47 src/db_adapters/boss_db_adapter_tyrant.erl
@@ -1,25 +1,28 @@
-module(boss_db_adapter_tyrant).
-behaviour(boss_db_adapter).
--export([start/0, start/1, stop/1, find/2, find/7]).
+-export([init/1, start/0, start/1, stop/1, find/2, find/7]).
-export([count/3, counter/2, incr/3, delete/2, save_record/2]).
-define(TRILLION, (1000 * 1000 * 1000 * 1000)).
+init(_) ->
+ ok.
+
start() ->
start([]).
start(Options) ->
Host = proplists:get_value(db_host, Options, "localhost"),
Port = proplists:get_value(db_port, Options, 1978),
- ok = medici:start([{hostname, Host}, {port, Port}]),
- {ok, undefined}.
+ Options = [{hostname, Host}, {port, Port}],
+ principe:connect(Options).
stop(_) ->
- medici:stop().
+ ok.
-find(_, Id) when is_list(Id) ->
+find(Conn, Id) when is_list(Id) ->
Type = infer_type_from_id(Id),
- case medici:get(list_to_binary(Id)) of
+ case principe_table:get(Conn, list_to_binary(Id)) of
Record when is_list(Record) ->
case boss_record_lib:ensure_loaded(Type) of
true -> activate_record(Record, Type);
@@ -31,13 +34,13 @@ find(_, Id) when is_list(Id) ->
{error, Reason}
end.
-find(_, Type, Conditions, Max, Skip, Sort, SortOrder) when is_atom(Type), is_list(Conditions),
+find(Conn, Type, Conditions, Max, Skip, Sort, SortOrder) when is_atom(Type), is_list(Conditions),
is_integer(Max) orelse Max =:= all,
is_integer(Skip), is_atom(Sort), is_atom(SortOrder) ->
case boss_record_lib:ensure_loaded(Type) of
true ->
Query = build_query(Type, Conditions, Max, Skip, Sort, SortOrder),
- ResultRows = medici:mget(medici:search(Query)),
+ ResultRows = principe_table:mget(Conn, principe_table:search(Conn, Query)),
FilteredRows = case {Max, Skip} of
{all, Skip} when Skip > 0 ->
lists:nthtail(Skip, ResultRows);
@@ -49,35 +52,35 @@ find(_, Type, Conditions, Max, Skip, Sort, SortOrder) when is_atom(Type), is_lis
[]
end.
-count(_, Type, Conditions) ->
- medici:searchcount(build_conditions(Type, Conditions)).
+count(Conn, Type, Conditions) ->
+ principe_table:searchcount(Conn, build_conditions(Type, Conditions)).
-counter(_, Id) when is_list(Id) ->
- case medici:get(list_to_binary(Id)) of
+counter(Conn, Id) when is_list(Id) ->
+ case principe_table:get(Conn, list_to_binary(Id)) of
Record when is_list(Record) ->
list_to_integer(binary_to_list(
proplists:get_value(<<"_num">>, Record, <<"0">>)));
{error, _Reason} -> 0
end.
-incr(_, Id, Count) when is_list(Id) ->
- medici:addint(list_to_binary(Id), Count).
+incr(Conn, Id, Count) when is_list(Id) ->
+ principe_table:addint(Conn, list_to_binary(Id), Count).
-delete(_, Id) when is_list(Id) ->
- medici:out(list_to_binary(Id)).
+delete(Conn, Id) when is_list(Id) ->
+ principe_table:out(Conn, list_to_binary(Id)).
-save_record(_, Record) when is_tuple(Record) ->
+save_record(Conn, Record) when is_tuple(Record) ->
Type = element(1, Record),
Id = case Record:id() of
id ->
- atom_to_list(Type) ++ "-" ++ binary_to_list(medici:genuid());
+ atom_to_list(Type) ++ "-" ++ binary_to_list(principe_table:genuid(Conn));
Defined when is_list(Defined) ->
Defined
end,
RecordWithId = Record:set(id, Id),
PackedRecord = pack_record(RecordWithId, Type),
- Result = medici:put(list_to_binary(Id), PackedRecord),
+ Result = principe_table:put(Conn, list_to_binary(Id), PackedRecord),
case Result of
ok -> {ok, RecordWithId};
{error, Error} -> {error, [Error]}
@@ -152,12 +155,12 @@ attribute_to_colname(Attribute) ->
build_query(Type, Conditions, Max, Skip, Sort, SortOrder) ->
Query = build_conditions(Type, Conditions),
Query1 = apply_limit(Query, Max, Skip),
- medici:query_order(Query1, atom_to_list(Sort), SortOrder).
+ principe_table:query_order(Query1, atom_to_list(Sort), SortOrder).
apply_limit(Query, all, _) ->
Query;
apply_limit(Query, Max, Skip) ->
- medici:query_limit(Query, Max, Skip).
+ principe_table:query_limit(Query, Max, Skip).
build_conditions(Type, Conditions) ->
build_conditions1([{'_type', 'equals', atom_to_list(Type)}|Conditions], []).
@@ -206,7 +209,7 @@ build_conditions1([{Key, 'contains_none', Values}|Rest], Acc) when is_list(Value
build_conditions1(Rest, add_cond(Acc, Key, {no, str_or}, pack_tokens(Values))).
add_cond(Acc, Key, Op, PackedVal) ->
- medici:query_add_condition(Acc, attribute_to_colname(Key), Op, [PackedVal]).
+ principe_table:query_add_condition(Acc, attribute_to_colname(Key), Op, [PackedVal]).
pack_tokens(Tokens) ->
list_to_binary(string:join(lists:map(fun(V) -> binary_to_list(pack_value(V)) end, Tokens), " ")).
Please sign in to comment.
Something went wrong with that request. Please try again.