NAME Data::Graph::Shared - Shared-memory directed weighted graph for Linux SYNOPSIS use Data::Graph::Shared; my $g = Data::Graph::Shared->new(undef, 100, 500); # 100 nodes, 500 edges my $a = $g->add_node(10); # returns node index my $b = $g->add_node(20); my $c = $g->add_node(30); $g->add_edge($a, $b, 5); # a→b weight 5 $g->add_edge($a, $c, 3); # a→c weight 3 $g->add_edge($b, $c, 1); # b→c weight 1 my @nbrs = $g->neighbors($a); # ([1,5], [2,3]) — [dst, weight] pairs say $g->degree($a); # 2 say $g->node_data($a); # 10 $g->remove_node($b); # removes node and outgoing edges DESCRIPTION Directed weighted graph in shared memory. Nodes allocated from a bitmap pool, edges stored as adjacency lists in a separate edge pool. Mutex-protected mutations with PID-based stale recovery. Note: "remove_node" removes the node and its outgoing edges only. Incoming edges from other nodes are NOT automatically removed (this is an O(1) design choice) — their "dst" is left dangling until the slot's bit is reused. Use "remove_node_full" when this matters; it additionally splices incoming edges in O(N+E). Linux-only. Requires 64-bit Perl. METHODS Constructors my $g = Data::Graph::Shared->new($path, $max_nodes, $max_edges); # file-backed my $g = Data::Graph::Shared->new(undef, $max_nodes, $max_edges); # anonymous my $g = Data::Graph::Shared->new_memfd($name, $max_nodes, $max_edges); my $g = Data::Graph::Shared->new_from_fd($fd); # reopen memfd Operations my $id = $g->add_node($data); # returns node index or undef $g->add_edge($src, $dst); # weight defaults to 1 $g->add_edge($src, $dst, $weight); $g->remove_node($id); # O(1) — outgoing edges only $g->remove_node_full($id); # O(N+E) — also splices incoming $g->has_node($id); $g->node_data($id); $g->set_node_data($id, $data); my @pairs = $g->neighbors($id); # list of [$dst, $weight] $g->each_neighbor($id, sub { my ($dst, $w) = @_ }); $g->degree($id); my @ids = $g->nodes; # all node indices $g->node_count; $g->edge_count; $g->max_nodes; $g->max_edges; Lifecycle $g->path; # backing file path, or undef for anon/memfd $g->memfd; # memfd fd (-1 for file-backed/anon) $g->stats; # diagnostic hashref $g->sync; # msync mmap to backing store $g->unlink; # remove backing file Class->unlink($path); # class-method form Event Loop Integration my $fd = $g->eventfd; # lazy-create eventfd, returns fd $g->eventfd_set($fd); # attach an external eventfd my $fd = $g->fileno; # current eventfd fd, or -1 $g->notify; # write 1 to eventfd (caller signals update) my $n = $g->eventfd_consume; # read+reset eventfd counter BENCHMARKS Single-process (10K ops, x86_64 Linux, Perl 5.40): add_node 3.9M/s add_edge (random) 2.3M/s has_node 13.3M/s node_data 5.5M/s neighbors 2.6M/s degree 5.6M/s STATS stats() returns: "node_count", "edge_count", "max_nodes", "max_edges", "ops", "mmap_size". SECURITY The mmap region is writable by all processes that open it. Do not share backing files with untrusted processes. SEE ALSO Data::Heap::Shared - priority queue (for Dijkstra, Prim, etc.) Data::Pool::Shared - fixed-size object pool Data::HashMap::Shared - concurrent hash table Data::Buffer::Shared - typed shared array Data::Queue::Shared - FIFO queue Data::Stack::Shared - LIFO stack Data::Deque::Shared - double-ended queue Data::Log::Shared - append-only log Data::Sync::Shared - synchronization primitives Data::PubSub::Shared - publish-subscribe ring Data::ReqRep::Shared - request-reply Data::BitSet::Shared - shared bitset (lock-free per-bit ops) Data::RingBuffer::Shared - fixed-size overwriting ring buffer AUTHOR vividsnow LICENSE This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.