summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornsensfel <SpamShield0@noot-noot.org>2018-12-12 17:36:34 +0100
committernsensfel <SpamShield0@noot-noot.org>2018-12-12 17:36:34 +0100
commit6b2fd0aae5067469598fa404f9163ab2ac87f69e (patch)
treecf8afc29feb913201246abd86a4a52aca0702722 /src
parent7ff80825a16b91ef2c0374776f0d140068153d0b (diff)
Moving more files from TO server's DB system.
Diffstat (limited to 'src')
-rw-r--r--src/ataxia_id_manager.erl207
-rw-r--r--src/ataxia_server.erl136
-rw-r--r--src/ataxic.erl59
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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%