summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornsensfel <SpamShield0@noot-noot.org>2018-07-11 18:02:26 +0200
committernsensfel <SpamShield0@noot-noot.org>2018-07-11 18:02:26 +0200
commitacb9dd3220a3edcac93aa11d1d74d008e2fb23ed (patch)
tree98b45af3f7eb9c7d812ed33a07e6a0f665a7a8cd /src/shared/io/shr_timed_cache.erl
parentfde827cba1ff3d889135c74ee1978098465fd200 (diff)
"sh_" -> "shr_".
Diffstat (limited to 'src/shared/io/shr_timed_cache.erl')
-rw-r--r--src/shared/io/shr_timed_cache.erl130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/shared/io/shr_timed_cache.erl b/src/shared/io/shr_timed_cache.erl
new file mode 100644
index 0000000..b89de48
--- /dev/null
+++ b/src/shared/io/shr_timed_cache.erl
@@ -0,0 +1,130 @@
+-module(shr_timed_cache).
+-behavior(gen_server).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% 'gen_server' Exports
+-export
+(
+ [
+ init/1,
+ handle_cast/2,
+ handle_call/3, %% No reply will ever be given.
+ terminate/2,
+ code_change/3,
+ format_status/2,
+ handle_info/2
+ ]
+).
+
+%%%% Actual Interface
+-export
+(
+ [
+ fetch/3,
+ update/4,
+ invalidate/3
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec add_to_cache (atom(), any(), any()) -> any().
+add_to_cache (DB, Owner, ObjectID) ->
+ {ok, TimerPID} = gen_server:start(?MODULE, {DB, {Owner, ObjectID}}, []),
+ {ok, Data} = shr_database:fetch(DB, ObjectID),
+ ets:insert(DB, {{Owner, ObjectID}, TimerPID, Data}),
+ Data.
+
+-spec add_update_to_cache (atom(), any(), any(), any()) -> 'ok'.
+add_update_to_cache (DB, Owner, ObjectID, Data) ->
+ {ok, TimerPID} = gen_server:start(?MODULE, {DB, {Owner, ObjectID}}, []),
+ ets:insert(DB, {{Owner, ObjectID}, TimerPID, Data}),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% 'gen_server' functions
+init ({DB, ObjectID}) ->
+ io:format("~nCache entry added: ~p.~n", [{DB, ObjectID}]),
+ {ok, {DB, ObjectID}, shr_timed_caches_manager:get_timeout()}.
+
+handle_call (invalidate, _, State) ->
+ {stop, normal, State};
+handle_call (ping, _, State) ->
+ {noreply, State, shr_timed_caches_manager:get_timeout()}.
+
+handle_cast (invalidate, State) ->
+ {stop, normal, State};
+handle_cast (ping, State) ->
+ {noreply, State, shr_timed_caches_manager:get_timeout()}.
+
+terminate (_, {DB, ObjectID}) ->
+ io:format
+ (
+ "~nCache entry timed out or was invalidated: ~p.~n",
+ [{DB, ObjectID}]
+ ),
+ ets:delete(DB, ObjectID).
+
+code_change (_, State, _) ->
+ {ok, State}.
+
+format_status (_, [_, State]) ->
+ [{data, [{"State", State}]}].
+
+handle_info(timeout, State) ->
+ {stop, normal, State};
+handle_info(_, {DB, ObjectID}) ->
+ {noreply, {DB, ObjectID}, shr_timed_caches_manager:get_timeout()}.
+
+%%%% Interface Functions
+-spec fetch (atom(), any(), any()) -> any().
+fetch (DB, Owner, ObjectID) ->
+ io:format("~nfetch from cache: ~p.~n", [{DB, {Owner, ObjectID}}]),
+ case ets:lookup(DB, {Owner, ObjectID}) of
+ [] -> add_to_cache(DB, Owner, ObjectID);
+
+ [{_, TimerPID, Data}] ->
+ gen_server:cast(TimerPID, ping),
+ Data
+ end.
+
+-spec update (atom(), any(), any(), any()) -> 'ok'.
+update (DB, Owner, ObjectID, Data) ->
+ io:format("~nUpdating cache: ~p.~n", [{DB, {Owner, ObjectID}}]),
+ case ets:lookup(DB, {Owner, ObjectID}) of
+ [] -> ok;
+
+ [{_OwnerID, TimerPID, _Data}] ->
+ gen_server:stop(TimerPID)
+ end,
+ add_update_to_cache(DB, Owner, ObjectID, Data).
+
+-spec invalidate (atom(), any(), any()) -> 'ok'.
+invalidate (DB, Owner, ObjectID) ->
+ case ets:lookup(DB, {Owner, ObjectID}) of
+ [] ->
+ io:format
+ (
+ "~nInvalidation request on non-stored entry: ~p.~n",
+ [{DB, Owner, ObjectID}]
+ ),
+ ok;
+
+ [{_, TimerPID, _}] ->
+ io:format
+ (
+ "~nInvalidation request on stored entry: ~p.~n",
+ [{DB, Owner, ObjectID}]
+ ),
+ gen_server:stop(TimerPID),
+ ok
+ end.