| summaryrefslogtreecommitdiff |
diff options
| author | nsensfel <SpamShield0@noot-noot.org> | 2018-12-12 17:36:34 +0100 |
|---|---|---|
| committer | nsensfel <SpamShield0@noot-noot.org> | 2018-12-12 17:36:34 +0100 |
| commit | 6b2fd0aae5067469598fa404f9163ab2ac87f69e (patch) | |
| tree | cf8afc29feb913201246abd86a4a52aca0702722 | |
| parent | 7ff80825a16b91ef2c0374776f0d140068153d0b (diff) | |
Moving more files from TO server's DB system.
| -rw-r--r-- | src/ataxia_id_manager.erl | 207 | ||||
| -rw-r--r-- | src/ataxia_server.erl | 136 | ||||
| -rw-r--r-- | src/ataxic.erl | 59 |
3 files changed, 402 insertions, 0 deletions
diff --git a/src/ataxia_id_manager.erl b/src/ataxia_id_manager.erl new file mode 100644 index 0000000..9df15d6 --- /dev/null +++ b/src/ataxia_id_manager.erl @@ -0,0 +1,207 @@ +-module(ataxia_id_manager). +-behavior(gen_server). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( + entry, + { + last_id :: binary(), + freed_ids :: list(binary()) + } +). + +-type entry() :: #entry{}. + +%% FIXME: IDs should be generated in a decentralized fashion. +%% TODO: How to handle IDs management with the redundancy DBs? + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% 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 +( + [ + allocate/1, + free/2, + start/0 + ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec next_char (integer()) -> integer(). +next_char ($9) -> $a; +next_char ($z) -> $A; +next_char ($Z) -> $0; +next_char (C) -> (C + 1). + +-spec next_id_internal + ( + list(integer()), + boolean(), + list(integer()) + ) + -> list(integer()). +next_id_internal ([], true, Result) -> [$0|Result]; +next_id_internal ([], false, Result) -> Result; +next_id_internal ([$Z|Next], true, Result) -> + next_id_internal(Next, true, [$0|Result]); +next_id_internal ([Char|Next], true, Result) -> + next_id_internal(Next, false, [next_char(Char)|Result]); +next_id_internal ([Char|Next], false, Result) -> + next_id_internal(Next, false, [Char|Result]). + +-spec next_id (binary()) -> binary(). +next_id (ID) -> + list_to_binary + ( + next_id_internal + ( + lists:reverse(binary:bin_to_list(ID)), + true, + [] + ) + ). + +-spec new_entry () -> entry(). +new_entry () -> + #entry + { + last_id = <<"">>, + freed_ids = [] + }. + +-spec allocate_id_in_entry (entry()) -> {entry(), binary()}. +allocate_id_in_entry (Entry) -> + case Entry#entry.freed_ids of + [] -> + NewID = next_id(Entry#entry.last_id), + { + Entry#entry{ last_id = NewID }, + NewID + }; + + [OldID|OtherOldIDs] -> + { + Entry#entry{ freed_ids = OtherOldIDs }, + OldID + } + end. + +-spec allocate_id + ( + atom(), + dict:dict(atom(), entry()) + ) + -> {dict:dict(atom(), entry()), binary()}. +allocate_id (DB, State) -> + S0Entry = + case dict:find(DB, State) of + {ok, Value} -> Value; + error -> new_entry() + end, + + {S1Entry, NewID} = allocate_id_in_entry(S0Entry), + + S0State = dict:store(DB, S1Entry, State), + + {S0State, NewID}. + +-spec free_id + ( + binary(), + atom(), + dict:dict(atom(), entry()) + ) + -> dict:dict(atom(), entry()). +free_id (ID, DB, State) -> + Entry = + case dict:find(DB, State) of + {ok, Value} -> Value; + error -> new_entry() + end, + + EntryFreedIDs = Entry#entry.freed_ids, + + case lists:member(ID, EntryFreedIDs) of + true -> State; + false -> + Result = + dict:store + ( + DB, + Entry#entry{ freed_ids = [ID|EntryFreedIDs] }, + State + ), + + Result + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' functions +init (_) -> {ok, dict:new()}. + +handle_call ({allocate, DB}, _, State) -> + {NewState, NewID} = allocate_id(DB, State), + {reply, {allocated_id, NewID}, NewState}; +handle_call ({free, ID, DB}, _, State) -> + {noreply, free_id(ID, DB, State)}. + +handle_cast ({allocate, _DB}, State) -> + {noreply, State}; +handle_cast ({free, ID, DB}, State) -> + {noreply, free_id(ID, DB, State)}. + +terminate (_, _) -> ok. + +code_change (_, State, _) -> + {ok, State}. + +format_status (_, [_, State]) -> + [{data, [{"State", State}]}]. + +handle_info(_, State) -> + {noreply, State}. + +%%%% Interface Functions +-spec allocate (atom()) -> binary(). +allocate (DB) -> + {allocated_id, Result} = + gen_server:call({global, ataxia_id_manager}, {allocate, DB}), + + io:format("~n[DB: ~p] Item ID ~p allocated.~n", [DB, Result]), + + Result. + +-spec free (binary(), atom()) -> 'ok'. +free (ID, DB) -> + gen_server:cast({global, ataxia_id_manager}, {free, ID, DB}), + + ok. + +-spec start () -> 'ok'. +start () -> + {ok, _} = gen_server:start({global, ataxia_id_manager}, ?MODULE, none, []), + + ok. diff --git a/src/ataxia_server.erl b/src/ataxia_server.erl new file mode 100644 index 0000000..206a6d9 --- /dev/null +++ b/src/ataxia_server.erl @@ -0,0 +1,136 @@ +-module(ataxia_server). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( + [ + read/4, + remove/3, + reserve/3, + insert_at/5, + insert/4, + query/1 + ] +). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-spec query_transaction (shr_db_query:type()) -> 'ok'. +query_transaction (Query) -> + DB = shr_db_query:get_database(Query), + ID = shr_db_query:get_entry_id(Query), + [Item] = mnesia:read(DB, ID), + {ok, UpdatedItem} = shr_db_query:apply_to(Query, Item), + + mnesia:write(DB, UpdatedItem, sticky_write), + + ok. + +-spec add_new_item (atom(), ataxia_entry:type()) -> 'ok'. +add_new_item (DB, Item) -> + ID = ataxia_entry:get_id(Item), + [] = mnesia:read(DB, ID), + + mnesia:write(DB, Item, sticky_write), + + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec read + ( + atom(), + ataxic:type(), + binary(), + ataxia_security:user() + ) + -> ({'aborted', any()} | {'ok', any()} | 'not_found'). +read (ID, Selector, User, DB) -> + case mnesia:transaction(fun mnesia:read/2, [DB, ID]) of + {'atomic', []} -> 'not_found'; + {'atomic', [Item]} -> + true = + ataxia_security:can_access + ( + User, + ataxia_entry:get_read_permission(Item) + ), + {ok, ataxic:apply_to(Selector, ataxia_entry:get_value(Item))}; + + Other -> {'aborted', Other} + end. + +-spec insert_at + ( + atom(), + binary(), + ataxia_security:permission(), + ataxia_security:permission(), + any()) + -> ({'aborted', any()} | 'ok'). +insert_at (DB, ID, ReadPerm, WritePerm, Value) -> + Item = ataxia_entry:new(ID, ReadPerm, WritePerm, Value), + case mnesia:transaction(fun add_new_item/2, [DB, Item]) of + {'atomic', 'ok'} -> 'ok'; + {aborted, Val} -> {aborted, Val} + end. + +-spec insert + ( + atom(), + ataxia_security:permission(), + ataxia_security:permission(), + any()) + -> ({'aborted', any()} | {'ok', binary()}). +insert (DB, ReadPerm, WritePerm, Value) -> + ID = db_item_ids_manager:allocate(DB), + case insert_at(DB, ID, ReadPerm, WritePerm, Value) of + {'atomic', 'ok'} -> {'ok', ID}; + {aborted, Val} -> {aborted, Val} + end. + +-spec query (shr_db_query:type()) -> ({'aborted', any()} | {'atomic', 'ok'}). +query (Query) -> + mnesia:transaction(fun query_transaction/1, [Query]). + +-spec reserve + ( + atom(), + binary(), + ataxia_security:user() + ) + -> ({'aborted', any()} | {'atomic', 'ok'}). +reserve (DB, ID, Cred) -> + insert_at + ( + DB, + ID, + [Cred], + [Cred], + { + reserved, + <<"?">> %% TODO [FUNCTION: db][LOW]: timestamp + } + ). + +-spec remove + ( + atom(), + binary(), + ataxia_security:user() + ) + -> ({'aborted', any()} | 'ok' | 'not_found'). +remove (_DB, _ID, _Cred) -> + %% TODO [FUNCTION: db][MEDIUM]: unimplemented + %% Don't forget to checkt that Cred has write access before removing the + %% value. + {'aborted', 'unimplemented'}. diff --git a/src/ataxic.erl b/src/ataxic.erl new file mode 100644 index 0000000..11da6e6 --- /dev/null +++ b/src/ataxic.erl @@ -0,0 +1,59 @@ +-module(ataxic). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%% UPDATE OP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%% Select +-record(field, {ix :: non_neg_integer(), op :: type()}). +-record(array_cell, {ix :: non_neg_integer(), op :: type()}). + +%%%% Sequence of instructions +-record(seq, {ops :: list(type())}). + +%%%% List +-record(list_append, {values :: list(any()), head :: boolean()}). + +%%%% CALC OP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record(const, {value :: any()}). +-record(current, {}). + +%%%% TEST OP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%% Number Comparison +-record(gt, {p0 :: type(), p1 :: type()}). +-record(ge, {p0 :: type(), p1 :: type()}). +-record(lt, {p0 :: type(), p1 :: type()}). +-record(le, {p0 :: type(), p1 :: type()}). +-record(eq, {p0 :: type(), p1 :: type()}). + +%%%% Bool Operations +-record(land, {params :: list(type())}). +-record(lor, {params :: list(type())}). +-record(neg, {param :: type()}). + +%-type type() :: ... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0]). + +-export +( + [ + % ... + ] +). + +-export([apply_to/2]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |


