Store records and the relationship chain
A node record holds a pointer to its first relationship, and each relationship record is a node in a doubly-linked list for both of its endpoints with back-pointers to its start and end nodes — so 'a node's edges' is literally a walkable chain, and fixed-size records turn record-id into a byte offset with no index needed.
Index-free adjacency promised O(1) hops; now we've seen the machinery — fixed-size records addressed by offset, and a doubly-linked chain of relationships hanging off each node. Walking and mutating that chain is cheap. But there's a hidden assumption: that we already KNOW which node to stand on. How did we find Alice in the first place?
Scene 04
Store records and the relationship chain
- Watch
- Try it
- Predict
- Capture
Last scene we said 'the node points to its relationships.' Here's what that actually IS in storage. Alice's node record is one fixed-width box; inside it, a firstRel pointer aims at a relationship record. Follow the path: read firstRel, land on record 100, then follow that record's endNode back-pointer to Bob. That's ONE hop — three pointer follows, no index touched. The relationship records to the right are joined by prev/next links: a chain you can walk.
Highlighted lines are the ones running in the diagram right now.
def fetch(record_id):# every relationship record is REL_SIZE bytes wideoffset = record_id * REL_SIZE # id IS the addressreturn store_file.read_at(offset, REL_SIZE)
def one_hop(node):rid = node.first_rel # 1) read the firstRel pointerrel = fetch(rid) # 2) land on the relationship recordother = rel.end_node # 3) follow the back-pointerreturn other # no index touched on any step
def prepend(node, new_rel):old_head = node.first_relnew_rel.next = old_headnew_rel.prev = Noneif old_head: old_head.prev = new_relnode.first_rel = new_rel # re-point the node record
Where this sits in Build a graph database (Neo4j / Dgraph-style)
Scene 04 of 16, in the The store act — Store records, index-free adjacency, the CSR trade.. Fixed-size store records (node ~15 B, relationship ~34 B) mean record-id × size = byte offset with no index, and each relationship sits in a doubly-linked list for BOTH its endpoints — so a node's edges are a chain you can walk, insert into, and delete from in place.
Up next. Everything so far assumed we were already standing on Alice. But 'start from the user named Alice' is a lookup by VALUE, and pointer-chasing can't do that — it can only follow edges from a node you already hold. So the very first step of every query needs something index-free adjacency explicitly does NOT provide.
All 16 scenes in Build a graph database (Neo4j / Dgraph-style) · Every curriculum