Skip to content

Commit 17e5a2e

Browse files
committed
wip
1 parent ace91ad commit 17e5a2e

7 files changed

Lines changed: 357 additions & 198 deletions

File tree

algo/scc.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func StronglyConnectedComponents(ctx context.Context, digraph container.Directed
3838
if _, visited := visitedIndex[node]; !visited {
3939
dfsDescentStack = append(dfsDescentStack, &descentCursor{
4040
id: node,
41-
branches: digraph.AdjacentNodes(node, graph.DirectionOutbound),
41+
branches: container.AdjacentNodes(digraph, node, graph.DirectionOutbound),
4242
branchIdx: 0,
4343
})
4444

@@ -72,7 +72,7 @@ func StronglyConnectedComponents(ctx context.Context, digraph container.Directed
7272

7373
dfsDescentStack = append(dfsDescentStack, &descentCursor{
7474
id: nextBranchID,
75-
branches: digraph.AdjacentNodes(nextBranchID, graph.DirectionOutbound),
75+
branches: container.AdjacentNodes(digraph, nextBranchID, graph.DirectionOutbound),
7676
branchIdx: 0,
7777
})
7878
} else if onStack.Contains(nextBranchID) {
@@ -263,32 +263,29 @@ func NewComponentGraph(ctx context.Context, originGraph container.DirectedGraph)
263263
var (
264264
componentMembers, memberComponentLookup = StronglyConnectedComponents(ctx, originGraph)
265265
componentDigraph = container.NewAdjacencyMapGraph()
266-
nextEdgeID = uint64(1)
267266
)
268267

269268
defer util.SLogMeasure("NewComponentGraph")()
270269

271270
// Ensure all components are present as vertices, even if they have no edges
272271
for componentID := range componentMembers {
273-
componentDigraph.Nodes().Add(uint64(componentID))
272+
componentDigraph.AddNode(uint64(componentID))
274273
}
275274

276275
originGraph.EachNode(func(node uint64) bool {
277276
nodeComponent := memberComponentLookup[node]
278277

279278
originGraph.EachAdjacentNode(node, graph.DirectionInbound, func(adjacent uint64) bool {
280279
if adjacentComponent := memberComponentLookup[adjacent]; nodeComponent != adjacentComponent {
281-
componentDigraph.AddEdge(nextEdgeID, adjacentComponent, nodeComponent)
282-
nextEdgeID += 1
280+
componentDigraph.AddEdge(adjacentComponent, nodeComponent)
283281
}
284282

285283
return util.IsContextLive(ctx)
286284
})
287285

288286
originGraph.EachAdjacentNode(node, graph.DirectionOutbound, func(adjacent uint64) bool {
289287
if adjacentComponent := memberComponentLookup[adjacent]; nodeComponent != adjacentComponent {
290-
componentDigraph.AddEdge(nextEdgeID, nodeComponent, adjacentComponent)
291-
nextEdgeID += 1
288+
componentDigraph.AddEdge(nodeComponent, adjacentComponent)
292289
}
293290

294291
return util.IsContextLive(ctx)

container/adjacencymap.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ type adjacencyMapDigraph struct {
1111
nodes cardinality.Duplex[uint64]
1212
}
1313

14-
func NewAdjacencyMapGraph() DirectedGraph {
14+
func NewAdjacencyMapGraph() MutableDirectedGraph {
1515
return &adjacencyMapDigraph{
1616
inbound: AdjacencyMap{},
1717
outbound: AdjacencyMap{},
1818
nodes: cardinality.NewBitmap64(),
1919
}
2020
}
2121

22+
func (s *adjacencyMapDigraph) AddNode(node uint64) {
23+
s.nodes.Add(node)
24+
}
25+
2226
func (s *adjacencyMapDigraph) Normalize() ([]uint64, DirectedGraph) {
2327
var (
2428
numNodes = s.NumNodes()
@@ -145,7 +149,7 @@ func (s *adjacencyMapDigraph) EachAdjacentNode(node uint64, direction graph.Dire
145149
}
146150
}
147151

148-
func (s *adjacencyMapDigraph) AddEdge(edge, start, end uint64) {
152+
func (s *adjacencyMapDigraph) AddEdge(start, end uint64) {
149153
if edgeBitmap, exists := s.outbound[start]; exists {
150154
edgeBitmap.Add(end)
151155
} else {

container/digraph.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,28 +60,53 @@ type PathTerminal struct {
6060
Distance int
6161
}
6262

63+
func Degrees(digraph DirectedGraph, node uint64, direction graph.Direction) uint64 {
64+
degrees := uint64(0)
65+
66+
digraph.EachAdjacentNode(node, direction, func(adjacent uint64) bool {
67+
degrees += 1
68+
return true
69+
})
70+
71+
return degrees
72+
}
73+
74+
func AdjacentNodes(digraph DirectedGraph, node uint64, direction graph.Direction) []uint64 {
75+
var nodes []uint64
76+
77+
digraph.EachAdjacentNode(node, direction, func(adjacent uint64) bool {
78+
nodes = append(nodes, adjacent)
79+
return true
80+
})
81+
82+
return nodes
83+
}
84+
6385
type DirectedGraph interface {
64-
AddEdge(edge, start, end uint64)
6586
NumNodes() uint64
66-
Nodes() cardinality.Duplex[uint64]
6787
EachNode(delegate func(node uint64) bool)
68-
Degrees(node uint64, direction graph.Direction) uint64
69-
AdjacentNodes(node uint64, direction graph.Direction) []uint64
7088
EachAdjacentNode(node uint64, direction graph.Direction, delegate func(adjacent uint64) bool)
7189
}
7290

91+
type MutableDirectedGraph interface {
92+
DirectedGraph
93+
94+
AddNode(node uint64)
95+
AddEdge(start, end uint64)
96+
}
97+
7398
func Dimensions(digraph DirectedGraph, direction graph.Direction) (uint64, uint64) {
7499
var largestRow uint64 = 0
75100

76101
digraph.EachNode(func(node uint64) bool {
77-
if degrees := digraph.Degrees(node, direction); degrees > largestRow {
102+
if degrees := Degrees(digraph, node, direction); degrees > largestRow {
78103
largestRow = degrees
79104
}
80105

81106
return true
82107
})
83108

84-
return digraph.Nodes().Cardinality(), largestRow
109+
return digraph.NumNodes(), largestRow
85110
}
86111

87112
func BFSTree(digraph DirectedGraph, nodeID uint64, direction graph.Direction) []PathTerminal {

container/fetch.go

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package container
33
import (
44
"context"
55

6+
"github.com/specterops/dawgs/cardinality"
67
"github.com/specterops/dawgs/cypher/models/cypher"
78
"github.com/specterops/dawgs/database"
89
"github.com/specterops/dawgs/graph"
@@ -14,13 +15,9 @@ const (
1415
channelBufferLen = 4096
1516
)
1617

17-
type anonymousEdge struct {
18-
EdgeID uint64
19-
StartID uint64
20-
EndID uint64
21-
}
22-
2318
func FetchAdjacencyGraph(ctx context.Context, graphDB database.Instance, relationshipFilter cypher.SyntaxNode) (DirectedGraph, error) {
19+
defer util.SLogMeasure("FetchAdjacencyGraph")()
20+
2421
digraph := NewAdjacencyMapGraph()
2522

2623
return digraph, graphDB.Session(ctx, func(ctx context.Context, driver database.Driver) error {
@@ -31,7 +28,6 @@ func FetchAdjacencyGraph(ctx context.Context, graphDB database.Instance, relatio
3128
}
3229

3330
builder.Return(
34-
query.Relationship().ID(),
3531
query.Start().ID(),
3632
query.End().ID(),
3733
)
@@ -44,16 +40,15 @@ func FetchAdjacencyGraph(ctx context.Context, graphDB database.Instance, relatio
4440

4541
for result.HasNext(ctx) {
4642
var (
47-
edgeID uint64
4843
startID uint64
4944
endID uint64
5045
)
5146

52-
if err := result.Scan(&edgeID, &startID, &endID); err != nil {
47+
if err := result.Scan(&startID, &endID); err != nil {
5348
return err
5449
}
5550

56-
digraph.AddEdge(edgeID, startID, endID)
51+
digraph.AddEdge(startID, endID)
5752
}
5853

5954
return result.Error()
@@ -100,22 +95,36 @@ func FetchKindDatabase(ctx context.Context, graphDB database.Instance) (KindData
10095
}
10196

10297
type TSDB struct {
103-
Triplestore Triplestore
104-
EdgeKinds KindMap
98+
Store Triplestore
99+
EdgeKinds KindMap
105100
}
106101

107-
func NewTSDB() TSDB {
102+
func (s TSDB) Projection(deletedNodes, deletedEdges cardinality.Duplex[uint64]) TSDB {
108103
return TSDB{
109-
Triplestore: NewTriplestore(),
110-
EdgeKinds: KindMap{},
104+
Store: s.Store.Projection(deletedNodes, deletedEdges),
105+
EdgeKinds: s.EdgeKinds,
111106
}
112107
}
113108

114-
func FetchTriplestore(ctx context.Context, graphDB database.Instance, filter cypher.SyntaxNode) (TSDB, error) {
115-
tsdb := TSDB{
116-
Triplestore: NewTriplestore(),
117-
EdgeKinds: KindMap{},
109+
func NewTSDB(ts Triplestore, edgeKinds KindMap) TSDB {
110+
return TSDB{
111+
Store: ts,
112+
EdgeKinds: edgeKinds,
118113
}
114+
}
115+
116+
func EmptyTSDB() TSDB {
117+
return NewTSDB(NewTriplestore(), KindMap{})
118+
}
119+
120+
func FetchTSDB(ctx context.Context, graphDB database.Instance, filter cypher.SyntaxNode) (TSDB, error) {
121+
var (
122+
store = NewTriplestore()
123+
tsdb = TSDB{
124+
Store: store,
125+
EdgeKinds: KindMap{},
126+
}
127+
)
119128

120129
defer util.SLogMeasure("FetchTriplestore")()
121130

@@ -149,7 +158,7 @@ func FetchTriplestore(ctx context.Context, graphDB database.Instance, filter cyp
149158
return err
150159
}
151160

152-
tsdb.Triplestore.AddEdge(relationshipID, startID, endID)
161+
store.AddTriple(relationshipID, startID, endID)
153162
tsdb.EdgeKinds.Add(relationshipKind, relationshipID)
154163
}
155164

container/threadsafe.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package container
2+
3+
import (
4+
"sync"
5+
6+
"github.com/gammazero/deque"
7+
)
8+
9+
type ThreadSafeDeque[T any] struct {
10+
lock *sync.RWMutex
11+
container deque.Deque[T]
12+
}
13+
14+
func (s *ThreadSafeDeque[T]) PushFront(elem T) {
15+
s.lock.Lock()
16+
s.container.PushFront(elem)
17+
s.lock.Unlock()
18+
}
19+
20+
func (s *ThreadSafeDeque[T]) PushBack(elem T) {
21+
s.lock.Lock()
22+
s.container.PushBack(elem)
23+
s.lock.Unlock()
24+
}
25+
26+
func (s *ThreadSafeDeque[T]) PopFront() T {
27+
s.lock.Lock()
28+
value := s.container.PopFront()
29+
s.lock.Unlock()
30+
return value
31+
}
32+
33+
func (s *ThreadSafeDeque[T]) PopBack() T {
34+
s.lock.Lock()
35+
value := s.container.PopBack()
36+
s.lock.Unlock()
37+
return value
38+
}
39+
40+
func (s *ThreadSafeDeque[T]) Len() int {
41+
s.lock.RLock()
42+
numElements := s.container.Len()
43+
s.lock.RUnlock()
44+
return numElements
45+
}

0 commit comments

Comments
 (0)