| summaryrefslogtreecommitdiff | 
diff options
Diffstat (limited to 'src/shared/io')
| -rw-r--r-- | src/shared/io/sh_database.erl | 137 | ||||
| -rw-r--r-- | src/shared/io/sh_timed_cache.erl | 130 | ||||
| -rw-r--r-- | src/shared/io/sh_timed_caches_manager.erl | 152 | 
3 files changed, 419 insertions, 0 deletions
diff --git a/src/shared/io/sh_database.erl b/src/shared/io/sh_database.erl new file mode 100644 index 0000000..a65b784 --- /dev/null +++ b/src/shared/io/sh_database.erl @@ -0,0 +1,137 @@ +-module(sh_database). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      generate_db/0, +      fetch/2, +      commit/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_db_node () -> +   list_to_atom("db_node@" ++ net_adm:localhost()). + +-spec generate_random_characters +   ( +      non_neg_integer(), +      non_neg_integer(), +      non_neg_integer(), +      non_neg_integer(), +      bm_battlemap:type(), +      list(bm_location:type()), +      list(bm_character:type()) +   ) +   -> list(bm_character:type()). +generate_random_characters +( +   0, +   0, +   _CharactersPerPlayer, +   _TotalCharacterCount, +   _Battlemap, +   _ForbiddenLocations, +   Result +) -> +   Result; +generate_random_characters +( +   MaxPlayerID, +   0, +   CharactersPerPlayer, +   TotalCharacterCount, +   Battlemap, +   ForbiddenLocations, +   Result +) -> +   generate_random_characters +   ( +      (MaxPlayerID - 1), +      CharactersPerPlayer, +      CharactersPerPlayer, +      TotalCharacterCount, +      Battlemap, +      ForbiddenLocations, +      Result +   ); +generate_random_characters +( +   MaxPlayerID, +   PlayerCharacterCount, +   CharactersPerPlayer, +   TotalCharacterCount, +   Battlemap, +   ForbiddenLocations, +   Result +) -> +   NewCharacter = +      bm_character:random +      ( +         TotalCharacterCount, +         list_to_binary(integer_to_list(MaxPlayerID)), +         bm_battlemap:get_width(Battlemap), +         bm_battlemap:get_height(Battlemap), +         ForbiddenLocations +      ), +   Character = +      case MaxPlayerID of +         0 -> bm_character:set_is_active(true, NewCharacter); +         _ -> NewCharacter +      end, + +   generate_random_characters +   ( +      MaxPlayerID, +      (PlayerCharacterCount - 1), +      CharactersPerPlayer, +      (TotalCharacterCount + 1), +      Battlemap, +      [bm_character:get_location(Character)|ForbiddenLocations], +      [Character|Result] +   ). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate_db () -> 'ok'. +generate_db () -> +   BattlemapWidth = sh_roll:between(16, 64), +   BattlemapHeight = sh_roll:between(16, 64), +   Battlemap = bm_battlemap:random(0, BattlemapWidth, BattlemapHeight), +   Characters = generate_random_characters(1, 8, 8, 0, Battlemap, [], []), +   PlayersAsList = [bm_player:new(<<"0">>), bm_player:new(<<"1">>)], +   Battle = bm_battle:new(<<"0">>, PlayersAsList, Battlemap, Characters), + +   {atomic, ok} = +      rpc:call +      ( +         get_db_node(), +         storage_access, +         insert, +         [battle_db, <<"0">>, any, Battle] +      ), + +   ok. + +-spec fetch (atom(), any()) -> ({'ok', any()} | 'not_found'). +fetch (DB, ObjectID) -> +   {atomic, Reply} = +      rpc:call(get_db_node(), storage_access, read, [DB, ObjectID]), +   io:format("~ndb_shim:fetch(~p) -> ~p.~n", [{DB, ObjectID}, Reply]), +   Reply. + +-spec commit (db_query:type()) -> 'ok'. +commit (Query) -> +   {atomic, ok} = rpc:call(get_db_node(), storage_access, query, [Query]), +   io:format("~ndb_shim:commit(~p) -> ok.~n", [Query]), +   ok. diff --git a/src/shared/io/sh_timed_cache.erl b/src/shared/io/sh_timed_cache.erl new file mode 100644 index 0000000..1839992 --- /dev/null +++ b/src/shared/io/sh_timed_cache.erl @@ -0,0 +1,130 @@ +-module(sh_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} = sh_gen_server:start(?MODULE, {DB, {Owner, ObjectID}}, []), +   {ok, Data} = sh_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}, sh_timed_caches_manager:get_timeout()}. + +handle_call (invalidate, _, State) -> +   {stop, normal, State}; +handle_call (ping, _, State) -> +   {noreply, State, sh_timed_caches_manager:get_timeout()}. + +handle_cast (invalidate, State) -> +   {stop, normal, State}; +handle_cast (ping, State) -> +   {noreply, State, sh_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}, 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. diff --git a/src/shared/io/sh_timed_caches_manager.erl b/src/shared/io/sh_timed_caches_manager.erl new file mode 100644 index 0000000..7921552 --- /dev/null +++ b/src/shared/io/sh_timed_caches_manager.erl @@ -0,0 +1,152 @@ +-module(sh_timed_caches_manager). +-behavior(gen_server). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' Exports +-export( +   [ +      init/1, +      handle_cast/2, +      handle_call/3, +      terminate/2, +      code_change/3, +      format_status/2, +      handle_info/2 +   ] +). + +%%%% Actual Interface +-export( +   [ +      start/0, +      new_cache/3, +      delete_cache/2, +      get_timeout/0 +   ] +) +. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +remove_cache (DB) -> +   ets:delete(DB). + +add_cache (DB, none) -> +   io:format("~nTimed Caches Manager added a new cache. ~n"), +   ets:new( +      DB, +      [ +         set, +         public, +         named_table, +         {keypos, 1}, +         {read_concurrency, true}, +         {heir, none} +      ] +   ); +add_cache (DB, Heir) -> +   io:format("~nTimed Caches Manager added a new cache. ~n"), +   ets:new( +      DB, +      [ +         set, +         public, +         named_table, +         {keypos, 1}, +         {read_concurrency, true}, +         {heir, Heir, DB} +      ] +   ). + +inherit_cache (CacheList, DB, Heir) -> +   case lists:member(DB, CacheList) of +      true -> +         ets:setopts(DB, {heir, Heir, DB}), +         CacheList; + +      false -> +         [DB|CacheList] +   end. + +remove_cache (CacheList, DB) -> +   case lists:member(DB, CacheList) of +      true -> +         remove_cache(DB), +         lists:delete(DB, CacheList); +      false -> +         CacheList +   end. + +add_cache (CacheList, DB, Heir) -> +   case lists:member(DB, CacheList) of +      true when (Heir =:= none) -> +         CacheList; + +      true -> +         ets:setopts(DB, {heir, Heir, DB}), +         CacheList; + +      false -> +         add_cache(DB, Heir), +         [DB|CacheList] +   end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' functions +init (CacheList) -> +   io:format("~nStarting Timed Caches Manager..."), +   {ok, CacheList}. + +handle_call ({remove, CacheName}, _Caller, State) -> +   {noreply, remove_cache(State, CacheName)}; +handle_call ({add, CacheName, Heir}, _Caller, State)-> +   {noreply, add_cache(State, CacheName, Heir)}; +handle_call ({inherit, CacheName, Heir}, _Caller, State)-> +   {noreply, inherit_cache(State, CacheName, Heir)}; +handle_call (terminate, _, State) -> +   {stop, normal, State}. + +handle_cast ({remove, CacheName}, State) -> +   {noreply, remove_cache(State, CacheName)}; +handle_cast ({add, CacheName, Heir}, State)-> +   {noreply, add_cache(State, CacheName, Heir)}; +handle_cast ({inherit, CacheName, Heir}, State)-> +   {noreply, inherit_cache(State, CacheName, Heir)}; +handle_cast (terminate, State) -> +   {stop, normal, State}. + +terminate (_Reason, []) -> +   ok; +terminate (Reason, [CacheName|OtherCaches]) -> +   remove_cache(CacheName), +   terminate(Reason, OtherCaches). + +code_change (_, State, _) -> +   {ok, State}. + +format_status (_, [_, State]) -> +   [{data, [{"State", State}]}]. + +handle_info(_, State) -> +   {noreply, State}. + +%%%% Interface Functions +start () -> +   gen_server:start(timed_caches_manager, [], []). + +new_cache (ManagerPid, DB, Heir) -> +   gen_server:cast(ManagerPid, {add, DB, Heir}). + +delete_cache (ManagerPid, DB) -> +   gen_server:cast(ManagerPid, {remove, DB}). + +get_timeout () -> +   120000. % 2min.  | 


