Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor decomposedfs to be more extensible, e.g. for the posix driver #4581

Merged
merged 8 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/extensible-decomposedfs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Make decomposedfs more extensible

We refactored decomposedfs to make it more extensible, e.g. for the posixfs storage driver.

https://github.com/cs3org/reva/pull/4581
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ require (
github.com/golang/glog v1.1.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/hashicorp/consul/api v1.15.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
Expand Down
4 changes: 3 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1164,8 +1164,9 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0 h1:zHs+jv3LO743/zFGcByu2KmpbliCU2AhjcGgrdTwSG4=
github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
Expand Down Expand Up @@ -1276,6 +1277,7 @@ github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSAS
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
Expand Down
11 changes: 11 additions & 0 deletions pkg/storage/fs/posix/lookup/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ func (lu *Lookup) TypeFromPath(ctx context.Context, path string) provider.Resour
return t
}

func (lu *Lookup) NodeIDFromParentAndName(ctx context.Context, parent *node.Node, name string) (string, error) {
id, err := lu.metadataBackend.Get(ctx, filepath.Join(parent.InternalPath(), name), prefixes.IDAttr)
if err != nil {
if metadata.IsNotExist(err) {
return "", errtypes.NotFound(name)
}
return "", err
}
return string(id), nil
}

// NodeFromResource takes in a request path or request id and converts it to a Node
func (lu *Lookup) NodeFromResource(ctx context.Context, ref *provider.Reference) (*node.Node, error) {
ctx, span := tracer.Start(ctx, "NodeFromResource")
Expand Down
38 changes: 38 additions & 0 deletions pkg/storage/fs/posix/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options"
Expand Down Expand Up @@ -687,6 +688,43 @@ func (t *Tree) DeleteBlob(node *node.Node) error {
return t.blobstore.Delete(node)
}

// BuildSpaceIDIndexEntry returns the entry for the space id index
func (t *Tree) BuildSpaceIDIndexEntry(spaceID, nodeID string) string {
return nodeID
}

// ResolveSpaceIDIndexEntry returns the node id for the space id index entry
func (t *Tree) ResolveSpaceIDIndexEntry(spaceid, entry string) (string, string, error) {
return spaceid, entry, nil
}

// InitNewNode initializes a new node
func (t *Tree) InitNewNode(ctx context.Context, n *node.Node, fsize uint64) (metadata.UnlockFunc, error) {
// create folder structure (if needed)
if err := os.MkdirAll(filepath.Dir(n.InternalPath()), 0700); err != nil {
return nil, err
}

// create and write lock new node metadata
unlock, err := t.lookup.MetadataBackend().Lock(n.InternalPath())
if err != nil {
return nil, err
}

// we also need to touch the actual node file here it stores the mtime of the resource
h, err := os.OpenFile(n.InternalPath(), os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
return unlock, err
}
h.Close()

if _, err := node.CheckQuota(ctx, n.SpaceRoot, false, 0, fsize); err != nil {
return unlock, err
}

return unlock, nil
}

// TODO check if node exists?
func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) {
ctx, span := tracer.Start(ctx, "createDirNode")
Expand Down
9 changes: 5 additions & 4 deletions pkg/storage/utils/decomposedfs/aspects/aspects.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import (

// Aspects holds dependencies for handling aspects of the decomposedfs
type Aspects struct {
Lookup node.PathLookup
Tree node.Tree
Permissions permissions.Permissions
EventStream events.Stream
Lookup node.PathLookup
Tree node.Tree
Permissions permissions.Permissions
EventStream events.Stream
DisableVersioning bool
}
2 changes: 1 addition & 1 deletion pkg/storage/utils/decomposedfs/decomposedfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func New(o *options.Options, aspects aspects.Aspects) (storage.FS, error) {
userSpaceIndex: userSpaceIndex,
groupSpaceIndex: groupSpaceIndex,
spaceTypeIndex: spaceTypeIndex,
sessionStore: upload.NewSessionStore(aspects.Lookup, aspects.Tree, o.Root, aspects.EventStream, o.AsyncFileUploads, o.Tokens),
sessionStore: upload.NewSessionStore(aspects.Lookup, aspects.Tree, o.Root, aspects.EventStream, o.AsyncFileUploads, o.Tokens, aspects.DisableVersioning),
}

if o.AsyncFileUploads {
Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/utils/decomposedfs/grants.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ func (fs *Decomposedfs) storeGrant(ctx context.Context, n *node.Node, g *provide
}

// update the indexes only after successfully setting the grant
err := fs.updateIndexes(ctx, g.GetGrantee(), spaceType, n.ID)
err := fs.updateIndexes(ctx, g.GetGrantee(), spaceType, n.SpaceID, n.ID)
if err != nil {
return err
}
Expand Down
17 changes: 17 additions & 0 deletions pkg/storage/utils/decomposedfs/lookup/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ func (lu *Lookup) ReadBlobIDAttr(ctx context.Context, path string) (string, erro
}
return string(attr), nil
}
func readChildNodeFromLink(path string) (string, error) {
link, err := os.Readlink(path)
if err != nil {
return "", err
}
nodeID := strings.TrimLeft(link, "/.")
nodeID = strings.ReplaceAll(nodeID, "/", "")
return nodeID, nil
}

func (lu *Lookup) NodeIDFromParentAndName(ctx context.Context, parent *node.Node, name string) (string, error) {
nodeID, err := readChildNodeFromLink(filepath.Join(parent.InternalPath(), name))
if err != nil {
return "", errors.Wrap(err, "decomposedfs: Wrap: readlink error")
}
return nodeID, nil
}

// TypeFromPath returns the type of the node at the given path
func (lu *Lookup) TypeFromPath(ctx context.Context, path string) provider.ResourceType {
Expand Down
11 changes: 11 additions & 0 deletions pkg/storage/utils/decomposedfs/metadata/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package metadata

import (
"io/fs"
"os"
"syscall"

Expand Down Expand Up @@ -50,3 +51,13 @@ func IsAttrUnset(err error) bool {
}
return false
}

// The os error is buried inside the fs.PathError error
func IsNotDir(err error) bool {
if perr, ok := errors.Cause(err).(*fs.PathError); ok {
if serr, ok2 := perr.Err.(syscall.Errno); ok2 {
return serr == syscall.ENOTDIR
}
}
return false
}
16 changes: 16 additions & 0 deletions pkg/storage/utils/decomposedfs/metadata/messagepack_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,22 @@ func (MessagePackBackend) MetadataPath(path string) string { return path + ".mpk
// LockfilePath returns the path of the lock file
func (MessagePackBackend) LockfilePath(path string) string { return path + ".mlock" }

// Lock locks the metadata for the given path
func (b MessagePackBackend) Lock(path string) (UnlockFunc, error) {
metaLockPath := b.LockfilePath(path)
mlock, err := lockedfile.OpenFile(metaLockPath, os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
return nil, err
}
return func() error {
err := mlock.Close()
if err != nil {
return err
}
return os.Remove(metaLockPath)
}, nil
}

func (b MessagePackBackend) cacheKey(path string) string {
// rootPath is guaranteed to have no trailing slash
// the cache key shouldn't begin with a slash as some stores drop it which can cause
Expand Down
8 changes: 8 additions & 0 deletions pkg/storage/utils/decomposedfs/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ func init() {

var errUnconfiguredError = errors.New("no metadata backend configured. Bailing out")

type UnlockFunc func() error

// Backend defines the interface for file attribute backends
type Backend interface {
Name() string
Expand All @@ -48,6 +50,7 @@ type Backend interface {
SetMultiple(ctx context.Context, path string, attribs map[string][]byte, acquireLock bool) error
Remove(ctx context.Context, path, key string, acquireLock bool) error

Lock(path string) (UnlockFunc, error)
Purge(path string) error
Rename(oldPath, newPath string) error
IsMetaFile(path string) bool
Expand Down Expand Up @@ -99,6 +102,11 @@ func (NullBackend) Remove(ctx context.Context, path string, key string, acquireL
return errUnconfiguredError
}

// Lock locks the metadata for the given path
func (NullBackend) Lock(path string) (UnlockFunc, error) {
return nil, nil
}

// IsMetaFile returns whether the given path represents a meta file
func (NullBackend) IsMetaFile(path string) bool { return false }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ package prefixes
// "user.ocis." in the xattrs_prefix*.go files.
const (
TypeAttr string = OcisPrefix + "type"
IDAttr string = OcisPrefix + "id"
ParentidAttr string = OcisPrefix + "parentid"
OwnerIDAttr string = OcisPrefix + "owner.id"
OwnerIDPAttr string = OcisPrefix + "owner.idp"
Expand Down Expand Up @@ -89,6 +90,7 @@ const (
QuotaAttr string = OcisPrefix + "quota"

// the name given to a storage space. It should not contain any semantics as its only purpose is to be read.
SpaceIDAttr string = OcisPrefix + "space.id"
SpaceNameAttr string = OcisPrefix + "space.name"
SpaceTypeAttr string = OcisPrefix + "space.type"
SpaceDescriptionAttr string = OcisPrefix + "space.description"
Expand Down
20 changes: 18 additions & 2 deletions pkg/storage/utils/decomposedfs/metadata/xattrs_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ func (b XattrsBackend) Set(ctx context.Context, path string, key string, val []b
}

// SetMultiple sets a set of attribute for the given path
func (XattrsBackend) SetMultiple(ctx context.Context, path string, attribs map[string][]byte, acquireLock bool) (err error) {
func (b XattrsBackend) SetMultiple(ctx context.Context, path string, attribs map[string][]byte, acquireLock bool) (err error) {
if acquireLock {
err := os.MkdirAll(filepath.Dir(path), 0600)
if err != nil {
return err
}
lockedFile, err := lockedfile.OpenFile(path+filelocks.LockFileSuffix, os.O_CREATE|os.O_WRONLY, 0600)
lockedFile, err := lockedfile.OpenFile(b.LockfilePath(path), os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return err
}
Expand Down Expand Up @@ -173,6 +173,22 @@ func (XattrsBackend) MetadataPath(path string) string { return path }
// LockfilePath returns the path of the lock file
func (XattrsBackend) LockfilePath(path string) string { return path + ".mlock" }

// Lock locks the metadata for the given path
func (b XattrsBackend) Lock(path string) (UnlockFunc, error) {
metaLockPath := b.LockfilePath(path)
mlock, err := lockedfile.OpenFile(metaLockPath, os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
return nil, err
}
return func() error {
err := mlock.Close()
if err != nil {
return err
}
return os.Remove(metaLockPath)
}, nil
}

func cleanupLockfile(f *lockedfile.File) {
_ = f.Close()
_ = os.Remove(f.Name())
Expand Down
Loading
Loading