bump reva to v2.15.1-0.20230809113840-3ceaf17cf7fb (#6978)

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Jörn Friedrich Dreyer
2023-08-09 16:01:46 +02:00
committed by GitHub
parent fecd836159
commit bae37cf20b
22 changed files with 1390 additions and 1405 deletions
@@ -39,7 +39,6 @@ import (
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/juliangruber/go-intersect"
"github.com/mitchellh/mapstructure"
"github.com/rs/zerolog/log"
"google.golang.org/grpc"
)
@@ -111,10 +110,8 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
for {
select {
case <-t.C:
log.Debug().Msg("app provider tick, registering Provider")
service.registerProvider()
case <-service.context.Done():
log.Debug().Msg("app provider stopped")
t.Stop()
}
}
@@ -840,7 +840,7 @@ func requiresExplicitFetching(n *xml.Name) bool {
switch n.Space {
case net.NsDav:
switch n.Local {
case "quota-available-bytes", "quota-used-bytes":
case "quota-available-bytes", "quota-used-bytes", "lockdiscovery":
// A <DAV:allprop> PROPFIND request SHOULD NOT return DAV:quota-available-bytes and DAV:quota-used-bytes
// from https://www.rfc-editor.org/rfc/rfc4331.html#section-2
return true
@@ -1663,21 +1663,14 @@ func (c *countingReader) Read(p []byte) (int, error) {
}
func metadataKeyOf(n *xml.Name) string {
switch n.Space {
case net.NsDav:
if n.Local == "quota-available-bytes" {
return "quota"
}
case net.NsOwncloud:
if n.Local == "share-types" {
return "share-types"
}
if n.Local == "tags" {
return "tags"
}
switch n.Local {
case "quota-available-bytes":
return "quota"
case "share-types", "tags", "lockdiscovery":
return n.Local
default:
return fmt.Sprintf("%s/%s", n.Space, n.Local)
}
return fmt.Sprintf("%s/%s", n.Space, n.Local)
}
// UnmarshalXML appends the property names enclosed within start to pn.
@@ -414,9 +414,17 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "missing resource information", fmt.Errorf("error getting resource information"))
return
}
if statRes.GetStatus().GetCode() != rpc.Code_CODE_OK {
if statRes.GetStatus().GetCode() == rpc.Code_CODE_NOT_FOUND {
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "update public share: resource not found", err)
return
}
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc stat request failed for stat when updating a public share", err)
return
}
// empty permissions mean internal link here - NOT denial. Hence we need an extra check
if !sufficientPermissions(statRes.Info.PermissionSet, newPermissions, true) {
if !sufficientPermissions(statRes.GetInfo().GetPermissionSet(), newPermissions, true) {
response.WriteOCSError(w, r, http.StatusForbidden, "no share permission", nil)
return
}
@@ -245,6 +245,11 @@ func (h *Handler) listUserShares(r *http.Request, filters []*collaboration.Filte
h.addFileInfo(ctx, data, info)
h.mapUserIds(ctx, client, data)
// Filter out a share if ShareWith is not found because the user or group already deleted
if data.ShareWith == "" {
continue
}
log.Debug().Interface("share", s).Interface("info", info).Interface("shareData", data).Msg("mapped")
ocsDataPayload = append(ocsDataPayload, data)
}
+12 -15
View File
@@ -44,6 +44,18 @@ import (
"go.opentelemetry.io/otel/trace"
)
func init() {
// register method with chi before any routing is set up
chi.RegisterMethod(ocdav.MethodPropfind)
chi.RegisterMethod(ocdav.MethodProppatch)
chi.RegisterMethod(ocdav.MethodLock)
chi.RegisterMethod(ocdav.MethodUnlock)
chi.RegisterMethod(ocdav.MethodCopy)
chi.RegisterMethod(ocdav.MethodMove)
chi.RegisterMethod(ocdav.MethodMkcol)
chi.RegisterMethod(ocdav.MethodReport)
}
const (
// ServerName to use when announcing the service to the registry
ServerName = "ocdav"
@@ -73,17 +85,6 @@ func Service(opts ...Option) (micro.Service, error) {
return nil, err
}
// Comment back in after resolving the issue in go-chi.
// See comment in line 87.
// register additional webdav verbs
// chi.RegisterMethod(ocdav.MethodPropfind)
// chi.RegisterMethod(ocdav.MethodProppatch)
// chi.RegisterMethod(ocdav.MethodLock)
// chi.RegisterMethod(ocdav.MethodUnlock)
// chi.RegisterMethod(ocdav.MethodCopy)
// chi.RegisterMethod(ocdav.MethodMove)
// chi.RegisterMethod(ocdav.MethodMkcol)
// chi.RegisterMethod(ocdav.MethodReport)
r := chi.NewRouter()
tp := sopts.TraceProvider
@@ -107,10 +108,6 @@ func Service(opts ...Option) (micro.Service, error) {
}
r.Handle("/*", revaService.Handler())
// This is a workaround for the go-chi concurrent map read write issue.
// After the issue has been solved upstream in go-chi we should switch
// back to using `chi.RegisterMethod`.
r.MethodNotAllowed(http.HandlerFunc(revaService.Handler().ServeHTTP))
_ = chi.Walk(r, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
sopts.Logger.Debug().Str("service", "ocdav").Str("method", method).Str("route", route).Int("middlewares", len(middlewares)).Msg("serving endpoint")
+1118 -4
View File
File diff suppressed because it is too large Load Diff
+20 -97
View File
@@ -337,17 +337,6 @@ func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *colla
eg.Go(func() error {
err := m.Cache.Add(ctx, md.Id.StorageId, md.Id.SpaceId, shareID, s)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := m.Cache.Sync(ctx, md.Id.StorageId, md.Id.SpaceId); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = m.Cache.Add(ctx, md.Id.StorageId, md.Id.SpaceId, shareID, s)
// TODO try more often?
}
if err != nil {
span.RecordError(err)
@@ -359,17 +348,6 @@ func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *colla
eg.Go(func() error {
err := m.CreatedCache.Add(ctx, s.GetCreator().GetOpaqueId(), shareID)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := m.CreatedCache.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = m.CreatedCache.Add(ctx, s.GetCreator().GetOpaqueId(), shareID)
// TODO try more often?
}
if err != nil {
span.RecordError(err)
@@ -391,16 +369,6 @@ func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *colla
State: collaboration.ShareState_SHARE_STATE_PENDING,
}
err := m.UserReceivedStates.Add(ctx, userid, spaceID, rs)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := m.UserReceivedStates.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = m.UserReceivedStates.Add(ctx, userid, spaceID, rs)
// TODO try more often?
}
if err != nil {
span.RecordError(err)
@@ -413,16 +381,6 @@ func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *colla
eg.Go(func() error {
groupid := g.Grantee.GetGroupId().GetOpaqueId()
err := m.GroupReceivedCache.Add(ctx, groupid, shareID)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := m.GroupReceivedCache.Sync(ctx, groupid); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = m.GroupReceivedCache.Add(ctx, groupid, shareID)
// TODO try more often?
}
if err != nil {
span.RecordError(err)
@@ -445,13 +403,11 @@ func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *colla
// getByID must be called in a lock-controlled block.
func (m *Manager) getByID(ctx context.Context, id *collaboration.ShareId) (*collaboration.Share, error) {
storageID, spaceID, _ := shareid.Decode(id.OpaqueId)
// sync cache, maybe our data is outdated
err := m.Cache.Sync(ctx, storageID, spaceID)
share, err := m.Cache.Get(ctx, storageID, spaceID, id.OpaqueId)
if err != nil {
return nil, err
}
share := m.Cache.Get(storageID, spaceID, id.OpaqueId)
if share == nil {
return nil, errtypes.NotFound(id.String())
}
@@ -460,12 +416,10 @@ func (m *Manager) getByID(ctx context.Context, id *collaboration.ShareId) (*coll
// getByKey must be called in a lock-controlled block.
func (m *Manager) getByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.Share, error) {
err := m.Cache.Sync(ctx, key.ResourceId.StorageId, key.ResourceId.SpaceId)
spaceShares, err := m.Cache.ListSpace(ctx, key.ResourceId.StorageId, key.ResourceId.SpaceId)
if err != nil {
return nil, err
}
spaceShares := m.Cache.ListSpace(key.ResourceId.StorageId, key.ResourceId.SpaceId)
for _, share := range spaceShares.Shares {
if utils.GranteeEqual(key.Grantee, share.Grantee) && utils.ResourceIDEqual(share.ResourceId, key.ResourceId) {
return share, nil
@@ -678,15 +632,11 @@ func (m *Manager) listSharesByIDs(ctx context.Context, user *userv1beta1.User, f
var ss []*collaboration.Share
for providerID, spaces := range providerSpaces {
for spaceID := range spaces {
err := m.Cache.Sync(ctx, providerID, spaceID)
shares, err := m.Cache.ListSpace(ctx, providerID, spaceID)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return nil, err
}
shares := m.Cache.ListSpace(providerID, spaceID)
for _, s := range shares.Shares {
if share.IsExpired(s) {
if err := m.removeShare(ctx, s); err != nil {
@@ -737,20 +687,20 @@ func (m *Manager) listCreatedShares(ctx context.Context, user *userv1beta1.User,
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "listCreatedShares")
defer span.End()
var ss []*collaboration.Share
if err := m.CreatedCache.Sync(ctx, user.Id.OpaqueId); err != nil {
list, err := m.CreatedCache.List(ctx, user.Id.OpaqueId)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return ss, err
return nil, err
}
for ssid, spaceShareIDs := range m.CreatedCache.List(user.Id.OpaqueId) {
var ss []*collaboration.Share
for ssid, spaceShareIDs := range list {
storageID, spaceID, _ := shareid.Decode(ssid)
err := m.Cache.Sync(ctx, storageID, spaceID)
spaceShares, err := m.Cache.ListSpace(ctx, storageID, spaceID)
if err != nil {
continue
}
spaceShares := m.Cache.ListSpace(storageID, spaceID)
for shareid := range spaceShareIDs.IDs {
s := spaceShares.Shares[shareid]
if s == nil {
@@ -800,10 +750,11 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati
// first collect all spaceids the user has access to as a group member
for _, group := range user.Groups {
if err := m.GroupReceivedCache.Sync(ctx, group); err != nil {
list, err := m.GroupReceivedCache.List(ctx, group)
if err != nil {
continue // ignore error, cache will be updated on next read
}
for ssid, spaceShareIDs := range m.GroupReceivedCache.List(group) {
for ssid, spaceShareIDs := range list {
// add a pending entry, the state will be updated
// when reading the received shares below if they have already been accepted or denied
var rs *receivedsharecache.Space
@@ -825,6 +776,7 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati
}
// add all spaces the user has receved shares for, this includes mount points and share state for groups
// TODO: rewrite this code to not use the internal strucs anymore (e.g. by adding a List method). Sync can then be made private.
_ = m.UserReceivedStates.Sync(ctx, user.Id.OpaqueId) // ignore error, cache will be updated on next read
if m.UserReceivedStates.ReceivedSpaces[user.Id.OpaqueId] != nil {
@@ -872,13 +824,9 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati
g.Go(func() error {
for w := range work {
storageID, spaceID, _ := shareid.Decode(w.ssid)
err := m.Cache.Sync(ctx, storageID, spaceID)
if err != nil {
continue
}
for shareID, state := range w.rspace.States {
s := m.Cache.Get(storageID, spaceID, shareID)
if s == nil {
s, err := m.Cache.Get(ctx, storageID, spaceID, shareID)
if err != nil || s == nil {
continue
}
if share.IsExpired(s) {
@@ -952,9 +900,8 @@ func (m *Manager) convert(ctx context.Context, userID string, s *collaboration.S
storageID, spaceID, _ := shareid.Decode(s.Id.OpaqueId)
_ = m.UserReceivedStates.Sync(ctx, userID) // ignore error, cache will be updated on next read
state := m.UserReceivedStates.Get(userID, storageID+shareid.IDDelimiter+spaceID, s.Id.GetOpaqueId())
if state != nil {
state, err := m.UserReceivedStates.Get(ctx, userID, storageID+shareid.IDDelimiter+spaceID, s.Id.GetOpaqueId())
if err == nil && state != nil {
rs.State = state.State
rs.MountPoint = state.MountPoint
}
@@ -1031,14 +978,6 @@ func (m *Manager) UpdateReceivedShare(ctx context.Context, receivedShare *collab
userID := ctxpkg.ContextMustGetUser(ctx)
err = m.UserReceivedStates.Add(ctx, userID.GetId().GetOpaqueId(), rs.Share.ResourceId.StorageId+shareid.IDDelimiter+rs.Share.ResourceId.SpaceId, rs)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
// when persisting fails, download, readd and persist again
if err := m.UserReceivedStates.Sync(ctx, userID.GetId().GetOpaqueId()); err != nil {
return nil, err
}
err = m.UserReceivedStates.Add(ctx, userID.GetId().GetOpaqueId(), rs.Share.ResourceId.StorageId+shareid.IDDelimiter+rs.Share.ResourceId.SpaceId, rs)
// TODO try more often?
}
if err != nil {
return nil, err
}
@@ -1120,29 +1059,13 @@ func (m *Manager) removeShare(ctx context.Context, s *collaboration.Share) error
eg.Go(func() error {
storageID, spaceID, _ := shareid.Decode(s.Id.OpaqueId)
err := m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := m.Cache.Sync(ctx, storageID, spaceID); err != nil {
return err
}
err = m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId)
// TODO try more often?
}
return err
})
eg.Go(func() error {
// remove from created cache
err := m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId)
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := m.CreatedCache.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil {
return err
}
err = m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId)
// TODO try more often?
}
return err
return m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId)
})
// TODO remove from grantee cache
@@ -127,6 +127,13 @@ func (c *Cache) Add(ctx context.Context, storageID, spaceID, shareID string, sha
unlock := c.LockSpace(spaceID)
defer unlock()
if c.Providers[storageID] == nil || c.Providers[storageID].Spaces[spaceID] == nil {
err := c.syncWithLock(ctx, storageID, spaceID)
if err != nil {
return err
}
}
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Add")
defer span.End()
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID), attribute.String("cs3.shareid", shareID))
@@ -140,9 +147,25 @@ func (c *Cache) Add(ctx context.Context, storageID, spaceID, shareID string, sha
return fmt.Errorf("missing share id")
}
c.initializeIfNeeded(storageID, spaceID)
c.Providers[storageID].Spaces[spaceID].Shares[shareID] = share
return c.Persist(ctx, storageID, spaceID)
persistFunc := func() error {
c.Providers[storageID].Spaces[spaceID].Shares[shareID] = share
return c.Persist(ctx, storageID, spaceID)
}
err := persistFunc()
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := c.syncWithLock(ctx, storageID, spaceID); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = persistFunc()
}
return err
}
// Remove removes a share from the cache
@@ -150,38 +173,68 @@ func (c *Cache) Remove(ctx context.Context, storageID, spaceID, shareID string)
unlock := c.LockSpace(spaceID)
defer unlock()
if c.Providers[storageID] == nil || c.Providers[storageID].Spaces[spaceID] == nil {
err := c.syncWithLock(ctx, storageID, spaceID)
if err != nil {
return err
}
}
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Remove")
defer span.End()
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID), attribute.String("cs3.shareid", shareID))
if c.Providers[storageID] == nil ||
c.Providers[storageID].Spaces[spaceID] == nil {
return nil
}
delete(c.Providers[storageID].Spaces[spaceID].Shares, shareID)
persistFunc := func() error {
if c.Providers[storageID] == nil ||
c.Providers[storageID].Spaces[spaceID] == nil {
return nil
}
delete(c.Providers[storageID].Spaces[spaceID].Shares, shareID)
return c.Persist(ctx, storageID, spaceID)
return c.Persist(ctx, storageID, spaceID)
}
err := persistFunc()
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := c.syncWithLock(ctx, storageID, spaceID); err != nil {
return err
}
err = persistFunc()
}
return err
}
// Get returns one entry from the cache
func (c *Cache) Get(storageID, spaceID, shareID string) *collaboration.Share {
func (c *Cache) Get(ctx context.Context, storageID, spaceID, shareID string) (*collaboration.Share, error) {
// sync cache, maybe our data is outdated
err := c.Sync(ctx, storageID, spaceID)
if err != nil {
return nil, err
}
if c.Providers[storageID] == nil ||
c.Providers[storageID].Spaces[spaceID] == nil {
return nil
return nil, nil
}
return c.Providers[storageID].Spaces[spaceID].Shares[shareID]
return c.Providers[storageID].Spaces[spaceID].Shares[shareID], nil
}
// ListSpace returns the list of shares in a given space
func (c *Cache) ListSpace(storageID, spaceID string) *Shares {
if c.Providers[storageID] == nil || c.Providers[storageID].Spaces[spaceID] == nil {
return &Shares{}
func (c *Cache) ListSpace(ctx context.Context, storageID, spaceID string) (*Shares, error) {
// sync cache, maybe our data is outdated
err := c.Sync(ctx, storageID, spaceID)
if err != nil {
return nil, err
}
return c.Providers[storageID].Spaces[spaceID]
if c.Providers[storageID] == nil || c.Providers[storageID].Spaces[spaceID] == nil {
return &Shares{}, nil
}
return c.Providers[storageID].Spaces[spaceID], nil
}
// PersistWithTime persists the data of one space if it has not been modified since the given mtime
func (c *Cache) PersistWithTime(ctx context.Context, storageID, spaceID string, mtime time.Time) error {
// Persist persists the data of one space
func (c *Cache) Persist(ctx context.Context, storageID, spaceID string) error {
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "PersistWithTime")
defer span.End()
span.SetAttributes(attribute.String("cs3.storageid", storageID), attribute.String("cs3.spaceid", spaceID))
@@ -192,7 +245,7 @@ func (c *Cache) PersistWithTime(ctx context.Context, storageID, spaceID string,
}
oldMtime := c.Providers[storageID].Spaces[spaceID].Mtime
c.Providers[storageID].Spaces[spaceID].Mtime = mtime
c.Providers[storageID].Spaces[spaceID].Mtime = time.Now()
// FIXME there is a race when between this time now and the below Uploed another process also updates the file -> we need a lock
createdBytes, err := json.Marshal(c.Providers[storageID].Spaces[spaceID])
@@ -213,7 +266,8 @@ func (c *Cache) PersistWithTime(ctx context.Context, storageID, spaceID string,
if err = c.storage.Upload(ctx, metadata.UploadRequest{
Path: jsonPath,
Content: createdBytes,
IfUnmodifiedSince: c.Providers[storageID].Spaces[spaceID].Mtime,
IfUnmodifiedSince: oldMtime,
MTime: c.Providers[storageID].Spaces[spaceID].Mtime,
}); err != nil {
c.Providers[storageID].Spaces[spaceID].Mtime = oldMtime
span.RecordError(err)
@@ -224,16 +278,15 @@ func (c *Cache) PersistWithTime(ctx context.Context, storageID, spaceID string,
return nil
}
// Persist persists the data of one space
func (c *Cache) Persist(ctx context.Context, storageID, spaceID string) error {
return c.PersistWithTime(ctx, storageID, spaceID, time.Now())
}
// Sync updates the in-memory data with the data from the storage if it is outdated
func (c *Cache) Sync(ctx context.Context, storageID, spaceID string) error {
unlock := c.LockSpace(spaceID)
defer unlock()
return c.syncWithLock(ctx, storageID, spaceID)
}
func (c *Cache) syncWithLock(ctx context.Context, storageID, spaceID string) error {
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Sync")
defer span.End()
@@ -95,38 +95,62 @@ func (c *Cache) Add(ctx context.Context, userID, spaceID string, rs *collaborati
unlock := c.lockUser(userID)
defer unlock()
if c.ReceivedSpaces[userID] == nil {
err := c.syncWithLock(ctx, userID)
if err != nil {
return err
}
}
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Add")
defer span.End()
span.SetAttributes(attribute.String("cs3.userid", userID), attribute.String("cs3.spaceid", spaceID))
if c.ReceivedSpaces[userID] == nil {
c.ReceivedSpaces[userID] = &Spaces{
Spaces: map[string]*Space{},
persistFunc := func() error {
if c.ReceivedSpaces[userID] == nil {
c.ReceivedSpaces[userID] = &Spaces{
Spaces: map[string]*Space{},
}
}
if c.ReceivedSpaces[userID].Spaces[spaceID] == nil {
c.ReceivedSpaces[userID].Spaces[spaceID] = &Space{}
}
}
if c.ReceivedSpaces[userID].Spaces[spaceID] == nil {
c.ReceivedSpaces[userID].Spaces[spaceID] = &Space{}
}
receivedSpace := c.ReceivedSpaces[userID].Spaces[spaceID]
receivedSpace.Mtime = time.Now()
if receivedSpace.States == nil {
receivedSpace.States = map[string]*State{}
}
receivedSpace.States[rs.Share.Id.GetOpaqueId()] = &State{
State: rs.State,
MountPoint: rs.MountPoint,
}
receivedSpace := c.ReceivedSpaces[userID].Spaces[spaceID]
receivedSpace.Mtime = time.Now()
if receivedSpace.States == nil {
receivedSpace.States = map[string]*State{}
}
receivedSpace.States[rs.Share.Id.GetOpaqueId()] = &State{
State: rs.State,
MountPoint: rs.MountPoint,
}
return c.persist(ctx, userID)
return c.persist(ctx, userID)
}
err := persistFunc()
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := c.syncWithLock(ctx, userID); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = persistFunc()
}
return err
}
// Get returns one entry from the cache
func (c *Cache) Get(userID, spaceID, shareID string) *State {
if c.ReceivedSpaces[userID] == nil || c.ReceivedSpaces[userID].Spaces[spaceID] == nil {
return nil
func (c *Cache) Get(ctx context.Context, userID, spaceID, shareID string) (*State, error) {
err := c.Sync(ctx, userID)
if err != nil {
return nil, err
}
return c.ReceivedSpaces[userID].Spaces[spaceID].States[shareID]
if c.ReceivedSpaces[userID] == nil || c.ReceivedSpaces[userID].Spaces[spaceID] == nil {
return nil, nil
}
return c.ReceivedSpaces[userID].Spaces[spaceID].States[shareID], nil
}
// Sync updates the in-memory data with the data from the storage if it is outdated
@@ -134,6 +158,10 @@ func (c *Cache) Sync(ctx context.Context, userID string) error {
unlock := c.lockUser(userID)
defer unlock()
return c.syncWithLock(ctx, userID)
}
func (c *Cache) syncWithLock(ctx context.Context, userID string) error {
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Sync")
defer span.End()
span.SetAttributes(attribute.String("cs3.userid", userID))
@@ -222,7 +250,8 @@ func (c *Cache) persist(ctx context.Context, userID string) error {
if err = c.storage.Upload(ctx, metadata.UploadRequest{
Path: jsonPath,
Content: createdBytes,
IfUnmodifiedSince: c.ReceivedSpaces[userID].Mtime,
IfUnmodifiedSince: oldMtime,
MTime: c.ReceivedSpaces[userID].Mtime,
}); err != nil {
c.ReceivedSpaces[userID].Mtime = oldMtime
span.RecordError(err)
@@ -92,6 +92,13 @@ func (c *Cache) Add(ctx context.Context, userid, shareID string) error {
unlock := c.lockUser(userid)
defer unlock()
if c.UserShares[userid] == nil {
err := c.syncWithLock(ctx, userid)
if err != nil {
return err
}
}
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Add")
defer span.End()
span.SetAttributes(attribute.String("cs3.userid", userid), attribute.String("cs3.shareid", shareID))
@@ -99,22 +106,37 @@ func (c *Cache) Add(ctx context.Context, userid, shareID string) error {
storageid, spaceid, _ := shareid.Decode(shareID)
ssid := storageid + shareid.IDDelimiter + spaceid
now := time.Now()
if c.UserShares[userid] == nil {
c.UserShares[userid] = &UserShareCache{
UserShares: map[string]*SpaceShareIDs{},
persistFunc := func() error {
now := time.Now()
if c.UserShares[userid] == nil {
c.UserShares[userid] = &UserShareCache{
UserShares: map[string]*SpaceShareIDs{},
}
}
}
if c.UserShares[userid].UserShares[ssid] == nil {
c.UserShares[userid].UserShares[ssid] = &SpaceShareIDs{
IDs: map[string]struct{}{},
if c.UserShares[userid].UserShares[ssid] == nil {
c.UserShares[userid].UserShares[ssid] = &SpaceShareIDs{
IDs: map[string]struct{}{},
}
}
// add share id
c.UserShares[userid].UserShares[ssid].Mtime = now
c.UserShares[userid].UserShares[ssid].IDs[shareID] = struct{}{}
return c.Persist(ctx, userid)
}
// add share id
c.UserShares[userid].Mtime = now
c.UserShares[userid].UserShares[ssid].Mtime = now
c.UserShares[userid].UserShares[ssid].IDs[shareID] = struct{}{}
return c.Persist(ctx, userid)
err := persistFunc()
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := c.syncWithLock(ctx, userid); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
err = persistFunc()
// TODO try more often?
}
return err
}
// Remove removes a share for the given user
@@ -122,6 +144,13 @@ func (c *Cache) Remove(ctx context.Context, userid, shareID string) error {
unlock := c.lockUser(userid)
defer unlock()
if c.UserShares[userid] == nil {
err := c.syncWithLock(ctx, userid)
if err != nil {
return err
}
}
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Remove")
defer span.End()
span.SetAttributes(attribute.String("cs3.userid", userid), attribute.String("cs3.shareid", shareID))
@@ -129,29 +158,44 @@ func (c *Cache) Remove(ctx context.Context, userid, shareID string) error {
storageid, spaceid, _ := shareid.Decode(shareID)
ssid := storageid + shareid.IDDelimiter + spaceid
now := time.Now()
if c.UserShares[userid] == nil {
c.UserShares[userid] = &UserShareCache{
Mtime: now,
UserShares: map[string]*SpaceShareIDs{},
persistFunc := func() error {
if c.UserShares[userid] == nil {
c.UserShares[userid] = &UserShareCache{
UserShares: map[string]*SpaceShareIDs{},
}
}
if c.UserShares[userid].UserShares[ssid] != nil {
// remove share id
c.UserShares[userid].UserShares[ssid].Mtime = time.Now()
delete(c.UserShares[userid].UserShares[ssid].IDs, shareID)
}
return c.Persist(ctx, userid)
}
if c.UserShares[userid].UserShares[ssid] != nil {
// remove share id
c.UserShares[userid].Mtime = now
c.UserShares[userid].UserShares[ssid].Mtime = now
delete(c.UserShares[userid].UserShares[ssid].IDs, shareID)
err := persistFunc()
if _, ok := err.(errtypes.IsPreconditionFailed); ok {
if err := c.syncWithLock(ctx, userid); err != nil {
return err
}
err = persistFunc()
}
return c.Persist(ctx, userid)
return err
}
// List return the list of spaces/shares for the given user/group
func (c *Cache) List(userid string) map[string]SpaceShareIDs {
func (c *Cache) List(ctx context.Context, userid string) (map[string]SpaceShareIDs, error) {
unlock := c.lockUser(userid)
defer unlock()
if err := c.syncWithLock(ctx, userid); err != nil {
return nil, err
}
r := map[string]SpaceShareIDs{}
if c.UserShares[userid] == nil {
return r
return r, nil
}
for ssid, cached := range c.UserShares[userid].UserShares {
@@ -160,14 +204,10 @@ func (c *Cache) List(userid string) map[string]SpaceShareIDs {
IDs: cached.IDs,
}
}
return r
return r, nil
}
// Sync updates the in-memory data with the data from the storage if it is outdated
func (c *Cache) Sync(ctx context.Context, userID string) error {
unlock := c.lockUser(userID)
defer unlock()
func (c *Cache) syncWithLock(ctx context.Context, userID string) error {
ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "Sync")
defer span.End()
span.SetAttributes(attribute.String("cs3.userid", userID))
@@ -253,7 +293,8 @@ func (c *Cache) Persist(ctx context.Context, userid string) error {
if err = c.storage.Upload(ctx, metadata.UploadRequest{
Path: jsonPath,
Content: createdBytes,
IfUnmodifiedSince: c.UserShares[userid].Mtime,
IfUnmodifiedSince: oldMtime,
MTime: c.UserShares[userid].Mtime,
}); err != nil {
c.UserShares[userid].Mtime = oldMtime
span.RecordError(err)
@@ -71,9 +71,9 @@ func (bs *Blobstore) Upload(node *node.Node, source string) error {
}
defer reader.Close()
_, err1 := bs.client.PutObject(context.Background(), bs.bucket, bs.path(node), reader, node.Blobsize, minio.PutObjectOptions{ContentType: "application/octet-stream"})
_, err = bs.client.PutObject(context.Background(), bs.bucket, bs.path(node), reader, node.Blobsize, minio.PutObjectOptions{ContentType: "application/octet-stream", SendContentMd5: true})
if err1 != nil {
if err != nil {
return errors.Wrapf(err, "could not store object '%s' into bucket '%s'", bs.path(node), bs.bucket)
}
return nil
@@ -60,7 +60,7 @@ func init() {
// Define keys and values used in the node metadata
const (
LockdiscoveryKey = "DAV:lockdiscovery"
LockdiscoveryKey = "lockdiscovery"
FavoriteKey = "http://owncloud.org/ns/favorite"
ShareTypesKey = "http://owncloud.org/ns/share-types"
ChecksumsKey = "http://owncloud.org/ns/checksums"
@@ -292,6 +292,7 @@ func (upload *Upload) FinishUpload(_ context.Context) error {
err = upload.Finalize()
Cleanup(upload, err != nil, false)
if err != nil {
log.Error().Err(err).Msg("failed to upload")
return err
}
}
+7 -2
View File
@@ -25,6 +25,7 @@ import (
"io"
"net/http"
"os"
"strconv"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -34,7 +35,6 @@ import (
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/utils"
"go.opentelemetry.io/otel"
@@ -149,6 +149,7 @@ func (cs3 *CS3) Upload(ctx context.Context, req UploadRequest) error {
}
ifuReq := &provider.InitiateFileUploadRequest{
Opaque: &types.Opaque{},
Ref: &provider.Reference{
ResourceId: cs3.SpaceRoot,
Path: utils.MakeRelativePath(req.Path),
@@ -165,13 +166,17 @@ func (cs3 *CS3) Upload(ctx context.Context, req UploadRequest) error {
IfUnmodifiedSince: utils.TimeToTS(req.IfUnmodifiedSince),
}
}
if req.MTime != (time.Time{}) {
// The format of the X-OC-Mtime header is <epoch>.<nanoseconds>, e.g. '1691053416.934129485'
ifuReq.Opaque = utils.AppendPlainToOpaque(ifuReq.Opaque, "X-OC-Mtime", strconv.Itoa(int(req.MTime.Unix()))+"."+strconv.Itoa(req.MTime.Nanosecond()))
}
res, err := client.InitiateFileUpload(ctx, ifuReq)
if err != nil {
return err
}
if res.Status.Code != rpc.Code_CODE_OK {
return status.NewErrorFromCode(res.Status.Code, "cs3 metadata SimpleUpload")
return errtypes.NewErrtypeFromStatus(res.Status)
}
var endpoint string
@@ -37,6 +37,7 @@ type UploadRequest struct {
IfMatchEtag string
IfUnmodifiedSince time.Time
MTime time.Time
}
// Storage is the interface to maintain metadata in a storage