Bump reva to get latest changes for LDAP client
This commit is contained in:
+3
-2
@@ -47,10 +47,11 @@
|
||||
package eos_grpc
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
+13
@@ -184,3 +184,16 @@ func (ResumePostprocessing) Unmarshal(v []byte) (interface{}, error) {
|
||||
err := json.Unmarshal(v, &e)
|
||||
return e, err
|
||||
}
|
||||
|
||||
// RestartPostprocessing will be emitted by postprocessing service if it doesn't know about an upload
|
||||
type RestartPostprocessing struct {
|
||||
UploadID string
|
||||
Timestamp *types.Timestamp
|
||||
}
|
||||
|
||||
// Unmarshal to fulfill umarshaller interface
|
||||
func (RestartPostprocessing) Unmarshal(v []byte) (interface{}, error) {
|
||||
e := RestartPostprocessing{}
|
||||
err := json.Unmarshal(v, &e)
|
||||
return e, err
|
||||
}
|
||||
|
||||
+1
@@ -52,6 +52,7 @@ func NatsFromConfig(cfg NatsConfig) (events.Stream, error) {
|
||||
natsjs.TLSConfig(tlsConf),
|
||||
natsjs.Address(cfg.Endpoint),
|
||||
natsjs.ClusterID(cfg.Cluster),
|
||||
natsjs.SynchronousPublish(true),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
+10
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/storage/favorite"
|
||||
"github.com/rs/zerolog"
|
||||
"go-micro.dev/v4/broker"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -54,6 +55,8 @@ type Options struct {
|
||||
TracingCollector string
|
||||
TracingEndpoint string
|
||||
|
||||
TraceProvider trace.TracerProvider
|
||||
|
||||
MetricsEnabled bool
|
||||
MetricsNamespace string
|
||||
MetricsSubsystem string
|
||||
@@ -234,6 +237,13 @@ func WithTracingExporter(exporter string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithTraceProvider option
|
||||
func WithTraceProvider(provider trace.TracerProvider) Option {
|
||||
return func(o *Options) {
|
||||
o.TraceProvider = provider
|
||||
}
|
||||
}
|
||||
|
||||
// Version provides a function to set the Version config option.
|
||||
func Version(val string) Option {
|
||||
return func(o *Options) {
|
||||
|
||||
+16
-14
@@ -51,7 +51,6 @@ const (
|
||||
|
||||
// Service initializes the ocdav service and underlying http server.
|
||||
func Service(opts ...Option) (micro.Service, error) {
|
||||
|
||||
sopts := newOptions(opts...)
|
||||
|
||||
// set defaults
|
||||
@@ -86,19 +85,23 @@ func Service(opts ...Option) (micro.Service, error) {
|
||||
// chi.RegisterMethod(ocdav.MethodMkcol)
|
||||
// chi.RegisterMethod(ocdav.MethodReport)
|
||||
r := chi.NewRouter()
|
||||
topts := []rtrace.Option{
|
||||
rtrace.WithExporter(sopts.TracingExporter),
|
||||
rtrace.WithEndpoint(sopts.TracingEndpoint),
|
||||
rtrace.WithCollector(sopts.TracingCollector),
|
||||
rtrace.WithServiceName(sopts.Name),
|
||||
tp := sopts.TraceProvider
|
||||
|
||||
if tp == nil {
|
||||
topts := []rtrace.Option{
|
||||
rtrace.WithExporter(sopts.TracingExporter),
|
||||
rtrace.WithEndpoint(sopts.TracingEndpoint),
|
||||
rtrace.WithCollector(sopts.TracingCollector),
|
||||
rtrace.WithServiceName(sopts.Name),
|
||||
}
|
||||
if sopts.TracingEnabled {
|
||||
topts = append(topts, rtrace.WithEnabled())
|
||||
}
|
||||
if sopts.TracingInsecure {
|
||||
topts = append(topts, rtrace.WithInsecure())
|
||||
}
|
||||
tp = rtrace.NewTracerProvider(topts...)
|
||||
}
|
||||
if sopts.TracingEnabled {
|
||||
topts = append(topts, rtrace.WithEnabled())
|
||||
}
|
||||
if sopts.TracingInsecure {
|
||||
topts = append(topts, rtrace.WithInsecure())
|
||||
}
|
||||
tp := rtrace.NewTracerProvider(topts...)
|
||||
if err := useMiddlewares(r, &sopts, revaService, tp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -132,7 +135,6 @@ func Service(opts ...Option) (micro.Service, error) {
|
||||
}
|
||||
|
||||
func setDefaults(sopts *Options) error {
|
||||
|
||||
// set defaults
|
||||
if sopts.Name == "" {
|
||||
sopts.Name = ServerName
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ import (
|
||||
var tracer trace.Tracer
|
||||
|
||||
func init() {
|
||||
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/utils/decomposedfs/lookup")
|
||||
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/cache")
|
||||
}
|
||||
|
||||
// NewStatCache creates a new StatCache
|
||||
|
||||
+70
-26
@@ -32,9 +32,9 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
@@ -48,9 +48,9 @@ import (
|
||||
"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/migrator"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/mtimesyncedcache"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaceidindex"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/filelocks"
|
||||
@@ -66,7 +66,15 @@ import (
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
var tracer trace.Tracer
|
||||
var (
|
||||
tracer trace.Tracer
|
||||
|
||||
_registeredEvents = []events.Unmarshaller{
|
||||
events.PostprocessingFinished{},
|
||||
events.PostprocessingStepFinished{},
|
||||
events.RestartPostprocessing{},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/utils/decomposedfs")
|
||||
@@ -104,8 +112,10 @@ type Decomposedfs struct {
|
||||
stream events.Stream
|
||||
cache cache.StatCache
|
||||
|
||||
UserCache *ttlcache.Cache
|
||||
spaceIDCache mtimesyncedcache.Cache[string, map[string]string]
|
||||
UserCache *ttlcache.Cache
|
||||
userSpaceIndex *spaceidindex.Index
|
||||
groupSpaceIndex *spaceidindex.Index
|
||||
spaceTypeIndex *spaceidindex.Index
|
||||
}
|
||||
|
||||
// NewDefault returns an instance with default components
|
||||
@@ -169,16 +179,34 @@ func New(o *options.Options, lu *lookup.Lookup, p Permissions, tp Tree, es event
|
||||
if o.LockCycleDurationFactor != 0 {
|
||||
filelocks.SetLockCycleDurationFactor(o.LockCycleDurationFactor)
|
||||
}
|
||||
userSpaceIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-user-id")
|
||||
err = userSpaceIndex.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupSpaceIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-group-id")
|
||||
err = groupSpaceIndex.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spaceTypeIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-type")
|
||||
err = spaceTypeIndex.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs := &Decomposedfs{
|
||||
tp: tp,
|
||||
lu: lu,
|
||||
o: o,
|
||||
p: p,
|
||||
chunkHandler: chunking.NewChunkHandler(filepath.Join(o.Root, "uploads")),
|
||||
stream: es,
|
||||
cache: cache.GetStatCache(o.StatCache.Store, o.StatCache.Nodes, o.StatCache.Database, "stat", time.Duration(o.StatCache.TTL)*time.Second, o.StatCache.Size),
|
||||
UserCache: ttlcache.NewCache(),
|
||||
tp: tp,
|
||||
lu: lu,
|
||||
o: o,
|
||||
p: p,
|
||||
chunkHandler: chunking.NewChunkHandler(filepath.Join(o.Root, "uploads")),
|
||||
stream: es,
|
||||
cache: cache.GetStatCache(o.StatCache.Store, o.StatCache.Nodes, o.StatCache.Database, "stat", time.Duration(o.StatCache.TTL)*time.Second, o.StatCache.Size),
|
||||
UserCache: ttlcache.NewCache(),
|
||||
userSpaceIndex: userSpaceIndex,
|
||||
groupSpaceIndex: groupSpaceIndex,
|
||||
spaceTypeIndex: spaceTypeIndex,
|
||||
}
|
||||
|
||||
if o.AsyncFileUploads {
|
||||
@@ -187,7 +215,7 @@ func New(o *options.Options, lu *lookup.Lookup, p Permissions, tp Tree, es event
|
||||
return nil, errors.New("need nats for async file processing")
|
||||
}
|
||||
|
||||
ch, err := events.Consume(fs.stream, "dcfs", events.PostprocessingFinished{}, events.PostprocessingStepFinished{})
|
||||
ch, err := events.Consume(fs.stream, "dcfs", _registeredEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -285,7 +313,34 @@ func (fs *Decomposedfs) Postprocessing(ch <-chan events.Event) {
|
||||
); err != nil {
|
||||
log.Error().Err(err).Str("uploadID", ev.UploadID).Msg("Failed to publish UploadReady event")
|
||||
}
|
||||
|
||||
case events.RestartPostprocessing:
|
||||
up, err := upload.Get(ctx, ev.UploadID, fs.lu, fs.tp, fs.o.Root, fs.stream, fs.o.AsyncFileUploads, fs.o.Tokens)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("uploadID", ev.UploadID).Msg("Failed to get upload")
|
||||
continue
|
||||
}
|
||||
n, err := node.ReadNode(ctx, fs.lu, up.Info.Storage["SpaceRoot"], up.Info.Storage["NodeId"], false, nil, true)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("uploadID", ev.UploadID).Msg("could not read node")
|
||||
continue
|
||||
}
|
||||
s, err := up.URL(up.Ctx)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("uploadID", ev.UploadID).Msg("could not create url")
|
||||
continue
|
||||
}
|
||||
// restart postprocessing
|
||||
if err := events.Publish(fs.stream, events.BytesReceived{
|
||||
UploadID: up.Info.ID,
|
||||
URL: s,
|
||||
SpaceOwner: n.SpaceOwnerOrManager(up.Ctx),
|
||||
ExecutingUser: &user.User{Id: &user.UserId{OpaqueId: "postprocessing-restart"}}, // send nil instead?
|
||||
ResourceID: &provider.ResourceId{SpaceId: n.SpaceID, OpaqueId: n.ID},
|
||||
Filename: up.Info.Storage["NodeName"],
|
||||
Filesize: uint64(up.Info.Size),
|
||||
}); err != nil {
|
||||
log.Error().Err(err).Str("uploadID", ev.UploadID).Msg("Failed to publish BytesReceived event")
|
||||
}
|
||||
case events.PostprocessingStepFinished:
|
||||
if ev.FinishedStep != events.PPStepAntivirus {
|
||||
// atm we are only interested in antivirus results
|
||||
@@ -515,17 +570,6 @@ func (fs *Decomposedfs) CreateHome(ctx context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The os not exists error is buried inside the xattr error,
|
||||
// so we cannot just use os.IsNotExists().
|
||||
func isAlreadyExists(err error) bool {
|
||||
if xerr, ok := err.(*os.LinkError); ok {
|
||||
if serr, ok2 := xerr.Err.(syscall.Errno); ok2 {
|
||||
return serr == syscall.EEXIST
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetHome is called to look up the home path for a user
|
||||
// It is NOT supposed to return the internal path but the external path
|
||||
func (fs *Decomposedfs) GetHome(ctx context.Context) (string, error) {
|
||||
|
||||
+2
-5
@@ -20,7 +20,6 @@ package decomposedfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -220,14 +219,12 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
|
||||
switch {
|
||||
case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
|
||||
// remove from user index
|
||||
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().GetOpaqueId(), grantNode.SpaceID)
|
||||
if err := os.Remove(userIDPath); err != nil {
|
||||
if err := fs.userSpaceIndex.Remove(g.Grantee.GetUserId().GetOpaqueId(), grantNode.SpaceID); err != nil {
|
||||
return err
|
||||
}
|
||||
case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
|
||||
// remove from group index
|
||||
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-group-id", g.Grantee.GetGroupId().GetOpaqueId(), grantNode.SpaceID)
|
||||
if err := os.Remove(userIDPath); err != nil {
|
||||
if err := fs.groupSpaceIndex.Remove(g.Grantee.GetGroupId().GetOpaqueId(), grantNode.SpaceID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -284,7 +284,7 @@ func refFromCS3(b []byte) (*provider.Reference, error) {
|
||||
func (lu *Lookup) CopyMetadata(ctx context.Context, src, target string, filter func(attributeName string) bool) (err error) {
|
||||
// Acquire a read log on the source node
|
||||
// write lock existing node before reading treesize or tree time
|
||||
f, err := lockedfile.Open(lu.MetadataBackend().MetadataPath(src))
|
||||
lock, err := lockedfile.OpenFile(lu.MetadataBackend().LockfilePath(src), os.O_RDONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -293,7 +293,7 @@ func (lu *Lookup) CopyMetadata(ctx context.Context, src, target string, filter f
|
||||
return errors.Wrap(err, "xattrs: Unable to lock source to read")
|
||||
}
|
||||
defer func() {
|
||||
rerr := f.Close()
|
||||
rerr := lock.Close()
|
||||
|
||||
// if err is non nil we do not overwrite that
|
||||
if err == nil {
|
||||
@@ -301,7 +301,7 @@ func (lu *Lookup) CopyMetadata(ctx context.Context, src, target string, filter f
|
||||
}
|
||||
}()
|
||||
|
||||
return lu.CopyMetadataWithSourceLock(ctx, src, target, filter, f)
|
||||
return lu.CopyMetadataWithSourceLock(ctx, src, target, filter, lock)
|
||||
}
|
||||
|
||||
// CopyMetadataWithSourceLock copies all extended attributes from source to target.
|
||||
@@ -312,11 +312,11 @@ func (lu *Lookup) CopyMetadataWithSourceLock(ctx context.Context, sourcePath, ta
|
||||
switch {
|
||||
case lockedSource == nil:
|
||||
return errors.New("no lock provided")
|
||||
case lockedSource.File.Name() != lu.MetadataBackend().MetadataPath(sourcePath):
|
||||
case lockedSource.File.Name() != lu.MetadataBackend().LockfilePath(sourcePath):
|
||||
return errors.New("lockpath does not match filepath")
|
||||
}
|
||||
|
||||
attrs, err := lu.metadataBackend.AllWithLockedSource(ctx, sourcePath, lockedSource)
|
||||
attrs, err := lu.metadataBackend.All(ctx, sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Generated
Vendored
+45
-43
@@ -20,7 +20,9 @@ package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -28,6 +30,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cs3org/reva/v2/pkg/storage/cache"
|
||||
"github.com/google/renameio/v2"
|
||||
"github.com/pkg/xattr"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
@@ -142,74 +145,60 @@ func (b MessagePackBackend) saveAttributes(ctx context.Context, path string, set
|
||||
span.End()
|
||||
}()
|
||||
|
||||
lockPath := b.LockfilePath(path)
|
||||
metaPath := b.MetadataPath(path)
|
||||
if acquireLock {
|
||||
_, subspan := tracer.Start(ctx, "lockedfile.OpenFile")
|
||||
f, err = lockedfile.OpenFile(metaPath, os.O_RDWR|os.O_CREATE, 0600)
|
||||
subspan.End()
|
||||
} else {
|
||||
_, subspan := tracer.Start(ctx, "os.OpenFile")
|
||||
f, err = os.OpenFile(metaPath, os.O_RDWR|os.O_CREATE, 0600)
|
||||
f, err = lockedfile.OpenFile(lockPath, os.O_RDWR|os.O_CREATE, 0600)
|
||||
subspan.End()
|
||||
defer f.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Invalidate cache early
|
||||
_, subspan := tracer.Start(ctx, "metaCache.RemoveMetadata")
|
||||
_ = b.metaCache.RemoveMetadata(b.cacheKey(path))
|
||||
subspan.End()
|
||||
|
||||
// Read current state
|
||||
_, subspan = tracer.Start(ctx, "io.ReadAll")
|
||||
_, subspan := tracer.Start(ctx, "os.ReadFile")
|
||||
var msgBytes []byte
|
||||
msgBytes, err = io.ReadAll(f)
|
||||
msgBytes, err = os.ReadFile(metaPath)
|
||||
subspan.End()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attribs := map[string][]byte{}
|
||||
if len(msgBytes) > 0 {
|
||||
switch {
|
||||
case err != nil:
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
case len(msgBytes) == 0:
|
||||
// ugh. an empty file? bail out
|
||||
return errors.New("encountered empty metadata file")
|
||||
default:
|
||||
// only unmarshal if we read data
|
||||
err = msgpack.Unmarshal(msgBytes, &attribs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// set new metadata
|
||||
// prepare metadata
|
||||
for key, val := range setAttribs {
|
||||
attribs[key] = val
|
||||
}
|
||||
for _, key := range deleteAttribs {
|
||||
delete(attribs, key)
|
||||
}
|
||||
|
||||
// Truncate file
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, subspan = tracer.Start(ctx, "f.Truncate")
|
||||
err = f.Truncate(0)
|
||||
subspan.End()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write new metadata to file
|
||||
var d []byte
|
||||
d, err = msgpack.Marshal(attribs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, subspan = tracer.Start(ctx, "f.Write")
|
||||
_, err = f.Write(d)
|
||||
subspan.End()
|
||||
|
||||
// overwrite file atomically
|
||||
_, subspan = tracer.Start(ctx, "renameio.Writefile")
|
||||
err = renameio.WriteFile(metaPath, d, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
subspan.End()
|
||||
|
||||
_, subspan = tracer.Start(ctx, "metaCache.PushToCache")
|
||||
err = b.metaCache.PushToCache(b.cacheKey(path), attribs)
|
||||
@@ -227,9 +216,13 @@ func (b MessagePackBackend) loadAttributes(ctx context.Context, path string, sou
|
||||
}
|
||||
|
||||
metaPath := b.MetadataPath(path)
|
||||
var msgBytes []byte
|
||||
|
||||
if source == nil {
|
||||
_, subspan := tracer.Start(ctx, "lockedfile.Open")
|
||||
source, err = lockedfile.Open(metaPath)
|
||||
// // No cached entry found. Read from storage and store in cache
|
||||
_, subspan := tracer.Start(ctx, "os.OpenFile")
|
||||
// source, err = lockedfile.Open(metaPath)
|
||||
source, err = os.Open(metaPath)
|
||||
subspan.End()
|
||||
// // No cached entry found. Read from storage and store in cache
|
||||
if err != nil {
|
||||
@@ -246,12 +239,16 @@ func (b MessagePackBackend) loadAttributes(ctx context.Context, path string, sou
|
||||
return attribs, nil // no attributes set yet
|
||||
}
|
||||
}
|
||||
defer source.(*lockedfile.File).Close()
|
||||
_, subspan = tracer.Start(ctx, "io.ReadAll")
|
||||
msgBytes, err = io.ReadAll(source)
|
||||
source.(*os.File).Close()
|
||||
subspan.End()
|
||||
} else {
|
||||
_, subspan := tracer.Start(ctx, "io.ReadAll")
|
||||
msgBytes, err = io.ReadAll(source)
|
||||
subspan.End()
|
||||
}
|
||||
|
||||
_, subspan := tracer.Start(ctx, "io.ReadAll")
|
||||
msgBytes, err := io.ReadAll(source)
|
||||
subspan.End()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -262,7 +259,7 @@ func (b MessagePackBackend) loadAttributes(ctx context.Context, path string, sou
|
||||
}
|
||||
}
|
||||
|
||||
_, subspan = tracer.Start(ctx, "metaCache.PushToCache")
|
||||
_, subspan := tracer.Start(ctx, "metaCache.PushToCache")
|
||||
err = b.metaCache.PushToCache(b.cacheKey(path), attribs)
|
||||
subspan.End()
|
||||
if err != nil {
|
||||
@@ -273,7 +270,9 @@ func (b MessagePackBackend) loadAttributes(ctx context.Context, path string, sou
|
||||
}
|
||||
|
||||
// IsMetaFile returns whether the given path represents a meta file
|
||||
func (MessagePackBackend) IsMetaFile(path string) bool { return strings.HasSuffix(path, ".mpk") }
|
||||
func (MessagePackBackend) IsMetaFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".mpk") || strings.HasSuffix(path, ".mlock")
|
||||
}
|
||||
|
||||
// Purge purges the data of a given path
|
||||
func (b MessagePackBackend) Purge(path string) error {
|
||||
@@ -304,6 +303,9 @@ func (b MessagePackBackend) Rename(oldPath, newPath string) error {
|
||||
// MetadataPath returns the path of the file holding the metadata for the given path
|
||||
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" }
|
||||
|
||||
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
|
||||
|
||||
Generated
Vendored
+4
@@ -52,6 +52,7 @@ type Backend interface {
|
||||
Rename(oldPath, newPath string) error
|
||||
IsMetaFile(path string) bool
|
||||
MetadataPath(path string) string
|
||||
LockfilePath(path string) string
|
||||
|
||||
AllWithLockedSource(ctx context.Context, path string, source io.Reader) (map[string][]byte, error)
|
||||
}
|
||||
@@ -110,6 +111,9 @@ func (NullBackend) Rename(oldPath, newPath string) error { return errUnconfigure
|
||||
// MetadataPath returns the path of the file holding the metadata for the given path
|
||||
func (NullBackend) MetadataPath(path string) string { return "" }
|
||||
|
||||
// LockfilePath returns the path of the lock file
|
||||
func (NullBackend) LockfilePath(path string) string { return "" }
|
||||
|
||||
// AllWithLockedSource reads all extended attributes from the given reader
|
||||
// The path argument is used for storing the data in the cache
|
||||
func (NullBackend) AllWithLockedSource(ctx context.Context, path string, source io.Reader) (map[string][]byte, error) {
|
||||
|
||||
Generated
Vendored
+5
-1
@@ -24,6 +24,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/filelocks"
|
||||
"github.com/pkg/errors"
|
||||
@@ -156,7 +157,7 @@ func (XattrsBackend) Remove(ctx context.Context, filePath string, key string) (e
|
||||
}
|
||||
|
||||
// IsMetaFile returns whether the given path represents a meta file
|
||||
func (XattrsBackend) IsMetaFile(path string) bool { return false }
|
||||
func (XattrsBackend) IsMetaFile(path string) bool { return strings.HasSuffix(path, ".meta.lock") }
|
||||
|
||||
// Purge purges the data of a given path
|
||||
func (XattrsBackend) Purge(path string) error { return nil }
|
||||
@@ -167,6 +168,9 @@ func (XattrsBackend) Rename(oldPath, newPath string) error { return nil }
|
||||
// MetadataPath returns the path of the file holding the metadata for the given path
|
||||
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" }
|
||||
|
||||
func cleanupLockfile(f *lockedfile.File) {
|
||||
_ = f.Close()
|
||||
_ = os.Remove(f.Name())
|
||||
|
||||
Generated
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
// Copyright 2018-2023 CERN
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// In applying this license, CERN does not waive the privileges and immunities
|
||||
// granted to it by virtue of its status as an Intergovernmental Organization
|
||||
// or submit itself to any jurisdiction.
|
||||
|
||||
package migrator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
)
|
||||
|
||||
// Migration0004 migrates the directory tree based space indexes to messagepack
|
||||
func (m *Migrator) Migration0004() (Result, error) {
|
||||
root := m.lu.InternalRoot()
|
||||
|
||||
// migrate user indexes
|
||||
users, err := os.ReadDir(filepath.Join(root, "indexes", "by-user-id"))
|
||||
if err != nil {
|
||||
m.log.Warn().Err(err).Msg("error listing user indexes")
|
||||
}
|
||||
for _, user := range users {
|
||||
if !user.IsDir() {
|
||||
continue
|
||||
}
|
||||
id := user.Name()
|
||||
indexPath := filepath.Join(root, "indexes", "by-user-id", id+".mpk")
|
||||
dirIndexPath := filepath.Join(root, "indexes", "by-user-id", id)
|
||||
cacheKey := "by-user-id:" + id
|
||||
|
||||
m.log.Info().Str("root", m.lu.InternalRoot()).Msg("Migrating " + indexPath + " to messagepack index format...")
|
||||
err := migrateSpaceIndex(indexPath, dirIndexPath, cacheKey)
|
||||
if err != nil {
|
||||
m.log.Error().Err(err).Str("path", dirIndexPath).Msg("error migrating index")
|
||||
}
|
||||
}
|
||||
|
||||
// migrate group indexes
|
||||
groups, err := os.ReadDir(filepath.Join(root, "indexes", "by-group-id"))
|
||||
if err != nil {
|
||||
m.log.Warn().Err(err).Msg("error listing group indexes")
|
||||
}
|
||||
for _, group := range groups {
|
||||
if !group.IsDir() {
|
||||
continue
|
||||
}
|
||||
id := group.Name()
|
||||
indexPath := filepath.Join(root, "indexes", "by-group-id", id+".mpk")
|
||||
dirIndexPath := filepath.Join(root, "indexes", "by-group-id", id)
|
||||
cacheKey := "by-group-id:" + id
|
||||
|
||||
m.log.Info().Str("root", m.lu.InternalRoot()).Msg("Migrating " + indexPath + " to messagepack index format...")
|
||||
err := migrateSpaceIndex(indexPath, dirIndexPath, cacheKey)
|
||||
if err != nil {
|
||||
m.log.Error().Err(err).Str("path", dirIndexPath).Msg("error migrating index")
|
||||
}
|
||||
}
|
||||
|
||||
// migrate project indexes
|
||||
for _, spaceType := range []string{"personal", "project", "share"} {
|
||||
indexPath := filepath.Join(root, "indexes", "by-type", spaceType+".mpk")
|
||||
dirIndexPath := filepath.Join(root, "indexes", "by-type", spaceType)
|
||||
cacheKey := "by-type:" + spaceType
|
||||
|
||||
_, err := os.Stat(dirIndexPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
m.log.Info().Str("root", m.lu.InternalRoot()).Msg("Migrating " + indexPath + " to messagepack index format...")
|
||||
err = migrateSpaceIndex(indexPath, dirIndexPath, cacheKey)
|
||||
if err != nil {
|
||||
m.log.Error().Err(err).Str("path", dirIndexPath).Msg("error migrating index")
|
||||
}
|
||||
}
|
||||
|
||||
m.log.Info().Msg("done.")
|
||||
return resultSucceeded, nil
|
||||
}
|
||||
|
||||
func migrateSpaceIndex(indexPath, dirIndexPath, cacheKey string) error {
|
||||
links := map[string][]byte{}
|
||||
m, err := filepath.Glob(dirIndexPath + "/*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range m {
|
||||
link, err := os.Readlink(match)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
links[filepath.Base(match)] = []byte(link)
|
||||
}
|
||||
|
||||
// rewrite index as file
|
||||
d, err := msgpack.Marshal(links)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(indexPath, d, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.RemoveAll(dirIndexPath)
|
||||
}
|
||||
Generated
Vendored
+1
-1
@@ -29,7 +29,7 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var allMigrations = []string{"0001", "0002", "0003"}
|
||||
var allMigrations = []string{"0001", "0002", "0003", "0004"}
|
||||
|
||||
const (
|
||||
resultFailed = "failed"
|
||||
|
||||
+3
-3
@@ -70,7 +70,7 @@ func (fs *Decomposedfs) ListRevisions(ctx context.Context, ref *provider.Referen
|
||||
np := n.InternalPath()
|
||||
if items, err := filepath.Glob(np + node.RevisionIDDelimiter + "*"); err == nil {
|
||||
for i := range items {
|
||||
if fs.lu.MetadataBackend().IsMetaFile(items[i]) {
|
||||
if fs.lu.MetadataBackend().IsMetaFile(items[i]) || strings.HasSuffix(items[i], ".mlock") {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ func (fs *Decomposedfs) RestoreRevision(ctx context.Context, ref *provider.Refer
|
||||
attributeName == prefixes.BlobsizeAttr
|
||||
})
|
||||
if err != nil {
|
||||
return errtypes.InternalError("failed to copy blob xattrs to version node")
|
||||
return errtypes.InternalError("failed to copy blob xattrs to version node: " + err.Error())
|
||||
}
|
||||
|
||||
// remember mtime from node as new revision mtime
|
||||
@@ -256,7 +256,7 @@ func (fs *Decomposedfs) RestoreRevision(ctx context.Context, ref *provider.Refer
|
||||
attributeName == prefixes.BlobsizeAttr
|
||||
})
|
||||
if err != nil {
|
||||
return errtypes.InternalError("failed to copy blob xattrs to old revision to node")
|
||||
return errtypes.InternalError("failed to copy blob xattrs to old revision to node: " + err.Error())
|
||||
}
|
||||
|
||||
revisionSize, err := fs.lu.MetadataBackend().GetInt64(ctx, restoredRevisionPath, prefixes.BlobsizeAttr)
|
||||
|
||||
Generated
Vendored
+153
@@ -0,0 +1,153 @@
|
||||
package spaceidindex
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/mtimesyncedcache"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
"github.com/shamaton/msgpack/v2"
|
||||
)
|
||||
|
||||
// Index holds space id indexes
|
||||
type Index struct {
|
||||
root string
|
||||
name string
|
||||
cache mtimesyncedcache.Cache[string, map[string]string]
|
||||
}
|
||||
|
||||
type readWriteCloseSeekTruncater interface {
|
||||
io.ReadWriteCloser
|
||||
io.Seeker
|
||||
Truncate(int64) error
|
||||
}
|
||||
|
||||
// New returns a new index instance
|
||||
func New(root, name string) *Index {
|
||||
return &Index{
|
||||
root: root,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the index and makes sure it can be used
|
||||
func (i *Index) Init() error {
|
||||
// Make sure to work on an existing tree
|
||||
return os.MkdirAll(filepath.Join(i.root, i.name), 0700)
|
||||
}
|
||||
|
||||
// Load returns the content of an index
|
||||
func (i *Index) Load(index string) (map[string]string, error) {
|
||||
indexPath := filepath.Join(i.root, i.name, index+".mpk")
|
||||
fi, err := os.Stat(indexPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.readSpaceIndex(indexPath, i.name+":"+index, fi.ModTime())
|
||||
}
|
||||
|
||||
// Add adds an entry to an index
|
||||
func (i *Index) Add(index, key string, value string) error {
|
||||
return i.updateIndex(index, map[string]string{key: value}, []string{})
|
||||
}
|
||||
|
||||
// Remove removes an entry from the index
|
||||
func (i *Index) Remove(index, key string) error {
|
||||
return i.updateIndex(index, map[string]string{}, []string{key})
|
||||
}
|
||||
|
||||
func (i *Index) updateIndex(index string, addLinks map[string]string, removeLinks []string) error {
|
||||
indexPath := filepath.Join(i.root, i.name, index+".mpk")
|
||||
|
||||
var err error
|
||||
// acquire writelock
|
||||
var f readWriteCloseSeekTruncater
|
||||
f, err = lockedfile.OpenFile(indexPath, os.O_RDWR|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to lock index to write")
|
||||
}
|
||||
defer func() {
|
||||
rerr := f.Close()
|
||||
|
||||
// if err is non nil we do not overwrite that
|
||||
if err == nil {
|
||||
err = rerr
|
||||
}
|
||||
}()
|
||||
|
||||
// Read current state
|
||||
msgBytes, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
links := map[string]string{}
|
||||
if len(msgBytes) > 0 {
|
||||
err = msgpack.Unmarshal(msgBytes, &links)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// set new metadata
|
||||
for key, val := range addLinks {
|
||||
links[key] = val
|
||||
}
|
||||
for _, key := range removeLinks {
|
||||
delete(links, key)
|
||||
}
|
||||
// Truncate file
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Truncate(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write new metadata to file
|
||||
d, err := msgpack.Marshal(links)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to marshal index")
|
||||
}
|
||||
_, err = f.Write(d)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to write index")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Index) readSpaceIndex(indexPath, cacheKey string, mtime time.Time) (map[string]string, error) {
|
||||
return i.cache.LoadOrStore(cacheKey, mtime, func() (map[string]string, error) {
|
||||
// Acquire a read log on the index file
|
||||
f, err := lockedfile.Open(indexPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to lock index to read")
|
||||
}
|
||||
defer func() {
|
||||
rerr := f.Close()
|
||||
|
||||
// if err is non nil we do not overwrite that
|
||||
if err == nil {
|
||||
err = rerr
|
||||
}
|
||||
}()
|
||||
|
||||
// Read current state
|
||||
msgBytes, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to read index")
|
||||
}
|
||||
links := map[string]string{}
|
||||
if len(msgBytes) > 0 {
|
||||
err = msgpack.Unmarshal(msgBytes, &links)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to parse index")
|
||||
}
|
||||
}
|
||||
return links, nil
|
||||
})
|
||||
}
|
||||
+29
-138
@@ -298,31 +298,13 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
}
|
||||
|
||||
matches := map[string]struct{}{}
|
||||
var allMatches map[string]string
|
||||
var err error
|
||||
|
||||
if requestedUserID != nil {
|
||||
allMatches := map[string]string{}
|
||||
indexPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID.GetOpaqueId())
|
||||
fi, err := os.Stat(indexPath)
|
||||
if err == nil {
|
||||
allMatches, err = fs.spaceIDCache.LoadOrStore("by-user-id:"+requestedUserID.GetOpaqueId(), fi.ModTime(), func() (map[string]string, error) {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID.GetOpaqueId(), "*")
|
||||
m, err := filepath.Glob(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
matches := map[string]string{}
|
||||
for _, match := range m {
|
||||
link, err := os.Readlink(match)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
matches[match] = link
|
||||
}
|
||||
return matches, nil
|
||||
})
|
||||
}
|
||||
allMatches, err = fs.userSpaceIndex.Load(requestedUserID.GetOpaqueId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "error reading user index")
|
||||
}
|
||||
|
||||
if nodeID == spaceIDAny {
|
||||
@@ -344,29 +326,12 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
}
|
||||
|
||||
for _, group := range user.Groups {
|
||||
indexPath := filepath.Join(fs.o.Root, "indexes", "by-group-id", group)
|
||||
fi, err := os.Stat(indexPath)
|
||||
allMatches, err = fs.groupSpaceIndex.Load(group)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
allMatches, err := fs.spaceIDCache.LoadOrStore("by-group-id:"+group, fi.ModTime(), func() (map[string]string, error) {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-group-id", group, "*")
|
||||
m, err := filepath.Glob(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if os.IsNotExist(err) {
|
||||
continue // no spaces for this group
|
||||
}
|
||||
matches := map[string]string{}
|
||||
for _, match := range m {
|
||||
link, err := os.Readlink(match)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
matches[match] = link
|
||||
}
|
||||
return matches, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "error reading group index")
|
||||
}
|
||||
|
||||
if nodeID == spaceIDAny {
|
||||
@@ -381,33 +346,22 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
|
||||
}
|
||||
|
||||
if requestedUserID == nil {
|
||||
if _, ok := spaceTypes[spaceTypeAny]; ok {
|
||||
// TODO do not hardcode dirs
|
||||
spaceTypes = map[string]struct{}{
|
||||
"personal": {},
|
||||
"project": {},
|
||||
"share": {},
|
||||
}
|
||||
}
|
||||
|
||||
for spaceType := range spaceTypes {
|
||||
indexPath := filepath.Join(fs.o.Root, "indexes", "by-type")
|
||||
if spaceType != spaceTypeAny {
|
||||
indexPath = filepath.Join(indexPath, spaceType)
|
||||
}
|
||||
fi, err := os.Stat(indexPath)
|
||||
allMatches, err = fs.spaceTypeIndex.Load(spaceType)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
allMatches, err := fs.spaceIDCache.LoadOrStore("by-type:"+spaceType, fi.ModTime(), func() (map[string]string, error) {
|
||||
path := filepath.Join(fs.o.Root, "indexes", "by-type", spaceType, "*")
|
||||
m, err := filepath.Glob(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if os.IsNotExist(err) {
|
||||
continue // no spaces for this space type
|
||||
}
|
||||
matches := map[string]string{}
|
||||
for _, match := range m {
|
||||
link, err := os.Readlink(match)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
matches[match] = link
|
||||
}
|
||||
return matches, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "error reading type index")
|
||||
}
|
||||
|
||||
if nodeID == spaceIDAny {
|
||||
@@ -764,13 +718,12 @@ func (fs *Decomposedfs) DeleteStorageSpace(ctx context.Context, req *provider.De
|
||||
return errtypes.NewErrtypeFromStatus(status.NewInvalid(ctx, "can't purge enabled space"))
|
||||
}
|
||||
|
||||
// TODO invalidate ALL indexes in msgpack, not only by type
|
||||
spaceType, err := n.XattrString(ctx, prefixes.SpaceTypeAttr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// remove type index
|
||||
spaceTypePath := filepath.Join(fs.o.Root, "indexes", "by-type", spaceType, spaceID)
|
||||
if err := os.Remove(spaceTypePath); err != nil {
|
||||
if err := fs.spaceTypeIndex.Remove(spaceType, spaceID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -817,80 +770,18 @@ func (fs *Decomposedfs) updateIndexes(ctx context.Context, grantee *provider.Gra
|
||||
}
|
||||
|
||||
func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID string) error {
|
||||
if userID == "" {
|
||||
return nil
|
||||
}
|
||||
// create user index dir
|
||||
// TODO: pathify userID
|
||||
if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-user-id", userID), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes/by-user-id", userID, spaceID))
|
||||
if err != nil {
|
||||
if isAlreadyExists(err) {
|
||||
appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("user-id", userID).Msg("symlink already exists")
|
||||
// FIXME: is it ok to wipe this err if the symlink already exists?
|
||||
err = nil //nolint
|
||||
} else {
|
||||
// TODO how should we handle error cases here?
|
||||
appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("user-id", userID).Msg("could not create symlink")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
target := "../../../spaces/" + lookup.Pathify(spaceID, 1, 2) + "/nodes/" + lookup.Pathify(spaceID, 4, 2)
|
||||
return fs.userSpaceIndex.Add(userID, spaceID, target)
|
||||
}
|
||||
|
||||
func (fs *Decomposedfs) linkSpaceByGroup(ctx context.Context, groupID, spaceID string) error {
|
||||
if groupID == "" {
|
||||
return nil
|
||||
}
|
||||
// create group index dir
|
||||
// TODO: pathify groupid
|
||||
if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-group-id", groupID), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes/by-group-id", groupID, spaceID))
|
||||
if err != nil {
|
||||
if isAlreadyExists(err) {
|
||||
appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("symlink already exists")
|
||||
// FIXME: is it ok to wipe this err if the symlink already exists?
|
||||
err = nil //nolint
|
||||
} else {
|
||||
// TODO how should we handle error cases here?
|
||||
appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("could not create symlink")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
target := "../../../spaces/" + lookup.Pathify(spaceID, 1, 2) + "/nodes/" + lookup.Pathify(spaceID, 4, 2)
|
||||
return fs.groupSpaceIndex.Add(groupID, spaceID, target)
|
||||
}
|
||||
|
||||
// TODO: implement linkSpaceByGroup
|
||||
|
||||
func (fs *Decomposedfs) linkStorageSpaceType(ctx context.Context, spaceType string, spaceID string) error {
|
||||
if spaceType == "" {
|
||||
return nil
|
||||
}
|
||||
// create space type dir
|
||||
if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-type", spaceType), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// link space in spacetypes
|
||||
err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes", "by-type", spaceType, spaceID))
|
||||
if err != nil {
|
||||
if isAlreadyExists(err) {
|
||||
appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("spacetype", spaceType).Msg("symlink already exists")
|
||||
// FIXME: is it ok to wipe this err if the symlink already exists?
|
||||
} else {
|
||||
// TODO how should we handle error cases here?
|
||||
appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("spacetype", spaceType).Msg("could not create symlink")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// touch index root to invalidate caches
|
||||
now := time.Now()
|
||||
return os.Chtimes(filepath.Join(fs.o.Root, "indexes", "by-type"), now, now)
|
||||
target := "../../../spaces/" + lookup.Pathify(spaceID, 1, 2) + "/nodes/" + lookup.Pathify(spaceID, 4, 2)
|
||||
return fs.spaceTypeIndex.Add(spaceType, spaceID, target)
|
||||
}
|
||||
|
||||
func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, checkPermissions bool) (*provider.StorageSpace, error) {
|
||||
|
||||
+3
-13
@@ -40,7 +40,6 @@ import (
|
||||
"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"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/filelocks"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
@@ -750,17 +749,8 @@ func (t *Tree) Propagate(ctx context.Context, n *node.Node, sizeDiff int64) (err
|
||||
// lock parent before reading treesize or tree time
|
||||
|
||||
_, subspan := tracer.Start(ctx, "lockedfile.OpenFile")
|
||||
var parentFilename string
|
||||
switch t.lookup.MetadataBackend().(type) {
|
||||
case metadata.MessagePackBackend:
|
||||
parentFilename = t.lookup.MetadataBackend().MetadataPath(n.ParentPath())
|
||||
f, err = lockedfile.OpenFile(parentFilename, os.O_RDWR|os.O_CREATE, 0600)
|
||||
case metadata.XattrsBackend:
|
||||
// we have to use dedicated lockfiles to lock directories
|
||||
// this only works because the xattr backend also locks folders with separate lock files
|
||||
parentFilename = n.ParentPath() + filelocks.LockFileSuffix
|
||||
f, err = lockedfile.OpenFile(parentFilename, os.O_RDWR|os.O_CREATE, 0600)
|
||||
}
|
||||
parentFilename := t.lookup.MetadataBackend().LockfilePath(n.ParentPath())
|
||||
f, err = lockedfile.OpenFile(parentFilename, os.O_RDWR|os.O_CREATE, 0600)
|
||||
subspan.End()
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).
|
||||
@@ -777,7 +767,7 @@ func (t *Tree) Propagate(ctx context.Context, n *node.Node, sizeDiff int64) (err
|
||||
}
|
||||
}()
|
||||
|
||||
if n, err = n.ParentWithReader(ctx, f); err != nil {
|
||||
if n, err = n.Parent(ctx); err != nil {
|
||||
sublog.Error().Err(err).
|
||||
Msg("Propagation failed. Could not read parent node.")
|
||||
return err
|
||||
|
||||
Generated
Vendored
+7
-14
@@ -38,7 +38,6 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/logger"
|
||||
"github.com/cs3org/reva/v2/pkg/storage/utils/chunking"
|
||||
"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"
|
||||
@@ -329,23 +328,17 @@ func initNewNode(upload *Upload, n *node.Node, fsize uint64) (*lockedfile.File,
|
||||
}
|
||||
|
||||
// create and write lock new node metadata
|
||||
f, err := lockedfile.OpenFile(upload.lu.MetadataBackend().MetadataPath(n.InternalPath()), os.O_RDWR|os.O_CREATE, 0600)
|
||||
f, err := lockedfile.OpenFile(upload.lu.MetadataBackend().LockfilePath(n.InternalPath()), os.O_RDWR|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch upload.lu.MetadataBackend().(type) {
|
||||
case metadata.MessagePackBackend:
|
||||
// for the ini and metadata backend we also need to touch the actual node file here.
|
||||
// it stores the mtime of the resource, which must not change when we update the ini file
|
||||
h, err := os.OpenFile(n.InternalPath(), os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
h.Close()
|
||||
case metadata.XattrsBackend:
|
||||
// nothing to do
|
||||
// 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, 0600)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
h.Close()
|
||||
|
||||
if _, err := node.CheckQuota(upload.Ctx, n.SpaceRoot, false, 0, fsize); err != nil {
|
||||
return f, err
|
||||
@@ -403,7 +396,7 @@ func updateExistingNode(upload *Upload, n *node.Node, spaceID string, fsize uint
|
||||
targetPath := n.InternalPath()
|
||||
|
||||
// write lock existing node before reading treesize or tree time
|
||||
f, err := lockedfile.OpenFile(upload.lu.MetadataBackend().MetadataPath(targetPath), os.O_RDWR, 0600)
|
||||
f, err := lockedfile.OpenFile(upload.lu.MetadataBackend().LockfilePath(targetPath), os.O_RDWR|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+22
-1
@@ -240,7 +240,23 @@ func (c *ConnWithReconnect) StartTLS(*tls.Config) error {
|
||||
}
|
||||
|
||||
// Close implements the ldap.Client interface
|
||||
func (c *ConnWithReconnect) Close() {}
|
||||
func (c *ConnWithReconnect) Close() (err error) {
|
||||
conn, err := c.getConnection()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.Close()
|
||||
}
|
||||
|
||||
func (c *ConnWithReconnect) GetLastError() error {
|
||||
conn, err := c.getConnection()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.GetLastError()
|
||||
}
|
||||
|
||||
// IsClosing implements the ldap.Client interface
|
||||
func (c *ConnWithReconnect) IsClosing() bool {
|
||||
@@ -304,3 +320,8 @@ func (c *ConnWithReconnect) TLSConnectionState() (tls.ConnectionState, bool) {
|
||||
func (c *ConnWithReconnect) Unbind() error {
|
||||
return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
// DirSync implements the ldap.Client interface
|
||||
func (c *ConnWithReconnect) DirSync(searchRequest *ldap.SearchRequest, flags, maxAttrCount int64, cookie []byte) (*ldap.SearchResult, error) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user