From 28efb6fd5020f046c1216773dd4e2f7e601f7d35 Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Wed, 21 Jul 2021 16:17:41 -0400 Subject: [PATCH] feat(orchard): synchronize cache access Signed-off-by: Chris Waldon --- orchard/orchard.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/orchard/orchard.go b/orchard/orchard.go index 98a6535..1dc4237 100644 --- a/orchard/orchard.go +++ b/orchard/orchard.go @@ -10,6 +10,7 @@ package orchard import ( "fmt" "io" + "sync" "time" "git.sr.ht/~whereswaldon/forest-go" @@ -55,7 +56,8 @@ var ( // Nodes are persisted as schema entities and can be queried as such. type Orchard struct { *bolt.DB - ReadCache *store.MemoryStore + cacheLock sync.RWMutex + readCache *store.MemoryStore // codec zero value defaults to Arbor serialization. // Can only be overriden by interal code. @@ -94,7 +96,7 @@ func Using(db *bolt.DB, opts ...Option) (*Orchard, error) { } o := Orchard{ DB: db, - ReadCache: store.NewMemoryStore(), + readCache: store.NewMemoryStore(), } for _, opt := range opts { opt(&o) @@ -185,12 +187,17 @@ func (o *Orchard) Add(node forest.Node) error { // Get searches for a node with the given id. // Present indicates whether the node exists, err indicates a failure to load it. func (o *Orchard) Get(nodeID *fields.QualifiedHash) (node forest.Node, present bool, err error) { - if n, ok, _ := o.ReadCache.Get(nodeID); ok { + o.cacheLock.RLock() + if n, ok, _ := o.readCache.Get(nodeID); ok { + o.cacheLock.RUnlock() return n, ok, nil } + o.cacheLock.RUnlock() defer func() { + o.cacheLock.Lock() + defer o.cacheLock.Unlock() if err == nil && node != nil { - _ = o.ReadCache.Add(node) + _ = o.readCache.Add(node) } }() var ( @@ -407,6 +414,8 @@ func (o *Orchard) RemoveSubtree(id *fields.QualifiedHash) error { if err != nil { return err } + o.cacheLock.Lock() + defer o.cacheLock.Unlock() for _, child := range children { if err := o.RemoveSubtree(child); err != nil { return err @@ -416,7 +425,7 @@ func (o *Orchard) RemoveSubtree(id *fields.QualifiedHash) error { } func (o *Orchard) delete(n forest.Node) error { - if err := o.ReadCache.RemoveSubtree(n.ID()); err != nil { + if err := o.readCache.RemoveSubtree(n.ID()); err != nil { return fmt.Errorf("failed removing node %v from cache: %w", n.ID(), err) } id, err := o.codec.Encode(n.ID()) -- 2.45.2