Skip to content

Commit b5c3c67

Browse files
committed
fix(decomposedfs): available space calculation
Move the calculation of the available size to the blobstore interface. We were just returning the available size of the local disk, which is wrong when using the S3 blobstore. Also, as the S3 blobstore doesn't have a concept of available size, we don't return a 'remaining' for S3 backed spaces with unlimited quota. Fixes: owncloud/ocis#9245
1 parent 0465da0 commit b5c3c67

File tree

15 files changed

+114
-8
lines changed

15 files changed

+114
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Bugfix: Fix remaining space calculation for S3 blobstore
2+
3+
The calculation of the remaining space in the S3 blobstore was incorrectly using
4+
the remaining space of the local disk instead.
5+
6+
https://github.com/cs3org/reva/pull/4867

pkg/storage/fs/ocis/blobstore/blobstore.go

+5
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ func (bs *Blobstore) Delete(node *node.Node) error {
116116
return nil
117117
}
118118

119+
// GetAvailableSize returns the available size in the blobstore in bytes
120+
func (bs *Blobstore) GetAvailableSize(n *node.Node) (uint64, error) {
121+
return node.GetAvailableSize(n.InternalPath())
122+
}
123+
119124
// List lists all blobs in the Blobstore
120125
func (bs *Blobstore) List() ([]*node.Node, error) {
121126
dirs, err := filepath.Glob(filepath.Join(bs.root, "spaces", "*", "*", "blobs", "*", "*", "*", "*", "*"))

pkg/storage/fs/posix/blobstore/blobstore.go

+5
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,8 @@ func (bs *Blobstore) Download(node *node.Node) (io.ReadCloser, error) {
8888
func (bs *Blobstore) Delete(node *node.Node) error {
8989
return nil
9090
}
91+
92+
// GetAvailableSize returns the available size in the blobstore in bytes
93+
func (bs *Blobstore) GetAvailableSize(n *node.Node) (uint64, error) {
94+
return node.GetAvailableSize(n.InternalPath())
95+
}

pkg/storage/fs/posix/posix.go

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ func New(m map[string]interface{}, stream events.Stream) (storage.FS, error) {
126126
aspects := aspects.Aspects{
127127
Lookup: lu,
128128
Tree: tp,
129+
Blobstore: bs,
129130
Permissions: p,
130131
EventStream: stream,
131132
UserMapper: um,

pkg/storage/fs/posix/testhelpers/helpers.go

+2
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ func NewTestEnv(config map[string]interface{}) (*TestEnv, error) {
178178
)
179179

180180
bs := &treemocks.Blobstore{}
181+
bs.On("GetAvailableSize", mock.Anything).Return(uint64(1000000000), nil)
181182
tree, err := tree.New(lu, bs, um, &trashbin.Trashbin{}, o, nil, store.Create())
182183
if err != nil {
183184
return nil, err
@@ -189,6 +190,7 @@ func NewTestEnv(config map[string]interface{}) (*TestEnv, error) {
189190
aspects := aspects.Aspects{
190191
Lookup: lu,
191192
Tree: tree,
193+
Blobstore: bs,
192194
Permissions: permissions.NewPermissions(pmock, permissionsSelector),
193195
Trashbin: tb,
194196
}

pkg/storage/fs/s3ng/blobstore/blobstore.go

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929

3030
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup"
3131
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
32+
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree"
3233
"github.com/minio/minio-go/v7"
3334
"github.com/minio/minio-go/v7/pkg/credentials"
3435
"github.com/pkg/errors"
@@ -128,6 +129,12 @@ func (bs *Blobstore) Delete(node *node.Node) error {
128129
return nil
129130
}
130131

132+
// GetAvailableSize returns the available size in the blobstore in bytes
133+
func (bs *Blobstore) GetAvailableSize(n *node.Node) (uint64, error) {
134+
// S3 doen't have a concept of available size
135+
return 0, tree.ErrSizeUnlimited
136+
}
137+
131138
// List lists all blobs in the Blobstore
132139
func (bs *Blobstore) List() ([]*node.Node, error) {
133140
ch := bs.client.ListObjects(context.Background(), bs.bucket, minio.ListObjectsOptions{Recursive: true})

pkg/storage/utils/decomposedfs/aspects/aspects.go

+2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ import (
2323
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
2424
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/permissions"
2525
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/trashbin"
26+
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree"
2627
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/usermapper"
2728
)
2829

2930
// Aspects holds dependencies for handling aspects of the decomposedfs
3031
type Aspects struct {
3132
Lookup node.PathLookup
3233
Tree node.Tree
34+
Blobstore tree.Blobstore
3335
Trashbin trashbin.Trashbin
3436
Permissions permissions.Permissions
3537
EventStream events.Stream

pkg/storage/utils/decomposedfs/decomposedfs.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"context"
2323
"fmt"
2424
"io"
25+
"math"
2526
"net/url"
2627
"path"
2728
"path/filepath"
@@ -112,6 +113,7 @@ type SessionStore interface {
112113
type Decomposedfs struct {
113114
lu node.PathLookup
114115
tp node.Tree
116+
bs tree.Blobstore
115117
trashbin trashbin.Trashbin
116118
o *options.Options
117119
p permissions.Permissions
@@ -162,6 +164,7 @@ func NewDefault(m map[string]interface{}, bs tree.Blobstore, es events.Stream) (
162164
aspects := aspects.Aspects{
163165
Lookup: lu,
164166
Tree: tp,
167+
Blobstore: bs,
165168
Permissions: permissions.NewPermissions(node.NewPermissions(lu), permissionsSelector),
166169
EventStream: es,
167170
DisableVersioning: o.DisableVersioning,
@@ -223,6 +226,7 @@ func New(o *options.Options, aspects aspects.Aspects) (storage.FS, error) {
223226

224227
fs := &Decomposedfs{
225228
tp: aspects.Tree,
229+
bs: aspects.Blobstore,
226230
lu: aspects.Lookup,
227231
trashbin: aspects.Trashbin,
228232
o: o,
@@ -598,9 +602,11 @@ func (fs *Decomposedfs) GetQuota(ctx context.Context, ref *provider.Reference) (
598602
quotaStr = string(ri.Opaque.Map["quota"].Value)
599603
}
600604

601-
// FIXME this reads remaining disk size from the local disk, not the blobstore
602-
remaining, err = node.GetAvailableSize(n.InternalPath())
603-
if err != nil {
605+
remaining, err = fs.bs.GetAvailableSize(n)
606+
switch {
607+
case errors.Is(err, tree.ErrSizeUnlimited):
608+
remaining = math.MaxUint64
609+
case err != nil:
604610
return 0, 0, 0, err
605611
}
606612

pkg/storage/utils/decomposedfs/decomposedfs_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ var _ = Describe("Decomposed", func() {
5858
Describe("NewDefault", func() {
5959
It("works", func() {
6060
bs := &treemocks.Blobstore{}
61+
bs.On("GetAvailableSize", mock.Anything).Return(uint64(1000000000), nil)
6162
_, err := decomposedfs.NewDefault(map[string]interface{}{
6263
"root": env.Root,
6364
"permissionssvc": "any",

pkg/storage/utils/decomposedfs/spaces.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
4646
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
4747
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/permissions"
48+
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree"
4849
"github.com/cs3org/reva/v2/pkg/storage/utils/templates"
4950
"github.com/cs3org/reva/v2/pkg/storagespace"
5051
"github.com/cs3org/reva/v2/pkg/utils"
@@ -1028,9 +1029,11 @@ func (fs *Decomposedfs) StorageSpaceFromNode(ctx context.Context, n *node.Node,
10281029
quotaStr = quotaInOpaque
10291030
}
10301031

1031-
// FIXME this reads remaining disk size from the local disk, not the blobstore
1032-
remaining, err := node.GetAvailableSize(n.InternalPath())
1033-
if err != nil {
1032+
remaining, err := fs.bs.GetAvailableSize(n)
1033+
switch {
1034+
case errors.Is(err, tree.ErrSizeUnlimited):
1035+
remaining = math.MaxUint64
1036+
case err != nil:
10341037
return nil, err
10351038
}
10361039
total, used, remaining, err := fs.calculateTotalUsedRemaining(quotaStr, space.GetRootInfo().GetSize(), remaining)
@@ -1039,7 +1042,9 @@ func (fs *Decomposedfs) StorageSpaceFromNode(ctx context.Context, n *node.Node,
10391042
}
10401043
space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "quota.total", strconv.FormatUint(total, 10))
10411044
space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "quota.used", strconv.FormatUint(used, 10))
1042-
space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "quota.remaining", strconv.FormatUint(remaining, 10))
1045+
if remaining != math.MaxUint64 {
1046+
space.Opaque = utils.AppendPlainToOpaque(space.Opaque, "quota.remaining", strconv.FormatUint(remaining, 10))
1047+
}
10431048

10441049
return space, nil
10451050
}

pkg/storage/utils/decomposedfs/testhelpers/helpers.go

+2
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ func NewTestEnv(config map[string]interface{}) (*TestEnv, error) {
175175
aspects := aspects.Aspects{
176176
Lookup: lu,
177177
Tree: tree,
178+
Blobstore: bs,
178179
Permissions: permissions.NewPermissions(pmock, permissionsSelector),
179180
Trashbin: &decomposedfs.DecomposedfsTrashbin{},
180181
}
@@ -290,6 +291,7 @@ func (t *TestEnv) CreateTestStorageSpace(typ string, quota *providerv1beta1.Quot
290291
if typ == "personal" {
291292
owner = t.Owner
292293
}
294+
t.Blobstore.On("GetAvailableSize", mock.Anything).Return(uint64(1000000000), nil)
293295
space, err := t.Fs.CreateStorageSpace(t.Ctx, &providerv1beta1.CreateStorageSpaceRequest{
294296
Owner: owner,
295297
Type: typ,

pkg/storage/utils/decomposedfs/tree/mocks/Blobstore.go

+56
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/storage/utils/decomposedfs/tree/tree.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ import (
4848
"golang.org/x/sync/errgroup"
4949
)
5050

51-
var tracer trace.Tracer
51+
var (
52+
tracer trace.Tracer
53+
ErrSizeUnlimited = errors.New("blobstore size unlimited")
54+
)
5255

5356
func init() {
5457
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/utils/decomposedfs/tree")
@@ -59,6 +62,7 @@ type Blobstore interface {
5962
Upload(node *node.Node, source string) error
6063
Download(node *node.Node) (io.ReadCloser, error)
6164
Delete(node *node.Node) error
65+
GetAvailableSize(node *node.Node) (uint64, error)
6266
}
6367

6468
// Tree manages a hierarchical tree

pkg/storage/utils/decomposedfs/upload_async_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ var _ = Describe("Async file uploads", Ordered, func() {
153153
},
154154
)
155155
bs = &treemocks.Blobstore{}
156+
bs.On("GetAvailableSize", mock.Anything).Return(uint64(1000000000), nil)
156157

157158
// create space uses CheckPermission endpoint
158159
cs3permissionsclient.On("CheckPermission", mock.Anything, mock.Anything, mock.Anything).Return(&cs3permissions.CheckPermissionResponse{
@@ -176,6 +177,7 @@ var _ = Describe("Async file uploads", Ordered, func() {
176177
aspects := aspects.Aspects{
177178
Lookup: lu,
178179
Tree: tree,
180+
Blobstore: bs,
179181
Permissions: permissions.NewPermissions(pmock, permissionsSelector),
180182
EventStream: stream.Chan{pub, con},
181183
Trashbin: &DecomposedfsTrashbin{},

pkg/storage/utils/decomposedfs/upload_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,13 @@ var _ = Describe("File uploads", func() {
136136
AddGrant: true,
137137
}, nil).Times(1)
138138
var err error
139+
bs.On("GetAvailableSize", mock.Anything).Return(uint64(1000000000), nil).Times(1)
139140
tree := tree.New(lu, bs, o, store.Create())
140141

141142
aspects := aspects.Aspects{
142143
Lookup: lu,
143144
Tree: tree,
145+
Blobstore: bs,
144146
Permissions: permissions.NewPermissions(pmock, permissionsSelector),
145147
Trashbin: &decomposedfs.DecomposedfsTrashbin{},
146148
}

0 commit comments

Comments
 (0)