Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 429 lines (341 sloc) 16.611 kb
d036073 BossDB is now its own project
Evan Miller authored
1 -module(boss_db_controller).
2
3 -behaviour(gen_server).
4
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
5 -export([start_link/0, start_link/1, try_connection/2]).
d036073 BossDB is now its own project
Evan Miller authored
6
7 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
8
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
9 -define(MAXDELAY, 10000).
10
d036073 BossDB is now its own project
Evan Miller authored
11 -record(state, {
dbf70e1 @davidw Pop the actual connection stuff into its own callback, so that we can
davidw authored
12 connection_state,
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
13 connection_delay,
9cb4b23 @davidw Keep track of timer and cancel it on termination.
davidw authored
14 connection_retry_timer,
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
15 options,
5cb6a6c @zkessin first chunk of refactor
zkessin authored
16 adapter,
17 read_connection,
18 write_connection,
c8a070d @zkessin More refactoring
zkessin authored
19 shards = [],
20 model_dict = dict:new(),
5cb6a6c @zkessin first chunk of refactor
zkessin authored
21 cache_enable,
22 cache_ttl,
23 cache_prefix,
c8a070d @zkessin More refactoring
zkessin authored
24 depth = 0}).
d036073 BossDB is now its own project
Evan Miller authored
25
c8a070d @zkessin More refactoring
zkessin authored
26 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
27 start_link() ->
28 start_link([]).
29
c8a070d @zkessin More refactoring
zkessin authored
30
31 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
32 start_link(Args) ->
fd2df1d Manage connections with Poolboy
Evan Miller authored
33 gen_server:start_link(?MODULE, Args, []).
d036073 BossDB is now its own project
Evan Miller authored
34
c8a070d @zkessin More refactoring
zkessin authored
35
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
37 connections_for_adapter(Adapter, Options) ->
38 case Adapter:init(Options) of
39 {ok, {readwrite, Read, Write}} ->
40 {ok, {Read, Write}};
41 {ok, Other} ->
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
42 {ok, {Other, Other}};
43 Error ->
44 {connection_error, Error}
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
45 end.
46
c8a070d @zkessin More refactoring
zkessin authored
47
48 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5cb6a6c @zkessin first chunk of refactor
zkessin authored
49 setup_reconnect(State =#state{connection_delay = DelayTime}) ->
50 Delay = case DelayTime of
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
51 D when D < ?MAXDELAY ->
52 D;
53 _ ->
54 ?MAXDELAY
55 end,
56 Pid = self(),
57 timer:apply_after(Delay, boss_db_controller, try_connection, [Pid, State#state.options]).
58
c8a070d @zkessin More refactoring
zkessin authored
59
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
61 try_connection(Pid, Options) ->
62 gen_server:cast(Pid, {try_connect, Options}).
63
c8a070d @zkessin More refactoring
zkessin authored
64
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8f7ad30 @evanmiller Don't terminate undefined connections
evanmiller authored
66 terminate_if_defined(_Adapter, undefined) ->
67 ok;
68 terminate_if_defined(Adapter, Conn) ->
69 Adapter:terminate(Conn).
70
c8a070d @zkessin More refactoring
zkessin authored
71
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
73 terminate_connections(Adapter, RC, RC) ->
8f7ad30 @evanmiller Don't terminate undefined connections
evanmiller authored
74 terminate_if_defined(Adapter, RC);
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
75 terminate_connections(Adapter, RC, WC) ->
8f7ad30 @evanmiller Don't terminate undefined connections
evanmiller authored
76 terminate_if_defined(Adapter, RC),
77 terminate_if_defined(Adapter, WC).
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
78
c8a070d @zkessin More refactoring
zkessin authored
79
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
81 init(Options) ->
82 AdapterName = proplists:get_value(adapter, Options, mock),
5cb6a6c @zkessin first chunk of refactor
zkessin authored
83 Adapter = list_to_atom(lists:concat(["boss_db_adapter_", AdapterName])),
d036073 BossDB is now its own project
Evan Miller authored
84 CacheEnable = proplists:get_value(cache_enable, Options, false),
5cb6a6c @zkessin first chunk of refactor
zkessin authored
85 CacheTTL = proplists:get_value(cache_exp_time, Options, 60),
41308e5 @brigadier Update boss_db_controller.erl
brigadier authored
86 CachePrefix = proplists:get_value(cache_prefix, Options, db),
a944735 Gracefully handle dropped connections
Evan Miller authored
87 process_flag(trap_exit, true),
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
88 try_connection(self(), Options),
5cb6a6c @zkessin first chunk of refactor
zkessin authored
89 {ok, #state{connection_state = connecting,
90 connection_delay = 1,
91 options = Options,
92 adapter = Adapter,
93 cache_enable = CacheEnable,
94 cache_ttl = CacheTTL,
95 cache_prefix = CachePrefix }}.
dbf70e1 @davidw Pop the actual connection stuff into its own callback, so that we can
davidw authored
96
c8a070d @zkessin More refactoring
zkessin authored
97
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
dbf70e1 @davidw Pop the actual connection stuff into its own callback, so that we can
davidw authored
99 handle_call(_Anything, _Anyone, State) when State#state.connection_state /= connected ->
100 {reply, db_connection_down, State};
d036073 BossDB is now its own project
Evan Miller authored
101
102 handle_call({find, Key}, From, #state{ cache_enable = true, cache_prefix = Prefix } = State) ->
c8a070d @zkessin More refactoring
zkessin authored
103 CacheResult = boss_cache:get(Prefix, Key),
104 find_by_key(Key, From, Prefix, State, CacheResult);
d036073 BossDB is now its own project
Evan Miller authored
105 handle_call({find, Key}, _From, #state{ cache_enable = false } = State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
106 {Adapter, Conn, _} = db_for_key(Key, State),
d036073 BossDB is now its own project
Evan Miller authored
107 {reply, Adapter:find(Conn, Key), State};
108
b9b280d @evanmiller Support for pre-caching belongs_to associations
evanmiller authored
109 handle_call({find, Type, Conditions, Max, Skip, Sort, SortOrder, Include} = Cmd, From,
d036073 BossDB is now its own project
Evan Miller authored
110 #state{ cache_enable = true, cache_prefix = Prefix } = State) ->
111 Key = {Type, Conditions, Max, Skip, Sort, SortOrder},
112 case boss_cache:get(Prefix, Key) of
113 undefined ->
5cb6a6c @zkessin first chunk of refactor
zkessin authored
114 Res = find_list(Type, Include, Cmd, From, Prefix, State, Key),
d036073 BossDB is now its own project
Evan Miller authored
115 {reply, Res, State};
116 CachedValue ->
117 boss_news:extend_watch(Key),
118 {reply, CachedValue, State}
119 end;
b9b280d @evanmiller Support for pre-caching belongs_to associations
evanmiller authored
120 handle_call({find, Type, Conditions, Max, Skip, Sort, SortOrder, _}, _From, #state{ cache_enable = false } = State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
121 {Adapter, Conn, _} = db_for_type(Type, State),
d036073 BossDB is now its own project
Evan Miller authored
122 {reply, Adapter:find(Conn, Type, Conditions, Max, Skip, Sort, SortOrder), State};
4dab059 @davidw Added a migration_done function to write to the migrations table that…
davidw authored
123
f5a832b @davidw Initial version of find_by_sql.
davidw authored
124 handle_call({find_by_sql, Type, Sql, Parameters}, _From, State) ->
125 {Adapter, Conn, _} = db_for_type(Type, State),
126 {reply, Adapter:find_by_sql(Conn, Type, Sql, Parameters), State};
127
4aeb83d @davidw Added table_exist and get_migrations_table - the latter fetches the
davidw authored
128 handle_call({get_migrations_table}, _From, #state{ cache_enable = false } = State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
129 {Adapter, Conn} = {State#state.adapter, State#state.read_connection},
4aeb83d @davidw Added table_exist and get_migrations_table - the latter fetches the
davidw authored
130 {reply, Adapter:get_migrations_table(Conn), State};
d036073 BossDB is now its own project
Evan Miller authored
131
f6e9091 @ngaranko Updated migration_done to accept direction (up/down). And Bit of code…
ngaranko authored
132 handle_call({migration_done, Tag, Direction}, _From, #state{ cache_enable = false } = State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
133 {Adapter, Conn} = {State#state.adapter, State#state.write_connection},
f6e9091 @ngaranko Updated migration_done to accept direction (up/down). And Bit of code…
ngaranko authored
134 {reply, Adapter:migration_done(Conn, Tag, Direction), State};
4dab059 @davidw Added a migration_done function to write to the migrations table that…
davidw authored
135
d036073 BossDB is now its own project
Evan Miller authored
136 handle_call({count, Type}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
137 {Adapter, Conn, _} = db_for_type(Type, State),
d036073 BossDB is now its own project
Evan Miller authored
138 {reply, Adapter:count(Conn, Type), State};
139
140 handle_call({count, Type, Conditions}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
141 {Adapter, Conn, _} = db_for_type(Type, State),
d036073 BossDB is now its own project
Evan Miller authored
142 {reply, Adapter:count(Conn, Type, Conditions), State};
143
144 handle_call({counter, Counter}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
145 {Adapter, Conn, _} = db_for_counter(Counter, State),
d036073 BossDB is now its own project
Evan Miller authored
146 {reply, Adapter:counter(Conn, Counter), State};
147
148 handle_call({incr, Key}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
149 {Adapter, _, Conn} = db_for_counter(Key, State),
d036073 BossDB is now its own project
Evan Miller authored
150 {reply, Adapter:incr(Conn, Key), State};
151
152 handle_call({incr, Key, Count}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
153 {Adapter, _, Conn} = db_for_counter(Key, State),
d036073 BossDB is now its own project
Evan Miller authored
154 {reply, Adapter:incr(Conn, Key, Count), State};
155
156 handle_call({delete, Id}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
157 {Adapter, _, Conn} = db_for_key(Id, State),
d036073 BossDB is now its own project
Evan Miller authored
158 {reply, Adapter:delete(Conn, Id), State};
159
160 handle_call({save_record, Record}, _From, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
161 {Adapter, _, Conn} = db_for_record(Record, State),
d036073 BossDB is now its own project
Evan Miller authored
162 {reply, Adapter:save_record(Conn, Record), State};
163
164 handle_call(push, _From, State) ->
165 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
166 Conn = State#state.write_connection,
d036073 BossDB is now its own project
Evan Miller authored
167 Depth = State#state.depth,
168 {reply, Adapter:push(Conn, Depth), State#state{depth = Depth + 1}};
169
170 handle_call(pop, _From, State) ->
171 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
172 Conn = State#state.write_connection,
d036073 BossDB is now its own project
Evan Miller authored
173 Depth = State#state.depth,
174 {reply, Adapter:pop(Conn, Depth), State#state{depth = Depth - 1}};
175
176 handle_call(depth, _From, State) ->
177 {reply, State#state.depth, State};
178
179 handle_call(dump, _From, State) ->
180 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
181 Conn = State#state.read_connection,
d036073 BossDB is now its own project
Evan Miller authored
182 {reply, Adapter:dump(Conn), State};
183
d729e64 @davidw Added a create_table function for Postgres, with the beginnings of a …
davidw authored
184 handle_call({create_table, TableName, TableDefinition}, _From, State) ->
185 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
186 Conn = State#state.write_connection,
d729e64 @davidw Added a create_table function for Postgres, with the beginnings of a …
davidw authored
187 {reply, Adapter:create_table(Conn, TableName, TableDefinition), State};
188
4aeb83d @davidw Added table_exist and get_migrations_table - the latter fetches the
davidw authored
189 handle_call({table_exists, TableName}, _From, State) ->
190 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
191 Conn = State#state.read_connection,
4aeb83d @davidw Added table_exist and get_migrations_table - the latter fetches the
davidw authored
192 {reply, Adapter:table_exists(Conn, TableName), State};
193
d036073 BossDB is now its own project
Evan Miller authored
194 handle_call({execute, Commands}, _From, State) ->
195 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
196 Conn = State#state.write_connection,
d036073 BossDB is now its own project
Evan Miller authored
197 {reply, Adapter:execute(Conn, Commands), State};
198
f50fd5d Parameterized queries for Postgres
Evan Miller authored
199 handle_call({execute, Commands, Params}, _From, State) ->
200 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
201 Conn = State#state.write_connection,
f50fd5d Parameterized queries for Postgres
Evan Miller authored
202 {reply, Adapter:execute(Conn, Commands, Params), State};
203
d036073 BossDB is now its own project
Evan Miller authored
204 handle_call({transaction, TransactionFun}, _From, State) ->
205 Adapter = State#state.adapter,
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
206 Conn = State#state.write_connection,
a678c25 Fix transactions
Evan Miller authored
207 {reply, Adapter:transaction(Conn, TransactionFun), State};
208
209 handle_call(state, _From, State) ->
210 {reply, State, State}.
d036073 BossDB is now its own project
Evan Miller authored
211
c8a070d @zkessin More refactoring
zkessin authored
212
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 handle_cast({try_connect, Options}, State) when State#state.connection_state /= connected ->
215 Adapter = State#state.adapter,
216 CacheEnable = State#state.cache_enable,
217 CacheTTL = State#state.cache_ttl,
218 try connections_for_adapter(Adapter, Options) of
219 {ok, {ReadConn, WriteConn}} ->
220 {Shards, ModelDict} = make_shards(Options, Adapter),
221 {noreply, #state{connection_state = connected, connection_delay = 1,
222 adapter = Adapter, read_connection = ReadConn, write_connection = WriteConn,
223 shards = lists:reverse(Shards), model_dict = ModelDict, options = Options,
224 cache_enable = CacheEnable, cache_ttl = CacheTTL, cache_prefix = db }};
225 _Failure ->
226 reconnect_no_reply(Options, State, Adapter, CacheEnable, CacheTTL)
227 catch
228 _Error ->
229 reconnect_no_reply(Options, State, Adapter, CacheEnable, CacheTTL)
230 end;
231
232 handle_cast(_Request, State) ->
233 {noreply, State}.
234
235
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 terminate(_Reason, State) ->
238 Adapter = State#state.adapter,
239 case State#state.connection_retry_timer of
240 undefined ->
241 noop;
242 Timer ->
243 timer:cancel(Timer)
244 end,
245 terminate_connections(Adapter, State#state.read_connection, State#state.write_connection),
246 lists:map(fun({A, RC, WC}) -> terminate_connections(A, RC, WC) end, State#state.shards).
247
248
249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 code_change(_OldVsn, State, _Extra) ->
251 {ok, State}.
252
253
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 handle_info(stop, State) ->
256 {stop, shutdown, State};
257
bdff76e @choptastic Only handle normal failures for mongodb
choptastic authored
258 handle_info({'EXIT', _From, 'normal'}, State) when State#state.adapter=:=boss_db_adapter_mongodb ->
259 %% Mongo Driver links and kills connection with each request, so capture it here and ignore it
bc0a542 @burbas Do not react to normal exits
burbas authored
260 {noreply, State};
c8a070d @zkessin More refactoring
zkessin authored
261 handle_info({'EXIT', _From, _Reason}, State) when State#state.connection_state == connected ->
262 {ok, Tref} = setup_reconnect(State),
263 {noreply, State#state { connection_state = disconnected, connection_delay = State#state.connection_delay * 2,
264 connection_retry_timer = Tref } };
265
266 handle_info({'EXIT', _From, _Reason}, State) ->
267 {noreply, State#state { connection_state = disconnected } };
268
269 handle_info(_Info, State) ->
270 {noreply, State}.
271
272
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67ac3e1 @zkessin starting to add property based tests
zkessin authored
274 find_by_key(Key, From, Prefix, State, _CachedValue = undefined) ->
c8a070d @zkessin More refactoring
zkessin authored
275 {reply, Res, _} = handle_call({find, Key}, From, State#state{ cache_enable = false }),
67ac3e1 @zkessin starting to add property based tests
zkessin authored
276 IsSuccess = find_is_success(Res),
c8a070d @zkessin More refactoring
zkessin authored
277 case IsSuccess of
278 true ->
279 boss_cache:set(Prefix, Key, Res, State#state.cache_ttl),
280 WatchString = lists:concat([Key, ", ", Key, ".*"]),
281 boss_news:set_watch(Key, WatchString,
282 fun boss_db_cache:handle_record_news/3,
283 {Prefix, Key},
284 State#state.cache_ttl);
67ac3e1 @zkessin starting to add property based tests
zkessin authored
285 false ->
286 lager:error("Find in Cache by key error ~p ~p ", [Key, Res]),
287 error
c8a070d @zkessin More refactoring
zkessin authored
288 end,
289 {reply, Res, State};
67ac3e1 @zkessin starting to add property based tests
zkessin authored
290 find_by_key(Key, _From, _Prefix, State, CachedValue) ->
c8a070d @zkessin More refactoring
zkessin authored
291 boss_news:extend_watch(Key),
292 {reply, CachedValue, State}.
293
294
295
296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67ac3e1 @zkessin starting to add property based tests
zkessin authored
297 -spec(find_is_success(undefined|tuple()) -> boolean()).
298 find_is_success(Res) ->
299 Res =:= undefined orelse is_tuple(Res) andalso element(1, Res) =/= error.
300
301
302
303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5cb6a6c @zkessin first chunk of refactor
zkessin authored
304 find_list(Type, Include, Cmd, From, Prefix, State, Key) ->
305 {reply, Res, _} = handle_call(Cmd, From, State#state{cache_enable = false}),
306 case is_list(Res) of
307 true ->
308 DummyRecord = boss_record_lib:dummy_record(Type),
309 BelongsToTypes = DummyRecord:belongs_to_types(),
310 IncludedRecords = find_list_records(Include, From, State,
311 Res, BelongsToTypes),
312 lists:map(fun(Rec) ->
313 boss_cache:set(Prefix, Rec:id(), Rec, State#state.cache_ttl)
314 end, IncludedRecords),
315 boss_cache:set(Prefix, Key, Res, State#state.cache_ttl),
316 WatchString = lists:concat([inflector:pluralize(atom_to_list(Type)),
317 ", ", Type, "-*.*"]),
318 boss_news:set_watch(Key, WatchString, fun boss_db_cache:handle_collection_news/3,
319 {Prefix, Key}, State#state.cache_ttl);
320 _ -> error % log it here?
321 end,
322 Res.
323
c8a070d @zkessin More refactoring
zkessin authored
324
325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5cb6a6c @zkessin first chunk of refactor
zkessin authored
326 find_list_records(Include, From, State, Res, BelongsToTypes) ->
327 lists:foldl(fun
328 ({RelationshipName, InnerInclude}, Acc) ->
329 RelType = proplists:get_value(RelationshipName, BelongsToTypes),
330 RecordList = lookup_rel_records(From, State, Res,
331 RelationshipName,
332 InnerInclude, RelType),
333 RecordList ++ Acc
334 end, [], lists:map(fun({R, I}) -> {R, I}; (R) -> {R, []} end, Include)).
335
c8a070d @zkessin More refactoring
zkessin authored
336
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67ac3e1 @zkessin starting to add property based tests
zkessin authored
338 lookup_rel_records(_From, _State, _Res, _RelationshipName, _InnerInclude,
5cb6a6c @zkessin first chunk of refactor
zkessin authored
339 undefined) -> [];
340 lookup_rel_records(From, State, Res, RelationshipName, InnerInclude,
341 RelationshipType) ->
342
343 IdList = lists:map(fun(Record) ->
344 Record:get(lists:concat([RelationshipType, "_id"]))
345 end, Res),
346 handle_call({find, RelationshipName,
347 [{'id', 'in', IdList}],
348 all, 0, id, ascending,
349 InnerInclude}, From, State).
350
351
c8a070d @zkessin More refactoring
zkessin authored
352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353 reconnect_no_reply(Options, State, Adapter, CacheEnable, CacheTTL) ->
1f3d6e3 @davidw One more timer reference to handle.
davidw authored
354 {ok, Tref} = setup_reconnect(State),
c8a070d @zkessin More refactoring
zkessin authored
355 {noreply, #state{connection_state = disconnected, connection_delay = State#state.connection_delay * 2,
356 connection_retry_timer = Tref,
357 adapter = Adapter, read_connection = undefined, write_connection = undefined,
358 options = Options, cache_enable = CacheEnable, cache_ttl = CacheTTL, cache_prefix = db}}.
359
360
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 make_shards(Options, Adapter) ->
363 lists:foldr(fun(ShardOptions, {ShardAcc, ModelDictAcc}) ->
364 case proplists:get_value(db_shard_models, ShardOptions, []) of
365 [] ->
366 {ShardAcc, ModelDictAcc};
367 Models ->
368 ShardAdapter = make_shard_adapter(Adapter, ShardOptions),
369 MergedOptions = make_merged_options(Options, ShardOptions),
370 {ok, {ShardRead, ShardWrite}} = connections_for_adapter(ShardAdapter, MergedOptions),
371 Index = erlang:length(ShardAcc),
372 NewDict = make_new_dict(ModelDictAcc, Models, Index),
373 {[{ShardAdapter, ShardRead, ShardWrite}|ShardAcc], NewDict}
374 end
375 end, {[], dict:new()}, proplists:get_value(shards, Options, [])).
376
377
378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 make_new_dict(ModelDictAcc, Models, Index) ->
380 lists:foldr(fun(ModelAtom, Dict) ->
381 dict:store(ModelAtom, Index, Dict)
382 end, ModelDictAcc, Models).
383
384
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 make_merged_options(Options, ShardOptions) ->
387 case proplists:get_value(db_replication_set, ShardOptions) of
388 undefined -> ShardOptions ++ proplists:delete(db_replication_set, Options);
389 _ -> ShardOptions ++ Options
390 end.
ce2dbe9 @davidw Exponential backoff strategy with retries for database connection.
davidw authored
391
392
c8a070d @zkessin More refactoring
zkessin authored
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 make_shard_adapter(Adapter, ShardOptions) ->
395 case proplists:get_value(db_adapter, ShardOptions) of
396 undefined -> Adapter;
397 ShortName -> list_to_atom(lists:concat(["boss_db_adapter_", ShortName]))
398 end.
d036073 BossDB is now its own project
Evan Miller authored
399
c8a070d @zkessin More refactoring
zkessin authored
400
401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
402 db_for_counter(_Counter, State) ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
403 {State#state.adapter, State#state.read_connection, State#state.write_connection}.
d036073 BossDB is now its own project
Evan Miller authored
404
c8a070d @zkessin More refactoring
zkessin authored
405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
406 db_for_record(Record, State) ->
407 db_for_type(element(1, Record), State).
408
c8a070d @zkessin More refactoring
zkessin authored
409
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
411 db_for_key(Key, State) ->
412 db_for_type(infer_type_from_id(Key), State).
413
c8a070d @zkessin More refactoring
zkessin authored
414
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416 db_for_type(Type, State = #state{model_dict = Dict}) ->
417 case dict:find(Type, Dict) of
d036073 BossDB is now its own project
Evan Miller authored
418 {ok, Index} ->
419 lists:nth(Index + 1, State#state.shards);
420 _ ->
5df9f61 @evanmiller Support db_write_host and friends
evanmiller authored
421 {State#state.adapter, State#state.read_connection, State#state.write_connection}
d036073 BossDB is now its own project
Evan Miller authored
422 end.
423
c8a070d @zkessin More refactoring
zkessin authored
424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d036073 BossDB is now its own project
Evan Miller authored
425 infer_type_from_id(Id) when is_binary(Id) ->
426 infer_type_from_id(binary_to_list(Id));
427 infer_type_from_id(Id) when is_list(Id) ->
428 list_to_atom(hd(string:tokens(Id, "-"))).
Something went wrong with that request. Please try again.