[#811] service/container: Hide cache invalidation logic in Writer interface

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2021-09-08 20:24:16 +03:00 committed by Alex Vanin
parent 49b6b5b49d
commit 01df4ffa61
2 changed files with 64 additions and 67 deletions

View file

@ -58,7 +58,10 @@ func initContainerService(c *cfg) {
} }
cnrRdr := new(morphContainerReader) cnrRdr := new(morphContainerReader)
cnrInvalidator := new(morphContainerInvalidator)
cnrWrt := &morphContainerWriter{
neoClient: wrap,
}
if c.cfgMorph.disableCache { if c.cfgMorph.disableCache {
c.cfgObject.eaclSource = eACLFetcher c.cfgObject.eaclSource = eACLFetcher
@ -79,9 +82,10 @@ func initContainerService(c *cfg) {
cnrRdr.eacl = c.cfgObject.eaclSource cnrRdr.eacl = c.cfgObject.eaclSource
cnrRdr.get = c.cfgObject.cnrSource cnrRdr.get = c.cfgObject.cnrSource
cnrInvalidator.lists = cachedContainerLister cnrWrt.cacheEnabled = true
cnrInvalidator.eacls = cachedEACLStorage cnrWrt.lists = cachedContainerLister
cnrInvalidator.containers = cachedContainerStorage cnrWrt.eacls = cachedEACLStorage
cnrWrt.containers = cachedContainerStorage
} }
localMetrics := &localStorageLoad{ localMetrics := &localStorageLoad{
@ -152,7 +156,7 @@ func initContainerService(c *cfg) {
&c.key.PrivateKey, &c.key.PrivateKey,
containerService.NewResponseService( containerService.NewResponseService(
&usedSpaceService{ &usedSpaceService{
Server: containerService.NewExecutionService(containerMorph.NewExecutor(wrap, cnrRdr, cnrInvalidator)), Server: containerService.NewExecutionService(containerMorph.NewExecutor(cnrRdr, cnrWrt)),
loadWriterProvider: loadRouter, loadWriterProvider: loadRouter,
loadPlacementBuilder: loadPlacementBuilder, loadPlacementBuilder: loadPlacementBuilder,
routeBuilder: routeBuilder, routeBuilder: routeBuilder,
@ -539,41 +543,56 @@ func (x *morphContainerReader) List(id *owner.ID) ([]*cid.ID, error) {
return x.lister.List(id) return x.lister.List(id)
} }
type morphContainerInvalidator struct { type morphContainerWriter struct {
containers interface { neoClient *wrapper.Wrapper
InvalidateContainer(*cid.ID)
}
eacls interface { cacheEnabled bool
InvalidateEACL(*cid.ID) containers *ttlContainerStorage
} eacls *ttlEACLStorage
lists *ttlContainerLister
lists interface {
InvalidateContainerList(*owner.ID)
InvalidateContainerListByCID(*cid.ID)
}
} }
func (x *morphContainerInvalidator) InvalidateContainer(id *cid.ID) { func (m morphContainerWriter) Put(cnr *containerSDK.Container) (*cid.ID, error) {
if x.containers != nil { containerID, err := wrapper.Put(m.neoClient, cnr)
x.containers.InvalidateContainer(id) if err != nil {
return nil, err
} }
if m.cacheEnabled {
m.lists.InvalidateContainerList(cnr.OwnerID())
}
return containerID, nil
} }
func (x *morphContainerInvalidator) InvalidateEACL(id *cid.ID) { func (m morphContainerWriter) Delete(witness containerCore.RemovalWitness) error {
if x.eacls != nil { err := wrapper.Delete(m.neoClient, witness)
x.eacls.InvalidateEACL(id) if err != nil {
return err
} }
if m.cacheEnabled {
containerID := witness.ContainerID()
m.containers.InvalidateContainer(containerID)
m.eacls.InvalidateEACL(containerID)
// it is faster to use slower invalidation by CID than making separate
// network request to fetch owner ID of the container.
m.lists.InvalidateContainerListByCID(containerID)
}
return nil
} }
func (x *morphContainerInvalidator) InvalidateContainerList(id *owner.ID) { func (m morphContainerWriter) PutEACL(table *eaclSDK.Table) error {
if x.lists != nil { err := wrapper.PutEACL(m.neoClient, table)
x.lists.InvalidateContainerList(id) if err != nil {
return err
} }
}
func (x *morphContainerInvalidator) InvalidateContainerListByCID(id *cid.ID) { if m.cacheEnabled {
if x.lists != nil { m.eacls.InvalidateEACL(table.CID())
x.lists.InvalidateContainerListByCID(id)
} }
return nil
} }

View file

@ -12,17 +12,13 @@ import (
"github.com/nspcc-dev/neofs-api-go/v2/container" "github.com/nspcc-dev/neofs-api-go/v2/container"
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
containercore "github.com/nspcc-dev/neofs-node/pkg/core/container" containercore "github.com/nspcc-dev/neofs-node/pkg/core/container"
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper"
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container" containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl" "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
) )
type morphExecutor struct { type morphExecutor struct {
wrapper *wrapper.Wrapper
rdr Reader rdr Reader
wrt Writer
invalidator Invalidator
} }
// Reader is an interface of read-only container storage. // Reader is an interface of read-only container storage.
@ -36,27 +32,20 @@ type Reader interface {
List(*owner.ID) ([]*cid.ID, error) List(*owner.ID) ([]*cid.ID, error)
} }
// Invalidator is an interface of local cache invalidator. It removes cached // Writer is an interface of container storage updater.
// values in order to synchronize updated data in the side chain faster. type Writer interface {
type Invalidator interface { // Put stores specified container in the side chain.
// InvalidateContainer from the local container cache if it exists. Put(*containerSDK.Container) (*cid.ID, error)
InvalidateContainer(*cid.ID) // Delete removes specified container from the side chain.
// InvalidateEACL from the local eACL cache if it exists. Delete(containercore.RemovalWitness) error
InvalidateEACL(*cid.ID) // PutEACL updates extended ACL table of specified container in the side chain.
// InvalidateContainerList from the local cache of container list results PutEACL(*eaclSDK.Table) error
// if it exists.
InvalidateContainerList(*owner.ID)
// InvalidateContainerListByCID from the local cache of container list
// results if it exists. Container list source uses owner.ID as a key,
// so invalidating cache record by the value requires different approach.
InvalidateContainerListByCID(*cid.ID)
} }
func NewExecutor(w *wrapper.Wrapper, rdr Reader, i Invalidator) containerSvc.ServiceExecutor { func NewExecutor(rdr Reader, wrt Writer) containerSvc.ServiceExecutor {
return &morphExecutor{ return &morphExecutor{
wrapper: w, rdr: rdr,
rdr: rdr, wrt: wrt,
invalidator: i,
} }
} }
@ -71,13 +60,11 @@ func (s *morphExecutor) Put(ctx containerSvc.ContextWithToken, body *container.P
session.NewTokenFromV2(ctx.SessionToken), session.NewTokenFromV2(ctx.SessionToken),
) )
cid, err := wrapper.Put(s.wrapper, cnr) cid, err := s.wrt.Put(cnr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.invalidator.InvalidateContainerList(cnr.OwnerID())
res := new(container.PutResponseBody) res := new(container.PutResponseBody)
res.SetContainerID(cid.ToV2()) res.SetContainerID(cid.ToV2())
@ -95,18 +82,11 @@ func (s *morphExecutor) Delete(ctx containerSvc.ContextWithToken, body *containe
rmWitness.SetSignature(sig) rmWitness.SetSignature(sig)
rmWitness.SetSessionToken(tok) rmWitness.SetSessionToken(tok)
err := wrapper.Delete(s.wrapper, rmWitness) err := s.wrt.Delete(rmWitness)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.invalidator.InvalidateContainer(id)
s.invalidator.InvalidateEACL(id)
// it is faster to use slower invalidation by CID than making separate
// network request to fetch owner ID of the container.
s.invalidator.InvalidateContainerListByCID(id)
return new(container.DeleteResponseBody), nil return new(container.DeleteResponseBody), nil
} }
@ -155,13 +135,11 @@ func (s *morphExecutor) SetExtendedACL(ctx containerSvc.ContextWithToken, body *
session.NewTokenFromV2(ctx.SessionToken), session.NewTokenFromV2(ctx.SessionToken),
) )
err := wrapper.PutEACL(s.wrapper, table) err := s.wrt.PutEACL(table)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.invalidator.InvalidateEACL(table.CID())
return new(container.SetExtendedACLResponseBody), nil return new(container.SetExtendedACLResponseBody), nil
} }