2020import java .nio .file .Path ;
2121import java .util .List ;
2222import java .util .Map ;
23+ import java .util .concurrent .atomic .AtomicReference ;
2324
2425/**
2526 * REST API controller for service topology queries.
@@ -32,8 +33,8 @@ public class TopologyController {
3233 private final TopologyService topologyService ;
3334 private final GraphStore graphStore ;
3435 private final CodeIqConfig config ;
35- private volatile List <CodeNode > cachedNodes ;
36- private volatile List <CodeEdge > cachedEdges ;
36+ private final AtomicReference < List <CodeNode >> cachedNodes = new AtomicReference <>() ;
37+ private final AtomicReference < List <CodeEdge >> cachedEdges = new AtomicReference <>() ;
3738
3839 public TopologyController (TopologyService topologyService ,
3940 @ Autowired (required = false ) GraphStore graphStore ,
@@ -65,15 +66,16 @@ private boolean hasNeo4jData() {
6566 * Load data from Neo4j if available, otherwise from H2 cache.
6667 */
6768 private synchronized void ensureDataLoaded () {
68- if (cachedNodes != null ) return ;
69+ if (cachedNodes . get () != null ) return ;
6970
7071 // Try Neo4j first (has enriched data with SERVICE nodes)
7172 if (hasNeo4jData ()) {
72- cachedNodes = graphStore .findAll ();
73+ List <CodeNode > nodes = graphStore .findAll ();
74+ cachedNodes .set (nodes );
7375 // Collect edges from all nodes' relationship lists
74- cachedEdges = cachedNodes .stream ()
76+ cachedEdges . set ( nodes .stream ()
7577 .flatMap (n -> n .getEdges ().stream ())
76- .toList ();
78+ .toList ()) ;
7779 return ;
7880 }
7981
@@ -83,89 +85,91 @@ private synchronized void ensureDataLoaded() {
8385 Path h2File = root .resolve (config .getCacheDir ()).resolve ("analysis-cache.mv.db" );
8486 if (!Files .exists (h2File )) return ;
8587 try (AnalysisCache cache = new AnalysisCache (cachePath )) {
86- cachedNodes = cache .loadAllNodes ();
87- cachedEdges = cache .loadAllEdges ();
88+ cachedNodes . set ( cache .loadAllNodes () );
89+ cachedEdges . set ( cache .loadAllEdges () );
8890 }
8991 }
9092
9193 /**
9294 * Invalidate the in-memory cache (e.g. after re-analysis).
9395 */
9496 public synchronized void invalidateCache () {
95- cachedNodes = null ;
96- cachedEdges = null ;
97+ cachedNodes . set ( null ) ;
98+ cachedEdges . set ( null ) ;
9799 neo4jHasData = null ;
98100 }
99101
100102 @ GetMapping
101103 public Map <String , Object > getTopology () {
102104 ensureDataLoaded ();
103- requireCache ();
104- return topologyService .getTopology (cachedNodes , cachedEdges );
105+ List < CodeNode > nodes = requireCache ();
106+ return topologyService .getTopology (nodes , cachedEdges . get () );
105107 }
106108
107109 @ GetMapping ("/services/{name}" )
108110 public Map <String , Object > serviceDetail (@ PathVariable String name ) {
109111 ensureDataLoaded ();
110- requireCache ();
111- return topologyService .serviceDetail (name , cachedNodes , cachedEdges );
112+ List < CodeNode > nodes = requireCache ();
113+ return topologyService .serviceDetail (name , nodes , cachedEdges . get () );
112114 }
113115
114116 @ GetMapping ("/services/{name}/deps" )
115117 public Map <String , Object > serviceDependencies (@ PathVariable String name ) {
116118 ensureDataLoaded ();
117- requireCache ();
118- return topologyService .serviceDependencies (name , cachedNodes , cachedEdges );
119+ List < CodeNode > nodes = requireCache ();
120+ return topologyService .serviceDependencies (name , nodes , cachedEdges . get () );
119121 }
120122
121123 @ GetMapping ("/services/{name}/dependents" )
122124 public Map <String , Object > serviceDependents (@ PathVariable String name ) {
123125 ensureDataLoaded ();
124- requireCache ();
125- return topologyService .serviceDependents (name , cachedNodes , cachedEdges );
126+ List < CodeNode > nodes = requireCache ();
127+ return topologyService .serviceDependents (name , nodes , cachedEdges . get () );
126128 }
127129
128130 @ GetMapping ("/blast-radius/{nodeId}" )
129131 public Map <String , Object > blastRadius (@ PathVariable String nodeId ) {
130132 ensureDataLoaded ();
131- requireCache ();
132- return topologyService .blastRadius (nodeId , cachedNodes , cachedEdges );
133+ List < CodeNode > nodes = requireCache ();
134+ return topologyService .blastRadius (nodeId , nodes , cachedEdges . get () );
133135 }
134136
135137 @ GetMapping ("/path" )
136138 public List <Map <String , Object >> findPath (
137139 @ RequestParam ("from" ) String source ,
138140 @ RequestParam ("to" ) String target ) {
139141 ensureDataLoaded ();
140- requireCache ();
141- return topologyService .findPath (source , target , cachedNodes , cachedEdges );
142+ List < CodeNode > nodes = requireCache ();
143+ return topologyService .findPath (source , target , nodes , cachedEdges . get () );
142144 }
143145
144146 @ GetMapping ("/bottlenecks" )
145147 public List <Map <String , Object >> findBottlenecks () {
146148 ensureDataLoaded ();
147- requireCache ();
148- return topologyService .findBottlenecks (cachedNodes , cachedEdges );
149+ List < CodeNode > nodes = requireCache ();
150+ return topologyService .findBottlenecks (nodes , cachedEdges . get () );
149151 }
150152
151153 @ GetMapping ("/circular" )
152154 public List <List <String >> findCircularDeps () {
153155 ensureDataLoaded ();
154- requireCache ();
155- return topologyService .findCircularDeps (cachedNodes , cachedEdges );
156+ List < CodeNode > nodes = requireCache ();
157+ return topologyService .findCircularDeps (nodes , cachedEdges . get () );
156158 }
157159
158160 @ GetMapping ("/dead" )
159161 public List <Map <String , Object >> findDeadServices () {
160162 ensureDataLoaded ();
161- requireCache ();
162- return topologyService .findDeadServices (cachedNodes , cachedEdges );
163+ List < CodeNode > nodes = requireCache ();
164+ return topologyService .findDeadServices (nodes , cachedEdges . get () );
163165 }
164166
165- private void requireCache () {
166- if (cachedNodes == null ) {
167+ private List <CodeNode > requireCache () {
168+ List <CodeNode > nodes = cachedNodes .get ();
169+ if (nodes == null ) {
167170 throw new ResponseStatusException (HttpStatus .NOT_FOUND ,
168171 "No analysis cache found. Run analyze first." );
169172 }
173+ return nodes ;
170174 }
171175}
0 commit comments