mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-22 19:19:18 -05:00
+10
-2
@@ -56,9 +56,11 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/filelocks"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/templates"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/store"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/jellydator/ttlcache/v2"
|
||||
"github.com/pkg/errors"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -117,8 +119,14 @@ func NewDefault(m map[string]interface{}, bs tree.Blobstore, es events.Stream) (
|
||||
return nil, fmt.Errorf("unknown metadata backend %s, only 'messagepack' or 'xattrs' (default) supported", o.MetadataBackend)
|
||||
}
|
||||
|
||||
tp := tree.New(lu, bs, o)
|
||||
|
||||
tp := tree.New(lu, bs, o, store.Create(
|
||||
store.Store(o.IDCache.Store),
|
||||
store.TTL(time.Duration(o.IDCache.TTL)*time.Second),
|
||||
store.Size(o.IDCache.Size),
|
||||
microstore.Nodes(o.IDCache.Nodes...),
|
||||
microstore.Database(o.IDCache.Database),
|
||||
microstore.Table(o.IDCache.Table),
|
||||
))
|
||||
permissionsClient, err := pool.GetPermissionsClient(o.PermissionsSVC, pool.WithTLSMode(o.PermTLSMode))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+13
-1
@@ -88,6 +88,12 @@ func (n *Node) RemoveXattr(key string) error {
|
||||
// XattrsWithReader returns the extended attributes of the node. If the attributes have already
|
||||
// been cached they are not read from disk again.
|
||||
func (n *Node) XattrsWithReader(r io.Reader) (Attributes, error) {
|
||||
if n.ID == "" {
|
||||
// Do not try to read the attribute of an empty node. The InternalPath points to the
|
||||
// base nodes directory in this case.
|
||||
return Attributes{}, &xattr.Error{Op: "node.XattrsWithReader", Path: n.InternalPath(), Err: xattr.ENOATTR}
|
||||
}
|
||||
|
||||
if n.xattrsCache != nil {
|
||||
return n.xattrsCache, nil
|
||||
}
|
||||
@@ -116,6 +122,12 @@ func (n *Node) Xattrs() (Attributes, error) {
|
||||
// Xattr returns an extended attribute of the node. If the attributes have already
|
||||
// been cached it is not read from disk again.
|
||||
func (n *Node) Xattr(key string) ([]byte, error) {
|
||||
if n.ID == "" {
|
||||
// Do not try to read the attribute of an empty node. The InternalPath points to the
|
||||
// base nodes directory in this case.
|
||||
return []byte{}, &xattr.Error{Op: "node.Xattr", Path: n.InternalPath(), Name: key, Err: xattr.ENOATTR}
|
||||
}
|
||||
|
||||
if n.xattrsCache == nil {
|
||||
attrs, err := n.lu.MetadataBackend().All(n.InternalPath())
|
||||
if err != nil {
|
||||
@@ -128,7 +140,7 @@ func (n *Node) Xattr(key string) ([]byte, error) {
|
||||
return val, nil
|
||||
}
|
||||
// wrap the error as xattr does
|
||||
return []byte{}, &xattr.Error{Op: "xattr.get", Path: n.InternalPath(), Name: key, Err: xattr.ENOATTR}
|
||||
return []byte{}, &xattr.Error{Op: "node.Xattr", Path: n.InternalPath(), Name: key, Err: xattr.ENOATTR}
|
||||
}
|
||||
|
||||
// XattrString returns the string representation of an attribute
|
||||
|
||||
Generated
Vendored
+1
@@ -69,6 +69,7 @@ type Options struct {
|
||||
|
||||
StatCache cache.Config `mapstructure:"statcache"`
|
||||
FileMetadataCache cache.Config `mapstructure:"filemetadatacache"`
|
||||
IDCache cache.Config `mapstructure:"idcache"`
|
||||
|
||||
MaxAcquireLockCycles int `mapstructure:"max_acquire_lock_cycles"`
|
||||
LockCycleDurationFactor int `mapstructure:"lock_cycle_duration_factor"`
|
||||
|
||||
+30
-14
@@ -32,7 +32,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bluele/gcache"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
@@ -47,6 +46,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
"github.com/rs/zerolog/log"
|
||||
"go-micro.dev/v4/store"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -80,19 +80,19 @@ type Tree struct {
|
||||
|
||||
options *options.Options
|
||||
|
||||
idCache gcache.Cache
|
||||
idCache store.Store
|
||||
}
|
||||
|
||||
// PermissionCheckFunc defined a function used to check resource permissions
|
||||
type PermissionCheckFunc func(rp *provider.ResourcePermissions) bool
|
||||
|
||||
// New returns a new instance of Tree
|
||||
func New(lu PathLookup, bs Blobstore, o *options.Options) *Tree {
|
||||
func New(lu PathLookup, bs Blobstore, o *options.Options, cache store.Store) *Tree {
|
||||
return &Tree{
|
||||
lookup: lu,
|
||||
blobstore: bs,
|
||||
options: o,
|
||||
idCache: gcache.New(1_000_000).LRU().Build(),
|
||||
idCache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +234,9 @@ func (t *Tree) Move(ctx context.Context, oldNode *node.Node, newNode *node.Node)
|
||||
}
|
||||
}
|
||||
|
||||
// remove cache entry in any case to avoid inconsistencies
|
||||
defer func() { _ = t.idCache.Delete(filepath.Join(oldNode.ParentPath(), oldNode.Name)) }()
|
||||
|
||||
// Always target the old node ID for xattr updates.
|
||||
// The new node id is empty if the target does not exist
|
||||
// and we need to overwrite the new one when overwriting an existing path.
|
||||
@@ -271,7 +274,6 @@ func (t *Tree) Move(ctx context.Context, oldNode *node.Node, newNode *node.Node)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Decomposedfs: could not move child")
|
||||
}
|
||||
t.idCache.Remove(filepath.Join(oldNode.ParentPath(), oldNode.Name))
|
||||
|
||||
// update target parentid and name
|
||||
attribs := node.Attributes{}
|
||||
@@ -361,16 +363,14 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
g.Go(func() error {
|
||||
for name := range work {
|
||||
nodeID := ""
|
||||
path := filepath.Join(dir, name)
|
||||
if val, err := t.idCache.Get(path); err == nil {
|
||||
nodeID = val.(string)
|
||||
} else {
|
||||
nodeID := getNodeIDFromCache(path, t.idCache)
|
||||
if nodeID == "" {
|
||||
nodeID, err = readChildNodeFromLink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = t.idCache.Set(path, nodeID)
|
||||
err = storeNodeIDInCache(path, nodeID, t.idCache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -416,6 +416,10 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro
|
||||
|
||||
// Delete deletes a node in the tree by moving it to the trash
|
||||
func (t *Tree) Delete(ctx context.Context, n *node.Node) (err error) {
|
||||
path := filepath.Join(n.ParentPath(), n.Name)
|
||||
// remove entry from cache immediately to avoid inconsistencies
|
||||
defer func() { _ = t.idCache.Delete(path) }()
|
||||
|
||||
deletingSharedResource := ctx.Value(appctx.DeletingSharedResource)
|
||||
|
||||
if deletingSharedResource != nil && deletingSharedResource.(bool) {
|
||||
@@ -492,10 +496,7 @@ func (t *Tree) Delete(ctx context.Context, n *node.Node) (err error) {
|
||||
_ = os.Remove(n.LockFilePath())
|
||||
|
||||
// finally remove the entry from the parent dir
|
||||
path := filepath.Join(n.ParentPath(), n.Name)
|
||||
err = os.Remove(path)
|
||||
t.idCache.Remove(path)
|
||||
if err != nil {
|
||||
if err = os.Remove(path); err != nil {
|
||||
// To roll back changes
|
||||
// TODO revert the rename
|
||||
// TODO remove symlink
|
||||
@@ -980,3 +981,18 @@ func (t *Tree) readRecycleItem(ctx context.Context, spaceID, key, path string) (
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getNodeIDFromCache(path string, cache store.Store) string {
|
||||
recs, err := cache.Read(path)
|
||||
if err == nil && len(recs) > 0 {
|
||||
return string(recs[0].Value)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func storeNodeIDInCache(path string, nodeID string, cache store.Store) error {
|
||||
return cache.Write(&store.Record{
|
||||
Key: path,
|
||||
Value: []byte(nodeID),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user