1- //! In-memory manifest cache for dependency resolution.
1+ //! Manifest cache data structures for dependency resolution.
22//!
3- //! ruborist itself only owns the memory tier; persistent storage (disk, remote
4- //! KV, …) is delegated to a [`super::store::ManifestStore`] supplied by the
5- //! host. The project-level cache ([`ProjectCacheData`]) is also pure data —
6- //! callers load/save it themselves and pass it through `BuildDepsOptions` /
7- //! `BuildDepsOutput`.
8- //!
9- //! # Memory Layout
10- //!
11- //! ```text
12- //! MemoryCache ─ Clone ─► (cheap: Arc ref-count)
13- //! │
14- //! └──► Arc<MemoryCacheInner> single allocation
15- //! ├── DashMap<Arc<FullManifest>> sharded, lock-free reads
16- //! ├── DashMap<Arc<VersionsInfo>>
17- //! └── DashMap<Arc<CoreVersionManifest>>
18- //! │
19- //! ▼
20- //! All values Arc-wrapped → get/set is O(1) ref-count,
21- //! no full clone of the (large) manifest payload.
22- //!
23- //! Global singleton: GLOBAL_MEMORY_CACHE (LazyLock)
24- //! └── all UnifiedRegistry instances share the same cache
25- //! ```
26- //!
27- //! # Lookup Flow
28- //!
29- //! ```text
30- //! resolve(name, spec)
31- //! │
32- //! ├─ 1. Memory hit? ──yes──► Arc<CoreVersionManifest> clone → done
33- //! ├─ 2. ManifestStore hit? ──yes──► populate memory → done
34- //! └─ 3. Network ──────► fetch JSON → store memory + fire-and-forget
35- //! ManifestStore::store_*
36- //! ```
3+ //! The demand BFS loop owns the in-memory manifest maps for one resolution run.
4+ //! This module only carries serializable data shared between the loop,
5+ //! provider jobs, and host persistence.
376
387use std:: collections:: HashMap ;
39- use std:: sync:: { Arc , LazyLock } ;
408
41- use dashmap:: DashMap ;
429use serde:: { Deserialize , Serialize } ;
4310
44- use crate :: model:: manifest:: { CoreVersionManifest , FullManifest , VersionsRef } ;
11+ use crate :: model:: manifest:: { CoreVersionManifest , VersionsRef } ;
4512
4613/// Lightweight versions info, persisted by `ManifestStore` for ETag validation.
4714#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -74,121 +41,6 @@ impl<'a> From<&'a Versions> for VersionsRef<'a> {
7441 }
7542}
7643
77- // ============================================================================
78- // Memory cache (lock-free reads via DashMap)
79- // ============================================================================
80-
81- /// Thread-safe in-memory manifest cache. Uses sharded `DashMap`s so concurrent
82- /// reads are lock-free across shards and writes only contend within a single
83- /// shard; values are stored as `Arc<…>` so reads return cheap ref-count clones
84- /// instead of cloning the full (potentially large) manifest payload.
85- #[ derive( Clone ) ]
86- pub struct MemoryCache ( Arc < MemoryCacheInner > ) ;
87-
88- struct MemoryCacheInner {
89- full_manifests : DashMap < String , Arc < FullManifest > > ,
90- versions_info : DashMap < String , Arc < VersionsInfo > > ,
91- version_manifests : DashMap < String , Arc < CoreVersionManifest > > ,
92- }
93-
94- /// Global singleton. All `UnifiedRegistry` instances share the same cache.
95- static GLOBAL_MEMORY_CACHE : LazyLock < MemoryCache > = LazyLock :: new ( || {
96- MemoryCache ( Arc :: new ( MemoryCacheInner {
97- full_manifests : DashMap :: new ( ) ,
98- versions_info : DashMap :: new ( ) ,
99- version_manifests : DashMap :: new ( ) ,
100- } ) )
101- } ) ;
102-
103- impl Default for MemoryCache {
104- fn default ( ) -> Self {
105- GLOBAL_MEMORY_CACHE . clone ( )
106- }
107- }
108-
109- impl MemoryCache {
110- pub fn get_full_manifest ( & self , name : & str ) -> Option < Arc < FullManifest > > {
111- self . 0 . full_manifests . get ( name) . map ( |v| v. clone ( ) )
112- }
113-
114- pub fn set_full_manifest ( & self , name : String , manifest : Arc < FullManifest > ) {
115- self . 0 . full_manifests . insert ( name, manifest) ;
116- }
117-
118- pub fn get_versions ( & self , name : & str ) -> Option < Arc < VersionsInfo > > {
119- self . 0 . versions_info . get ( name) . map ( |v| v. clone ( ) )
120- }
121-
122- pub fn set_versions ( & self , name : String , info : Arc < VersionsInfo > ) {
123- self . 0 . versions_info . insert ( name, info) ;
124- }
125-
126- pub fn get_version_manifest (
127- & self ,
128- name : & str ,
129- version : & str ,
130- ) -> Option < Arc < CoreVersionManifest > > {
131- let key = format ! ( "{name}@{version}" ) ;
132- self . 0 . version_manifests . get ( & key) . map ( |v| v. clone ( ) )
133- }
134-
135- pub fn set_version_manifest (
136- & self ,
137- name : String ,
138- version : String ,
139- manifest : Arc < CoreVersionManifest > ,
140- ) {
141- let key = format ! ( "{name}@{version}" ) ;
142- self . 0 . version_manifests . insert ( key, manifest) ;
143- }
144-
145- pub fn full_manifest_count ( & self ) -> usize {
146- self . 0 . full_manifests . len ( )
147- }
148-
149- pub fn versions_count ( & self ) -> usize {
150- self . 0 . versions_info . len ( )
151- }
152-
153- pub fn version_manifest_count ( & self ) -> usize {
154- self . 0 . version_manifests . len ( )
155- }
156-
157- /// Export all version manifests for persistence into a project cache.
158- pub fn export_version_manifests ( & self ) -> Vec < ( String , Arc < CoreVersionManifest > ) > {
159- self . 0
160- . version_manifests
161- . iter ( )
162- . map ( |kv| ( kv. key ( ) . clone ( ) , kv. value ( ) . clone ( ) ) )
163- . collect ( )
164- }
165-
166- /// Get cache statistics.
167- pub fn stats ( & self ) -> CacheStats {
168- CacheStats {
169- full_manifest_count : self . full_manifest_count ( ) ,
170- versions_count : self . versions_count ( ) ,
171- version_manifest_count : self . version_manifest_count ( ) ,
172- }
173- }
174- }
175-
176- /// Cache statistics.
177- #[ derive( Debug , Clone ) ]
178- pub struct CacheStats {
179- pub full_manifest_count : usize ,
180- pub versions_count : usize ,
181- pub version_manifest_count : usize ,
182- }
183-
184- /// Alias kept so call sites that pre-date the disk-cache split can continue
185- /// to spell the in-memory cache as `PackageCache` without churn.
186- pub type PackageCache = MemoryCache ;
187-
188- // ============================================================================
189- // Project-level cache (per-project resolved packages)
190- // ============================================================================
191-
19244/// Project-level cache data.
19345///
19446/// Stores resolved package information for a specific project. Hosts persist
@@ -211,62 +63,3 @@ pub struct ProjectPackageCache {
21163 #[ serde( default ) ]
21264 pub manifests : HashMap < String , CoreVersionManifest > ,
21365}
214-
215- #[ cfg( test) ]
216- mod tests {
217- use super :: * ;
218-
219- #[ test]
220- fn test_memory_cache_full_manifest ( ) {
221- let cache = MemoryCache :: default ( ) ;
222-
223- let manifest = FullManifest {
224- name : "test" . to_string ( ) ,
225- ..Default :: default ( )
226- } ;
227-
228- cache. set_full_manifest ( "test" . to_string ( ) , Arc :: new ( manifest) ) ;
229-
230- let retrieved = cache. get_full_manifest ( "test" ) . unwrap ( ) ;
231- assert_eq ! ( retrieved. name, "test" ) ;
232- assert ! ( cache. full_manifest_count( ) >= 1 ) ;
233- }
234-
235- #[ test]
236- fn test_memory_cache_versions ( ) {
237- let cache = MemoryCache :: default ( ) ;
238-
239- let info = VersionsInfo {
240- versions : Versions {
241- version_list : vec ! [ "1.0.0" . to_string( ) ] ,
242- dist_tags : HashMap :: new ( ) ,
243- } ,
244- etag : Some ( "abc" . to_string ( ) ) ,
245- last_updated : 12345 ,
246- } ;
247-
248- cache. set_versions ( "test" . to_string ( ) , Arc :: new ( info) ) ;
249-
250- let retrieved = cache. get_versions ( "test" ) . unwrap ( ) ;
251- assert_eq ! ( retrieved. versions. version_list, vec![ "1.0.0" ] ) ;
252- assert ! ( cache. versions_count( ) >= 1 ) ;
253- }
254-
255- #[ test]
256- fn test_memory_cache_version_manifest ( ) {
257- let cache = MemoryCache :: default ( ) ;
258-
259- let manifest = CoreVersionManifest {
260- name : "test" . to_string ( ) ,
261- version : "1.0.0" . to_string ( ) ,
262- ..Default :: default ( )
263- } ;
264-
265- cache. set_version_manifest ( "test" . to_string ( ) , "1.0.0" . to_string ( ) , Arc :: new ( manifest) ) ;
266-
267- let retrieved = cache. get_version_manifest ( "test" , "1.0.0" ) . unwrap ( ) ;
268- assert_eq ! ( retrieved. name, "test" ) ;
269- assert_eq ! ( retrieved. version, "1.0.0" ) ;
270- assert ! ( cache. version_manifest_count( ) >= 1 ) ;
271- }
272- }
0 commit comments