@@ -94,7 +94,7 @@ func NewProofKey(id universe.Identifier, key universe.LeafKey) ProofKey {
9494}
9595
9696// numCachedProofs is the number of universe proofs we'll cache.
97- const numCachedProofs = 25_000
97+ const numCachedProofs = 50_000
9898
9999// cachedProof is a single cached proof.
100100type cachedProof []* universe.Proof
@@ -181,18 +181,47 @@ func (p *proofCache) delProofsForAsset(id universe.Identifier) {
181181 p .Delete (idStr )
182182}
183183
184- // cachedRoots is used to store the latest root for each known universe tree.
185- type cachedRoots []universe.Root
184+ // rootPageQuery is a wrapper around a query to fetch all the roots, but with
185+ // pagination parameters.
186+ type rootPageQuery struct {
187+ withAmountsById bool
188+ leafQuery
189+ }
190+
191+ // newRootPageQuery creates a new root page query.
192+ func newRootPageQuery (q universe.RootNodesQuery ) rootPageQuery {
193+ return rootPageQuery {
194+ withAmountsById : q .WithAmountsById ,
195+ leafQuery : leafQuery {
196+ sortDirection : q .SortDirection ,
197+ offset : int32 (q .Offset ),
198+ limit : int32 (q .Limit ),
199+ },
200+ }
201+ }
202+
203+ // universeRootPage is a single page of roots.
204+ type universeRootPage []universe.Root
205+
206+ // Size is the amount of roots in the page.
207+ func (u universeRootPage ) Size () (uint64 , error ) {
208+ return uint64 (len (u )), nil
209+ }
210+
211+ // rootPageCache is used to store the latest root pages for a given treeID.
212+ type rootPageCache = lru.Cache [rootPageQuery , universeRootPage ]
186213
187214// atomicRootCache is an atomic pointer to a root cache.
188- type atomicRootCache = atomic.Pointer [cachedRoots ]
215+ type atomicRootCache = atomic.Pointer [rootPageCache ]
189216
190217// newAtomicRootCache creates a new atomic root cache.
191218func newAtomicRootCache () atomicRootCache {
192- treeCache := & cachedRoots {}
219+ rootCache := lru.NewCache [rootPageQuery , universeRootPage ](
220+ numCachedProofs ,
221+ )
193222
194223 var a atomicRootCache
195- a .Store (treeCache )
224+ a .Store (rootCache )
196225
197226 return a
198227}
@@ -237,14 +266,8 @@ func newRootNodeCache() *rootNodeCache {
237266// fetchRoots reads the cached roots for the given proof type. If the amounts
238267// are needed, then we return nothing so we go to the database to fetch the
239268// information.
240- func (r * rootNodeCache ) fetchRoots (withAmts , haveWriteLock bool ,
241- ) []universe.Root {
242-
243- // We don't cache roots with amounts, so if the caller wants the
244- // amounts, they'll go to disk.
245- if withAmts {
246- return nil
247- }
269+ func (r * rootNodeCache ) fetchRoots (q universe.RootNodesQuery ,
270+ haveWriteLock bool ) []universe.Root {
248271
249272 // If we have the write lock already, no need to fetch it.
250273 if ! haveWriteLock {
@@ -256,7 +279,7 @@ func (r *rootNodeCache) fetchRoots(withAmts, haveWriteLock bool,
256279
257280 // Attempt to read directly from the root node cache.
258281 rootNodeCache := r .allRoots .Load ()
259- rootNodes := * rootNodeCache
282+ rootNodes , _ := rootNodeCache . Get ( newRootPageQuery ( q ))
260283
261284 if len (rootNodes ) > 0 {
262285 r .Hit ()
@@ -282,13 +305,23 @@ func (r *rootNodeCache) fetchRoot(id universe.Identifier) *universe.Root {
282305 return nil
283306}
284307
308+ // cacheRoot stores the given root in the cache.
309+ func (r * rootNodeCache ) cacheRoot (id universe.Identifier ,
310+ root universe.Root ) {
311+
312+ rootIndex := r .rootIndex .Load ()
313+ rootIndex .Store (treeID (id .String ()), & root )
314+ }
315+
285316// cacheRoots stores the given roots in the cache.
286- func (r * rootNodeCache ) cacheRoots (rootNodes []universe.Root ) {
317+ func (r * rootNodeCache ) cacheRoots (q universe.RootNodesQuery ,
318+ rootNodes []universe.Root ) {
319+
287320 log .Debugf ("caching num_roots=%v" , len (rootNodes ))
288321
289322 // Store the main root pointer, then update the root index.
290- newRoots := cachedRoots ( rootNodes )
291- r . allRoots . Store ( & newRoots )
323+ rootPageCache := r . allRoots . Load ( )
324+ rootPageCache . Put ( newRootPageQuery ( q ), rootNodes )
292325
293326 rootIndex := r .rootIndex .Load ()
294327 for _ , rootNode := range rootNodes {
@@ -301,7 +334,11 @@ func (r *rootNodeCache) cacheRoots(rootNodes []universe.Root) {
301334func (r * rootNodeCache ) wipeCache () {
302335 log .Debugf ("wiping universe cache" )
303336
304- r .allRoots .Store (& cachedRoots {})
337+ rootCache := lru.NewCache [rootPageQuery , universeRootPage ](
338+ numCachedProofs ,
339+ )
340+ r .allRoots .Store (rootCache )
341+
305342 r .rootIndex .Store (& rootIndex {})
306343}
307344
@@ -512,6 +549,16 @@ func (b *MultiverseStore) UniverseRootNode(ctx context.Context,
512549 return * rootNode , nil
513550 }
514551
552+ b .rootNodeCache .Lock ()
553+ defer b .rootNodeCache .Unlock ()
554+
555+ // Check to see if the cache was populated while we were waiting for
556+ // the lock.
557+ rootNode = b .rootNodeCache .fetchRoot (id )
558+ if rootNode != nil {
559+ return * rootNode , nil
560+ }
561+
515562 var universeRoot UniverseRoot
516563
517564 universeNamespace := id .String ()
@@ -546,6 +593,8 @@ func (b *MultiverseStore) UniverseRootNode(ctx context.Context,
546593 AssetName : universeRoot .AssetName ,
547594 }
548595
596+ b .rootNodeCache .cacheRoot (id , dbRoot )
597+
549598 return dbRoot , nil
550599}
551600
@@ -573,7 +622,7 @@ func (b *MultiverseStore) UniverseLeafKeys(ctx context.Context,
573622 // Otherwise, we'll read it from disk, then add it to our cache.
574623 readTx := NewBaseUniverseReadTx ()
575624 dbErr := b .db .ExecTx (ctx , & readTx , func (db BaseMultiverseStore ) error {
576- dbLeaves , err := mintingKeys (ctx , db , q )
625+ dbLeaves , err := mintingKeys (ctx , db , q , q . Id . String () )
577626 if err != nil {
578627 return err
579628 }
@@ -597,7 +646,7 @@ func (b *MultiverseStore) RootNodes(ctx context.Context,
597646 q universe.RootNodesQuery ) ([]universe.Root , error ) {
598647
599648 // Attempt to read directly from the root node cache.
600- rootNodes := b .rootNodeCache .fetchRoots (q . WithAmountsById , false )
649+ rootNodes := b .rootNodeCache .fetchRoots (q , false )
601650 if len (rootNodes ) > 0 {
602651 log .Debugf ("read %d root nodes from cache" , len (rootNodes ))
603652 return rootNodes , nil
@@ -608,7 +657,7 @@ func (b *MultiverseStore) RootNodes(ctx context.Context,
608657
609658 // Check to see if the cache was populated while we were waiting for
610659 // the mutex.
611- rootNodes = b .rootNodeCache .fetchRoots (q . WithAmountsById , true )
660+ rootNodes = b .rootNodeCache .fetchRoots (q , true )
612661 if len (rootNodes ) > 0 {
613662 log .Debugf ("read %d root nodes from cache" , len (rootNodes ))
614663 return rootNodes , nil
@@ -721,7 +770,7 @@ func (b *MultiverseStore) RootNodes(ctx context.Context,
721770 len (uniRoots ), time .Since (now ))
722771
723772 // Cache all the root nodes we just read from the database.
724- b .rootNodeCache .cacheRoots (uniRoots )
773+ b .rootNodeCache .cacheRoots (q , uniRoots )
725774
726775 return uniRoots , nil
727776}
0 commit comments