Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 9 additions & 19 deletions TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -817,30 +817,20 @@ pass through the category guard (rejecting category nrefs 1–5) and then return

---

### L5. Relationship row IDs allocated from the global `nref_server`
### L5. Relationship row IDs allocated from the global `nref_server` — **RESOLVED** (2026-05-19)

**Evidence:** `graphdb_attr.erl:453-454`, `graphdb_class.erl:416-417,
465-466`, `graphdb_instance.erl:329-332, 421-422`,
`graphdb_bootstrap.erl:388-389`.

The `id` field is the relationship row's primary key, not a
graph-visible reference. Sharing the global nref allocator means
relationship rows consume integers that could otherwise identify nodes.

**Fix:** add a separate `relationship_id_server` (or extend
`nref_allocator` with a second counter). Migrate all `id` allocations
to it.
New `rel_id_server` gen_server added to `apps/graphdb/src/` as first child of
`graphdb_sup`. All 23 `#relationship.id` allocations across 5 files migrated from
`nref_server:get_nref/0` to `rel_id_server:get_id/0`. Bootstrap test assertions
updated (nref floor now `>= 100002`; relationship IDs now start at 1). 4 CT tests added.

---

### Task 7. Wire `dictionary_server` and `term_server` to `dictionary_imp`

**Evidence:** `apps/dictionary/src/dictionary_server.erl` and
`apps/dictionary/src/term_server.erl` are gen_server stubs.
`dictionary_imp` is fully implemented.
### Task 7. Wire `dictionary_server` and `term_server` to `dictionary_imp` — **RESOLVED** (2026-05-19)

**Fix:** delegate from each gen_server to the relevant `dictionary_imp`
functions. Independent of all graphdb work.
Both gen_servers delegate to `dictionary_imp` via `start_dictionary/stop_dictionary`
in `init/terminate` and forward all CRUD calls. Also fixed a pre-existing one-line bug
in `dictionary_imp:delete/2` (wrong ETS key type). 14 CT tests added (7 per server).

---

Expand Down
2 changes: 1 addition & 1 deletion apps/dictionary/src/dictionary_imp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ update(Proc_Name, Key, Value) ->
rpc(fun(From) -> From!{Proc_Name, ets:insert(get("tab"),{list_to_binary(Key),Value})} end, Proc_Name).

delete(Proc_Name, Key) ->
rpc(fun(From) -> From!{Proc_Name,ets:delete(get("tab"),{list_to_binary(Key)})} end, Proc_Name).
rpc(fun(From) -> From!{Proc_Name,ets:delete(get("tab"),list_to_binary(Key))} end, Proc_Name).

all(Proc_Name) ->
rpc(fun(From) -> From!{Proc_Name, ets:tab2list(get("tab"))} end, Proc_Name).
Expand Down
62 changes: 44 additions & 18 deletions apps/dictionary/src/dictionary_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
%% Rev PA1 Date: *** 2008 Author: Dallas Noyes (dallas.noyes@gmail.com)
%% Stub implementation.
%%---------------------------------------------------------------------
%% Rev A Date: *** 2008 Author: Dallas Noyes (dallas.noyes@gmail.com)
%%
%% Rev A Date: 2026-05-19 Author: David W. Thomas
%% Wire to dictionary_imp.
%%---------------------------------------------------------------------
-module(dictionary_server).
-behaviour(gen_server).
Expand All @@ -32,20 +32,9 @@
%%-modified_by('dallas.noyes@gmail.com').


%%---------------------------------------------------------------------
%% Include files
%%---------------------------------------------------------------------

%%---------------------------------------------------------------------
%% Macro Functions
%%---------------------------------------------------------------------
%% NYI - Not Yet Implemented
%% F = {fun,{Arg1,Arg2,...}}
%%
%% UEM - UnExpected Message
%% F = {fun,{Arg1,Arg2,...}}
%% X = Message
%%---------------------------------------------------------------------
-define(NYI(F), (begin
io:format("*** NYI ~p ~p ~p~n",[?MODULE, ?LINE, F]),
exit(nyi)
Expand All @@ -56,14 +45,29 @@
end)).


%%---------------------------------------------------------------------
%% Records
%%---------------------------------------------------------------------
-record(state, {
imp_proc, %% atom() — registered name of the dictionary_imp process
file %% string() — backing ETS file path
}).


%%---------------------------------------------------------------------
%% Exported Functions
%%---------------------------------------------------------------------
%%---------------------------------------------------------------------
%% Exports External API
%%---------------------------------------------------------------------
-export([
start_link/0
start_link/0,
create/1,
read/1,
update/2,
delete/1,
all/0,
size/0
]).

%%---------------------------------------------------------------------
Expand All @@ -86,14 +90,36 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

create(Key) -> gen_server:call(?MODULE, {create, Key}).
read(Key) -> gen_server:call(?MODULE, {read, Key}).
update(Key, Value) -> gen_server:call(?MODULE, {update, Key, Value}).
delete(Key) -> gen_server:call(?MODULE, {delete, Key}).
all() -> gen_server:call(?MODULE, all).
size() -> gen_server:call(?MODULE, size).


%%---------------------------------------------------------------------
%% gen_server Behaviour Callbacks
%%---------------------------------------------------------------------

init([]) ->
{ok, []}.

DataPath = application:get_env(seerstone_graph_db, data_path, "data"),
File = filename:join(DataPath, "dictionary.dat"),
ok = dictionary_imp:start_dictionary(File, dictionary),
{ok, #state{imp_proc = dictionary, file = File}}.

handle_call({create, Key}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:create(P, Key), State};
handle_call({read, Key}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:read(P, Key), State};
handle_call({update, Key, Value}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:update(P, Key, Value), State};
handle_call({delete, Key}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:delete(P, Key), State};
handle_call(all, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:all(P), State};
handle_call(size, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:size(P), State};
handle_call(Request, From, State) ->
?UEM(handle_call, {Request, From, State}),
{noreply, State}.
Expand All @@ -106,8 +132,8 @@ handle_info(Info, State) ->
?UEM(handle_info, {Info, State}),
{noreply, State}.

terminate(_Reason, _State) ->
ok.
terminate(_Reason, #state{imp_proc = P, file = F}) ->
dictionary_imp:stop_dictionary(F, P).

code_change(_OldVsn, State, _Extra) ->
?NYI(code_change),
Expand Down
62 changes: 44 additions & 18 deletions apps/dictionary/src/term_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
%% Rev PA1 Date: *** 2008 Author: Dallas Noyes (dallas.noyes@gmail.com)
%% Stub implementation.
%%---------------------------------------------------------------------
%% Rev A Date: *** 2008 Author: Dallas Noyes (dallas.noyes@gmail.com)
%%
%% Rev A Date: 2026-05-19 Author: David W. Thomas
%% Wire to dictionary_imp.
%%---------------------------------------------------------------------
-module(term_server).
-behaviour(gen_server).
Expand All @@ -32,20 +32,9 @@
%%-modified_by('dallas.noyes@gmail.com').


%%---------------------------------------------------------------------
%% Include files
%%---------------------------------------------------------------------

%%---------------------------------------------------------------------
%% Macro Functions
%%---------------------------------------------------------------------
%% NYI - Not Yet Implemented
%% F = {fun,{Arg1,Arg2,...}}
%%
%% UEM - UnExpected Message
%% F = {fun,{Arg1,Arg2,...}}
%% X = Message
%%---------------------------------------------------------------------
-define(NYI(F), (begin
io:format("*** NYI ~p ~p ~p~n",[?MODULE, ?LINE, F]),
exit(nyi)
Expand All @@ -56,14 +45,29 @@
end)).


%%---------------------------------------------------------------------
%% Records
%%---------------------------------------------------------------------
-record(state, {
imp_proc, %% atom() — registered name of the dictionary_imp process
file %% string() — backing ETS file path
}).


%%---------------------------------------------------------------------
%% Exported Functions
%%---------------------------------------------------------------------
%%---------------------------------------------------------------------
%% Exports External API
%%---------------------------------------------------------------------
-export([
start_link/0
start_link/0,
create/1,
read/1,
update/2,
delete/1,
all/0,
size/0
]).

%%---------------------------------------------------------------------
Expand All @@ -86,14 +90,36 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

create(Key) -> gen_server:call(?MODULE, {create, Key}).
read(Key) -> gen_server:call(?MODULE, {read, Key}).
update(Key, Value) -> gen_server:call(?MODULE, {update, Key, Value}).
delete(Key) -> gen_server:call(?MODULE, {delete, Key}).
all() -> gen_server:call(?MODULE, all).
size() -> gen_server:call(?MODULE, size).


%%---------------------------------------------------------------------
%% gen_server Behaviour Callbacks
%%---------------------------------------------------------------------

init([]) ->
{ok, []}.

DataPath = application:get_env(seerstone_graph_db, data_path, "data"),
File = filename:join(DataPath, "terms.dat"),
ok = dictionary_imp:start_dictionary(File, terms),
{ok, #state{imp_proc = terms, file = File}}.

handle_call({create, Key}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:create(P, Key), State};
handle_call({read, Key}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:read(P, Key), State};
handle_call({update, Key, Value}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:update(P, Key, Value), State};
handle_call({delete, Key}, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:delete(P, Key), State};
handle_call(all, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:all(P), State};
handle_call(size, _From, State = #state{imp_proc = P}) ->
{reply, dictionary_imp:size(P), State};
handle_call(Request, From, State) ->
?UEM(handle_call, {Request, From, State}),
{noreply, State}.
Expand All @@ -106,8 +132,8 @@ handle_info(Info, State) ->
?UEM(handle_info, {Info, State}),
{noreply, State}.

terminate(_Reason, _State) ->
ok.
terminate(_Reason, #state{imp_proc = P, file = F}) ->
dictionary_imp:stop_dictionary(F, P).

code_change(_OldVsn, State, _Extra) ->
?NYI(code_change),
Expand Down
Loading
Loading