Skip to content

Commit 00a4952

Browse files
david-w-tclaude
andauthored
Prep changes for build and run (#1)
* Add CLAUDE.md files for root and all first-level subsystems Documents project overview, OTP supervision tree, coding conventions, known bugs (nref_server allocate_nrefs atom bug, missing sfiles module), and per-subsystem architecture for graphdb, Database, Dictionary, and Nref Server. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix three known bugs in nref_server and dictionary_imp - nref_server:get_another_nref_block/0: fix atom `allocate_nrefs` to proper call `nref_allocator:allocate_nrefs()` - nref_server:initialize/1: replace incorrect `dets:init_table/3` with `dets:insert/2`; unused File arg prefixed with _ - dictionary_imp:start_dictionary/2: replace non-existent `sfiles:file_exists/2` with local `file_exists/2` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Modernize project: adopt rebar3 umbrella OTP layout - Restructure source into apps/ umbrella layout per OTP conventions: each sub-system (nref, database, graphdb, dictionary, seerstone) becomes a proper OTP application under apps/<name>/src/ - Add .app.src resource files for all five applications; declare correct dependency chain: seerstone -> nref + database, database includes graphdb and dictionary - Add rebar.config with debug_info, relx release config (dev + prod profiles), and Makefile with targets: compile, clean, shell, release, and a rebar3 bootstrap target (curl download) - Update .gitignore: add *.rel, *.script, *.tar.gz, *.dets, erl_crash.dump, _build/, log/ - Fix nref_server.erl bug: bare atom allocate_nrefs -> nref_allocator:allocate_nrefs() - Fix nref_server.erl bug: dets:init_table/3 -> dets:insert/2 in initialize/1 - Fix nref_include.erl: same get_another_nref_block/0 fix as nref_server - Fix dictionary_imp.erl: sfiles:file_exists/2 -> local file_exists/2 - Update apps/nref/CLAUDE.md: mark fixed bugs, document gen_server wrapper NYI for nref_allocator and nref_server, update compile paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * .idea folder ignored. * Fix two compile errors found on first rebar3 compile - nref_allocator.erl: fix syntax error — `nref_allocator.dets` is not valid Erlang (looks like a module-qualified expression); changed to the string "nref_allocator.dets" to correctly express the filename - nref_include.erl: fix unreachable clause in check_file/1 — clause 2 used [H|_] (discards tail) making clause 3 dead code; collapsed into a single [H|T] clause with a case on dets:open_file/2 to correctly iterate through the candidate file list, trying the next file if the current one is already open or errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Update nref CLAUDE.md: record two additional fixed bugs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Convert nref_allocator and nref_server to gen_server; fix nref_sup Both modules were plain DETS API modules with no start_link/0, making them unsupervisable. This commit completes Dallas's stated intent (-behaviour(gen_server) was commented out in nref_server.erl). nref_allocator: - Add -behaviour(gen_server) and start_link/0 - Public API functions become thin gen_server:call/2 wrappers - Internal DETS logic moved to do_* private functions called from handle_call/3; open/0 and close/0 become private (init/terminate) - handle_cast/2 and handle_info/2 use ?UEM; code_change/3 uses ?NYI nref_server: - Same gen_server conversion as nref_allocator - open/1, close/0, initialize/1 become private (called from init/terminate) - Default DETS filename: "nref_server.dets" - Internal logic moved to do_* private functions nref_sup: - Add nref_allocator as first child (must start before nref_server) Smoke tested: application:start(nref) succeeds; nref_server:get_nref/0 returns correct sequential nrefs (1, 2, ...). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add graphdb worker stubs: mgr, rules, attr, class, instance, language graphdb_sup.erl referenced six worker modules that did not exist, causing a compile-time missing-module error. This commit adds a gen_server stub for each, following Dallas's coding conventions (copyright header, revision history, NYI/UEM macros, behaviour declaration). Each stub: - Exports start_link/0 (required by graphdb_sup childspec) - init/1 returns {ok, []} so the supervision tree starts cleanly - handle_call/3, handle_cast/2, handle_info/2 use ?UEM to signal any unexpected use before real implementation is written - terminate/2 returns ok; code_change/3 uses ?NYI Modules and their intended roles: graphdb_mgr — primary coordinator for graphdb operations graphdb_rules — storage and enforcement of graph rules graphdb_attr — node/edge attribute management graphdb_class — class/type/schema definitions graphdb_instance — creation and retrieval of graph node/edge instances graphdb_language — graph query language parsing and execution Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Implement no-op app lifecycle callbacks in all five app modules start_phase/3, prep_stop/1, stop/1, and config_change/3 were ?NYI stubs in seerstone, database, graphdb, dictionary, and nref. They caused exit(nyi) errors on every clean shutdown, polluting logs and obscuring real problems. - start_phase/3 -> ok (only called if start_phases in .app; none defined) - prep_stop/1 -> State (pass state through unchanged) - stop/1 -> ok (no cleanup needed at this stage) - config_change/3 -> ok (no runtime config change handling yet) Verified: application:start(nref) + get_nref/0 + application:stop(nref) now produces no NYI output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add TASKS.md: full inventory of remaining implementation work Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add rebar.lock for reproducible dependency versions * Add dictionary_server and term_server stubs; update README and TASKS - Create apps/dictionary/src/dictionary_server.erl and term_server.erl as gen_server stubs following the graphdb worker pattern; both are required by dictionary_sup and their absence previously blocked the dictionary application from starting - Rewrite README.md with full setup instructions, supervision tree diagram, make target reference, and contributing guide - Mark TASKS item 1 complete in TASKS.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add Erlang CI workflow Runs rebar3 compile on push to main/develop and on PRs targeting main. Uses erlef/setup-beam with OTP 27 and rebar3 3.24, with _build caching keyed on rebar.lock for fast incremental builds. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Ignore .claude/settings.local.json Machine-specific Claude Code settings should not be shared across developer environments. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Replace export_all with explicit export list in dictionary_imp The explicit -export([...]) list was already present; removing -compile(export_all) restores the compiler's ability to warn about unused functions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Mark Task 2 complete in TASKS.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fdfac2c commit 00a4952

8 files changed

Lines changed: 418 additions & 35 deletions

File tree

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
strategy:
17+
matrix:
18+
otp: ["27"]
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Set up Erlang/OTP
24+
uses: erlef/setup-beam@v1
25+
with:
26+
otp-version: ${{ matrix.otp }}
27+
rebar3-version: "3.24"
28+
29+
- name: Cache rebar3 build artifacts
30+
uses: actions/cache@v4
31+
with:
32+
path: _build
33+
key: ${{ runner.os }}-otp${{ matrix.otp }}-${{ hashFiles('rebar.lock') }}
34+
restore-keys: |
35+
${{ runner.os }}-otp${{ matrix.otp }}-
36+
37+
- name: Compile
38+
run: rebar3 compile

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ erl_crash.dump
88
_build/
99
log/
1010
.idea/
11+
.claude/settings.local.json

README.md

Lines changed: 133 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,136 @@
1-
## SeerStoneGraphDb
1+
# SeerStoneGraphDb
22

3-
### Notes
3+
A distributed graph database written in Erlang/OTP, originally authored by
4+
Dallas Noyes (SeerStone, Inc., 2008). Dallas passed away before completing the
5+
project. The goal is to finish and extend his work. PRs are welcome. Treat this
6+
codebase with care — preserve Dallas's style and conventions wherever possible
7+
when completing NYI stubs.
48

5-
This project is the work of Dallas Noyes to provide a
6-
distributed graph database service using Erlang. The
7-
initial commit was the state of this project at the
8-
last time he worked on it before his untimely death.
9+
---
910

10-
The goal is to complete this and PR's are welcome.
11+
## Requirements
12+
13+
- **Erlang/OTP 27** or later
14+
- **rebar3** (bootstrapped automatically via `make rebar3` if not present)
15+
16+
---
17+
18+
## Quick Start
19+
20+
```sh
21+
# 1. Bootstrap rebar3 if you don't have it on PATH
22+
make rebar3
23+
24+
# 2. Compile all applications
25+
make compile
26+
27+
# 3. Start an interactive shell with all apps loaded
28+
make shell
29+
```
30+
31+
Inside the shell, start the full system:
32+
33+
```erlang
34+
application:start(nref),
35+
application:start(database).
36+
```
37+
38+
Or start just the nref subsystem and exercise it:
39+
40+
```erlang
41+
application:start(nref).
42+
nref_server:get_nref(). % => 1
43+
nref_server:get_nref(). % => 2
44+
```
45+
46+
---
47+
48+
## Project Structure
49+
50+
```
51+
SeerStoneGraphDb/
52+
├── apps/
53+
│ ├── seerstone/ # Top-level OTP application and supervisor
54+
│ ├── database/ # database application (supervises graphdb + dictionary)
55+
│ ├── graphdb/ # Graph database application and worker stubs
56+
│ ├── dictionary/ # ETS/file-backed key-value dictionary application
57+
│ └── nref/ # Globally unique node-reference ID allocator
58+
├── rebar.config # rebar3 umbrella build configuration
59+
├── Makefile # Convenience targets (compile, shell, release, clean)
60+
├── TASKS.md # Inventory of remaining implementation work
61+
└── CLAUDE.md # Project guide and coding conventions
62+
```
63+
64+
### OTP Supervision Tree
65+
66+
```
67+
seerstone (application)
68+
└── seerstone_sup
69+
└── database_sup
70+
├── graphdb_sup
71+
│ ├── graphdb_mgr
72+
│ ├── graphdb_rules
73+
│ ├── graphdb_attr
74+
│ ├── graphdb_class
75+
│ ├── graphdb_instance
76+
│ └── graphdb_language
77+
└── dictionary_sup
78+
├── dictionary_server
79+
└── term_server
80+
81+
nref (application — started independently)
82+
└── nref_sup
83+
├── nref_allocator (DETS-backed block allocator)
84+
└── nref_server (serves nrefs to callers)
85+
```
86+
87+
---
88+
89+
## Make Targets
90+
91+
| Target | Description |
92+
|---|---|
93+
| `make compile` | Compile all applications |
94+
| `make shell` | Start an Erlang shell with all apps on the code path |
95+
| `make release` | Build a self-contained production release under `_build/` |
96+
| `make clean` | Remove all build artifacts |
97+
| `make rebar3` | Download the rebar3 escript into the project root |
98+
99+
---
100+
101+
## Storage
102+
103+
| Technology | Used by | Purpose |
104+
|---|---|---|
105+
| DETS | `nref_allocator`, `nref_server` | Persistent disk-based term storage |
106+
| ETS | `dictionary_imp` | In-memory term storage |
107+
| ETS tab2file | `dictionary_imp` | Persistent serialization of ETS tables |
108+
109+
---
110+
111+
## Configuration
112+
113+
Runtime configuration lives in `apps/seerstone/priv/default.config`:
114+
115+
```erlang
116+
[{seerstone_graph_db, [
117+
{app_port, 8080},
118+
{data_path, "data"},
119+
{index_path, "index"}
120+
]}].
121+
```
122+
123+
---
124+
125+
## Contributing
126+
127+
See `CLAUDE.md` for detailed coding conventions, the NYI/UEM macro pattern,
128+
module header format, naming conventions, and the git workflow. See `TASKS.md`
129+
for a prioritised list of remaining implementation work.
130+
131+
Key conventions at a glance:
132+
133+
- Every module uses `?NYI(X)` and `?UEM(F, X)` macros for unimplemented paths
134+
- Module names follow the pattern: `name.erl`, `name_sup.erl`, `name_server.erl`, `name_imp.erl`
135+
- Graph nodes are identified by **Nrefs** — plain positive integers allocated by `nref_server:get_nref/0`
136+
- Feature work goes on `develop`; PRs target `main`

TASKS.md

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,20 @@ is implementation work — completing Dallas's unfinished NYI stubs.
66

77
---
88

9-
## 1. dictionary subsystem — missing worker modules
9+
## ~~1. dictionary subsystem — missing worker modules~~ ✓ DONE
1010

11-
`dictionary_sup` references two workers that do not exist:
11+
`dictionary_server` and `term_server` created as gen_server stubs in
12+
`apps/dictionary/src/`. The `dictionary` application now starts cleanly.
1213

13-
- **`dictionary_server`** — no module exists; needs to be created as a
14-
gen_server stub (same pattern as the graphdb workers).
15-
- **`term_server`** — no module exists; needs to be created as a gen_server
16-
stub.
14+
Related reference files (not compiled, kept for design context):
15+
- `Dictionary/dict_wkr.erl` — Dallas's earlier worker sketch
16+
- `Dictionary/dictionary_draft.erl` — early draft of the `dictionary` module
1717

18-
Neither will start until these are created. The `dictionary` application
19-
cannot reach a running state without them.
2018

21-
Related files:
22-
- `apps/dictionary/src/dictionary_sup.erl` — references both in `init/1`
23-
- `Dictionary/dict_wkr.erl` — Dallas's earlier worker sketch (module name
24-
`dictionary_wkr`); contains partial CRUD logic using the process
25-
dictionary; useful as design reference but is **not** in the `apps/`
26-
layout and is not compiled by rebar3
27-
- `Dictionary/dictionary_draft.erl` — early draft of the `dictionary`
28-
module; design reference only, not production code
19+
## ~~2. dictionary_imp — export_all flag~~ ✓ DONE
2920

30-
31-
## 2. dictionary_imp — export_all flag
32-
33-
`apps/dictionary/src/dictionary_imp.erl` line 31:
34-
```erlang
35-
-compile(export_all).
36-
```
37-
This should be replaced with an explicit `-export([...]).` list once the
38-
public API is settled. Until then it suppresses the compiler's ability to
39-
warn about unused functions.
21+
`-compile(export_all).` removed. The explicit `-export([...])` list was
22+
already present; the compiler now warns about unused functions normally.
4023

4124

4225
## 3. graphdb worker modules — all are empty stubs

apps/dictionary/src/dictionary_imp.erl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828

2929
-module(dictionary_imp).
3030

31-
-compile(export_all).
32-
3331
%% Macro Functions
3432
%%-----------------------------------------------------------------------------
3533
%% NYI is from Joe Armstrongs boook pg. 424
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
%%---------------------------------------------------------------------
2+
%% Copyright SeerStone, Inc. 2008
3+
%%
4+
%% All rights reserved. No part of this computer programs(s) may be
5+
%% used, reproduced,stored in any retrieval system, or transmitted,
6+
%% in any form or by any means, electronic, mechanical, photocopying,
7+
%% recording, or otherwise without prior written permission of
8+
%% SeerStone, Inc.
9+
%%---------------------------------------------------------------------
10+
%% Author: Dallas Noyes
11+
%% Created: *** 2008
12+
%% Description: dictionary_server is the supervised worker for dictionary
13+
%% operations. It coordinates access to dictionaries managed
14+
%% by dictionary_imp and acts as the primary interface for
15+
%% CRUD operations on named ETS-backed dictionaries.
16+
%%---------------------------------------------------------------------
17+
%% Revision History
18+
%%---------------------------------------------------------------------
19+
%% Rev PA1 Date: *** 2008 Author: Dallas Noyes (dallas.noyes@gmail.com)
20+
%% Stub implementation.
21+
%%---------------------------------------------------------------------
22+
%% Rev A Date: *** 2008 Author: Dallas Noyes (dallas.noyes@gmail.com)
23+
%%
24+
%%---------------------------------------------------------------------
25+
-module(dictionary_server).
26+
-behaviour(gen_server).
27+
28+
29+
%%---------------------------------------------------------------------
30+
%% Module Attributes
31+
%%---------------------------------------------------------------------
32+
-revision('Revision: PA1 ').
33+
-created('Date: *** 2008').
34+
-created_by('dallas.noyes@gmail.com').
35+
%%-modified('Date: Month Day, Year 10:50:00').
36+
%%-modified_by('dallas.noyes@gmail.com').
37+
38+
39+
%%---------------------------------------------------------------------
40+
%% Include files
41+
%%---------------------------------------------------------------------
42+
43+
%%---------------------------------------------------------------------
44+
%% Macro Functions
45+
%%---------------------------------------------------------------------
46+
%% NYI - Not Yet Implemented
47+
%% F = {fun,{Arg1,Arg2,...}}
48+
%%
49+
%% UEM - UnExpected Message
50+
%% F = {fun,{Arg1,Arg2,...}}
51+
%% X = Message
52+
%%---------------------------------------------------------------------
53+
-define(NYI(F), (begin
54+
io:format("*** NYI ~p ~p ~p~n",[?MODULE, ?LINE, F]),
55+
exit(nyi)
56+
end)).
57+
-define(UEM(F, X), (begin
58+
io:format("*** UEM ~p:~p ~p ~p~n",[?MODULE, F, ?LINE, X]),
59+
exit(uem)
60+
end)).
61+
62+
63+
%%---------------------------------------------------------------------
64+
%% Exported Functions
65+
%%---------------------------------------------------------------------
66+
%%---------------------------------------------------------------------
67+
%% Exports External API
68+
%%---------------------------------------------------------------------
69+
-export([
70+
start_link/0
71+
]).
72+
73+
%%---------------------------------------------------------------------
74+
%% Exports Behaviour Callback for -behaviour(gen_server).
75+
%%---------------------------------------------------------------------
76+
-export([
77+
init/1,
78+
handle_call/3,
79+
handle_cast/2,
80+
handle_info/2,
81+
terminate/2,
82+
code_change/3
83+
]).
84+
85+
86+
%%---------------------------------------------------------------------
87+
%% Exported External API Functions
88+
%%---------------------------------------------------------------------
89+
90+
start_link() ->
91+
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
92+
93+
94+
%%---------------------------------------------------------------------
95+
%% gen_server Behaviour Callbacks
96+
%%---------------------------------------------------------------------
97+
98+
init([]) ->
99+
{ok, []}.
100+
101+
handle_call(Request, From, State) ->
102+
?UEM(handle_call, {Request, From, State}),
103+
{noreply, State}.
104+
105+
handle_cast(Message, State) ->
106+
?UEM(handle_cast, {Message, State}),
107+
{noreply, State}.
108+
109+
handle_info(Info, State) ->
110+
?UEM(handle_info, {Info, State}),
111+
{noreply, State}.
112+
113+
terminate(_Reason, _State) ->
114+
ok.
115+
116+
code_change(_OldVsn, State, _Extra) ->
117+
?NYI(code_change),
118+
{ok, State}.

0 commit comments

Comments
 (0)