Skip to content

Commit 2eeac3a

Browse files
committed
tapdb: adapt universe root cache to observe pagination
1 parent ac3a77b commit 2eeac3a

File tree

2 files changed

+75
-27
lines changed

2 files changed

+75
-27
lines changed

tapdb/multiverse.go

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
100100
type 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.
191218
func 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) {
301334
func (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
}

tapdb/universe.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,8 @@ func universeFetchProofLeaf(ctx context.Context,
615615

616616
// mintingKeys returns all the leaf keys in the target universe.
617617
func mintingKeys(ctx context.Context, dbTx BaseUniverseStore,
618-
q universe.UniverseLeafKeysQuery) ([]universe.LeafKey, error) {
619-
620-
namespace := q.Id.String()
618+
q universe.UniverseLeafKeysQuery,
619+
namespace string) ([]universe.LeafKey, error) {
621620

622621
universeKeys, err := dbTx.FetchUniverseKeys(
623622
ctx, UniverseLeafKeysQuery{
@@ -678,7 +677,7 @@ func (b *BaseUniverseTree) MintingKeys(ctx context.Context,
678677

679678
readTx := NewBaseUniverseReadTx()
680679
dbErr := b.db.ExecTx(ctx, &readTx, func(db BaseUniverseStore) error {
681-
dbLeaves, err := mintingKeys(ctx, db, q)
680+
dbLeaves, err := mintingKeys(ctx, db, q, b.smtNamespace)
682681
if err != nil {
683682
return err
684683
}

0 commit comments

Comments
 (0)