Algorithm:
For each plugin
- Select root node
- Node not in subgraph previously constructed
- Affinity is equal to plugin name
- Select adjacent node to any node in already subgraph which is not in rejected list
- if there are no such nodes end
- Check selected node has same affinity
- Add node to subgraph if check was successful or add to rejected list otherwise
- Check global condition
- Nodes in rejected list can never be added to subgraph
- Nodes not in subgraph and not in rejected list can possibly be added later
- Check subgraph topology (the only check now is there are no indirect subgraph self-references)
- If global condition was failed remove last node from subgraph, add it to rejected list and go to step 5
- we can rollback multiple times here because rejected list is changed every time
- Go to step 2
Example:
graph TD;
1-->2;
2-->3;
2-->4;
3-->5;
4-->5;
5-->6;
6-->7;
Nodes [1,2,3,5,6,7] are supported in plugin, [4] is not
Possible roots: [1,2,3,5,6,7]
- Select root [1]
- Subgraph: [1]
- Rejected: []
- Global condition: ok
- Merge [2]
- Subgraph: [1,2]
- Rejected: []
- Global condition: ok
- Merge [3]
- Subgraph: [1,2,3]
- Rejected: []
- Global condition: ok
- Merge [5]
- Subgraph: [1,2,3,5]
- Rejected: []
- Global condition: There is possible self-references through node [4] but we do not know yet, ok
- Merge [6]
- Subgraph: [1,2,3,5,6]
- Rejected: []
- Global condition: There is possible self-references through node [4] but we do not know yet, ok
- Merge [7]
- Subgraph: [1,2,3,5,6,7]
- Rejected: []
- Global condition: There is possible self-references through node [4] but we do not know yet, ok
- Failed to merge [4]
- Subgraph: [1,2,3,5,6,7]
- Rejected: [4]
- Global condition: There is self-references through node [4], reject
- Rollback [7]
- Subgraph: [1,2,3,5,6]
- Rejected: [4,7]
- Global condition: There is self-references through node [4], reject
- Rollback [6]
- Subgraph: [1,2,3,5]
- Rejected: [4,6,7]
- Global condition: There is self-references through node [4], reject
- Rollback [5]
- Subgraph: [1,2,3]
- Rejected: [4,5,6,7]
- Global condition: ok
- There are nodes to merge end
Possible roots: [5,6,7]
- Select root [5]
- Subgraph: [5]
- Rejected: []
- Global condition: ok
- Merge [6]
- Subgraph: [5,6]
- Rejected: []
- Global condition: ok
- Merge [7]
- Subgraph: [5,6,7]
- Rejected: []
- Global condition: ok
- Merge [3]
- Subgraph: [3,5,6,7]
- Rejected: []
- Global condition: ok
- Merge [2]
- Subgraph: [2,3,5,6,7]
- Rejected: []
- Global condition: There is possible self-references through node [4] but we do not know yet, ok
- Failed to merge [4]
- Subgraph: [2,3,5,6,7]
- Rejected: [4]
- Global condition: There is self-references through node [4], reject
- Rollback [2]
- Subgraph: [3,5,6,7]
- Rejected: [2,4]
- Global condition: ok
- There are nodes to merge end
Possible roots: [] no roots, END
Subgraphs: [1,2,3], [3,5,6,7]
Select best subgraph:
- When we have multiple subgraphs larger ([3,5,6,7]) is always selected, always
Repeat previous steps with remaining nodes [1,2]
The final result is:
- First plugin: [3,5,6,7], [1,2]
- Second plugin: [4]
- For each node in network build a list of reachable node (transitive closure)
- For each pair of nodes in subgraph find
path
nodes (nodes through one node in pair reachable to other)- assume
src
- one node in pair,dst
- other node in pair - get all nodes reachable from
src
- in those nodes find nodes through you can reach
dst
those will be ourpath
node
- assume
- Results for pairs is cached.
- Check if there intersection between
path
nodes set and rejected nodes set for each nodes pair in subgraph - In case of intersection we have a self-reference and subgraph is invalid