Skip to content

Commit 298d4ec

Browse files
committed
Merged scoutfs and posix ListObjects and ListObjectsV2
1 parent 3934bea commit 298d4ec

File tree

3 files changed

+23
-192
lines changed

3 files changed

+23
-192
lines changed

backend/posix/posix.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,6 +4206,10 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
42064206
}
42074207

42084208
func (p *Posix) ListObjects(ctx context.Context, input *s3.ListObjectsInput) (s3response.ListObjectsResult, error) {
4209+
return p.ListObjectsParametrized(ctx, input, p.FileToObj)
4210+
}
4211+
4212+
func (p *Posix) ListObjectsParametrized(ctx context.Context, input *s3.ListObjectsInput, customFileToObj func(string, bool) backend.GetObjFunc) (s3response.ListObjectsResult, error) {
42094213
bucket := *input.Bucket
42104214
prefix := ""
42114215
if input.Prefix != nil {
@@ -4234,7 +4238,7 @@ func (p *Posix) ListObjects(ctx context.Context, input *s3.ListObjectsInput) (s3
42344238

42354239
fileSystem := os.DirFS(bucket)
42364240
results, err := backend.Walk(ctx, fileSystem, prefix, delim, marker, maxkeys,
4237-
p.fileToObj(bucket, true), []string{metaTmpDir})
4241+
customFileToObj(bucket, true), []string{metaTmpDir})
42384242
if err != nil {
42394243
return s3response.ListObjectsResult{}, fmt.Errorf("walk %v: %w", bucket, err)
42404244
}
@@ -4252,7 +4256,7 @@ func (p *Posix) ListObjects(ctx context.Context, input *s3.ListObjectsInput) (s3
42524256
}, nil
42534257
}
42544258

4255-
func (p *Posix) fileToObj(bucket string, fetchOwner bool) backend.GetObjFunc {
4259+
func (p *Posix) FileToObj(bucket string, fetchOwner bool) backend.GetObjFunc {
42564260
return func(path string, d fs.DirEntry) (s3response.Object, error) {
42574261
var owner *types.Owner
42584262
// Retreive the object owner data from bucket ACL, if fetchOwner is true
@@ -4355,6 +4359,10 @@ func (p *Posix) fileToObj(bucket string, fetchOwner bool) backend.GetObjFunc {
43554359
}
43564360

43574361
func (p *Posix) ListObjectsV2(ctx context.Context, input *s3.ListObjectsV2Input) (s3response.ListObjectsV2Result, error) {
4362+
return p.ListObjectsV2Parametrized(ctx, input, p.FileToObj)
4363+
}
4364+
4365+
func (p *Posix) ListObjectsV2Parametrized(ctx context.Context, input *s3.ListObjectsV2Input, customFileToObj func(string, bool) backend.GetObjFunc) (s3response.ListObjectsV2Result, error) {
43584366
bucket := *input.Bucket
43594367
prefix := ""
43604368
if input.Prefix != nil {
@@ -4391,7 +4399,7 @@ func (p *Posix) ListObjectsV2(ctx context.Context, input *s3.ListObjectsV2Input)
43914399

43924400
fileSystem := os.DirFS(bucket)
43934401
results, err := backend.Walk(ctx, fileSystem, prefix, delim, marker, maxkeys,
4394-
p.fileToObj(bucket, fetchOwner), []string{metaTmpDir})
4402+
customFileToObj(bucket, fetchOwner), []string{metaTmpDir})
43954403
if err != nil {
43964404
return s3response.ListObjectsV2Result{}, fmt.Errorf("walk %v: %w", bucket, err)
43974405
}

backend/scoutfs/scoutfs.go

Lines changed: 12 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import (
3030
"github.com/aws/aws-sdk-go-v2/service/s3/types"
3131
"github.com/pkg/xattr"
3232
"github.com/versity/versitygw/backend"
33-
"github.com/versity/versitygw/backend/meta"
3433
"github.com/versity/versitygw/backend/posix"
3534
"github.com/versity/versitygw/s3err"
3635
"github.com/versity/versitygw/s3response"
@@ -50,9 +49,6 @@ type ScoutFS struct {
5049
rootfd *os.File
5150
rootdir string
5251

53-
// bucket/object metadata storage facility
54-
meta meta.MetadataStorer
55-
5652
// glaciermode enables the following behavior:
5753
// GET object: if file offline, return invalid object state
5854
// HEAD object: if file offline, set obj storage class to GLACIER
@@ -75,8 +71,6 @@ var _ backend.Backend = &ScoutFS{}
7571
const (
7672
metaTmpDir = ".sgwtmp"
7773
metaTmpMultipartDir = metaTmpDir + "/multipart"
78-
etagkey = "etag"
79-
checksumsKey = "checksums"
8074
)
8175

8276
var (
@@ -245,173 +239,25 @@ func (s *ScoutFS) GetObject(ctx context.Context, input *s3.GetObjectInput) (*s3.
245239
}
246240

247241
func (s *ScoutFS) ListObjects(ctx context.Context, input *s3.ListObjectsInput) (s3response.ListObjectsResult, error) {
248-
bucket := *input.Bucket
249-
prefix := ""
250-
if input.Prefix != nil {
251-
prefix = *input.Prefix
252-
}
253-
marker := ""
254-
if input.Marker != nil {
255-
marker = *input.Marker
256-
}
257-
delim := ""
258-
if input.Delimiter != nil {
259-
delim = *input.Delimiter
260-
}
261-
maxkeys := int32(0)
262-
if input.MaxKeys != nil {
263-
maxkeys = *input.MaxKeys
264-
}
265-
266-
_, err := os.Stat(bucket)
267-
if errors.Is(err, fs.ErrNotExist) {
268-
return s3response.ListObjectsResult{}, s3err.GetAPIError(s3err.ErrNoSuchBucket)
269-
}
270-
if err != nil {
271-
return s3response.ListObjectsResult{}, fmt.Errorf("stat bucket: %w", err)
272-
}
273-
274-
fileSystem := os.DirFS(bucket)
275-
results, err := backend.Walk(ctx, fileSystem, prefix, delim, marker, maxkeys,
276-
s.fileToObj(bucket), []string{metaTmpDir})
277-
if err != nil {
278-
return s3response.ListObjectsResult{}, fmt.Errorf("walk %v: %w", bucket, err)
279-
}
280-
281-
return s3response.ListObjectsResult{
282-
CommonPrefixes: results.CommonPrefixes,
283-
Contents: results.Objects,
284-
Delimiter: backend.GetPtrFromString(delim),
285-
Marker: backend.GetPtrFromString(marker),
286-
NextMarker: backend.GetPtrFromString(results.NextMarker),
287-
Prefix: backend.GetPtrFromString(prefix),
288-
IsTruncated: &results.Truncated,
289-
MaxKeys: &maxkeys,
290-
Name: &bucket,
291-
}, nil
242+
return s.Posix.ListObjectsParametrized(ctx, input, s.fileToObj)
292243
}
293244

294245
func (s *ScoutFS) ListObjectsV2(ctx context.Context, input *s3.ListObjectsV2Input) (s3response.ListObjectsV2Result, error) {
295-
bucket := *input.Bucket
296-
prefix := ""
297-
if input.Prefix != nil {
298-
prefix = *input.Prefix
299-
}
300-
marker := ""
301-
if input.ContinuationToken != nil {
302-
if input.StartAfter != nil {
303-
marker = max(*input.StartAfter, *input.ContinuationToken)
304-
} else {
305-
marker = *input.ContinuationToken
306-
}
307-
}
308-
delim := ""
309-
if input.Delimiter != nil {
310-
delim = *input.Delimiter
311-
}
312-
maxkeys := int32(0)
313-
if input.MaxKeys != nil {
314-
maxkeys = *input.MaxKeys
315-
}
316-
317-
_, err := os.Stat(bucket)
318-
if errors.Is(err, fs.ErrNotExist) {
319-
return s3response.ListObjectsV2Result{}, s3err.GetAPIError(s3err.ErrNoSuchBucket)
320-
}
321-
if err != nil {
322-
return s3response.ListObjectsV2Result{}, fmt.Errorf("stat bucket: %w", err)
323-
}
324-
325-
fileSystem := os.DirFS(bucket)
326-
results, err := backend.Walk(ctx, fileSystem, prefix, delim, marker, int32(maxkeys),
327-
s.fileToObj(bucket), []string{metaTmpDir})
328-
if err != nil {
329-
return s3response.ListObjectsV2Result{}, fmt.Errorf("walk %v: %w", bucket, err)
330-
}
331-
332-
count := int32(len(results.Objects))
333-
334-
return s3response.ListObjectsV2Result{
335-
CommonPrefixes: results.CommonPrefixes,
336-
Contents: results.Objects,
337-
IsTruncated: &results.Truncated,
338-
MaxKeys: &maxkeys,
339-
Name: &bucket,
340-
KeyCount: &count,
341-
Delimiter: backend.GetPtrFromString(delim),
342-
ContinuationToken: backend.GetPtrFromString(marker),
343-
NextContinuationToken: backend.GetPtrFromString(results.NextMarker),
344-
Prefix: backend.GetPtrFromString(prefix),
345-
StartAfter: backend.GetPtrFromString(*input.StartAfter),
346-
}, nil
246+
return s.Posix.ListObjectsV2Parametrized(ctx, input, s.fileToObj)
347247
}
348248

349-
func (s *ScoutFS) fileToObj(bucket string) backend.GetObjFunc {
350-
return func(path string, d fs.DirEntry) (s3response.Object, error) {
351-
objPath := filepath.Join(bucket, path)
352-
if d.IsDir() {
353-
// directory object only happens if directory empty
354-
// check to see if this is a directory object by checking etag
355-
etagBytes, err := s.meta.RetrieveAttribute(nil, bucket, path, etagkey)
356-
if errors.Is(err, meta.ErrNoSuchKey) || errors.Is(err, fs.ErrNotExist) {
357-
return s3response.Object{}, backend.ErrSkipObj
358-
}
359-
if err != nil {
360-
return s3response.Object{}, fmt.Errorf("get etag: %w", err)
361-
}
362-
etag := string(etagBytes)
363-
364-
fi, err := d.Info()
365-
if errors.Is(err, fs.ErrNotExist) {
366-
return s3response.Object{}, backend.ErrSkipObj
367-
}
368-
if err != nil {
369-
return s3response.Object{}, fmt.Errorf("get fileinfo: %w", err)
370-
}
371-
372-
size := int64(0)
373-
mtime := fi.ModTime()
374-
375-
return s3response.Object{
376-
ETag: &etag,
377-
Key: &path,
378-
LastModified: &mtime,
379-
Size: &size,
380-
StorageClass: types.ObjectStorageClassStandard,
381-
}, nil
382-
}
383-
384-
// Retreive the object checksum algorithm
385-
checksums, err := s.retrieveChecksums(nil, bucket, path)
386-
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
387-
return s3response.Object{}, backend.ErrSkipObj
388-
}
249+
func (s *ScoutFS) fileToObj(bucket string, fetchOwner bool) backend.GetObjFunc {
250+
posixFileToObj := s.Posix.FileToObj(bucket, fetchOwner)
389251

390-
// file object, get object info and fill out object data
391-
b, err := s.meta.RetrieveAttribute(nil, bucket, path, etagkey)
392-
if errors.Is(err, fs.ErrNotExist) {
393-
return s3response.Object{}, backend.ErrSkipObj
394-
}
395-
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
396-
return s3response.Object{}, fmt.Errorf("get etag: %w", err)
397-
}
398-
// note: meta.ErrNoSuchKey will return etagBytes = []byte{}
399-
// so this will just set etag to "" if its not already set
400-
401-
etag := string(b)
402-
403-
fi, err := d.Info()
404-
if errors.Is(err, fs.ErrNotExist) {
405-
return s3response.Object{}, backend.ErrSkipObj
406-
}
407-
if err != nil {
408-
return s3response.Object{}, fmt.Errorf("get fileinfo: %w", err)
252+
return func(path string, d fs.DirEntry) (s3response.Object, error) {
253+
res, err := posixFileToObj(path, d)
254+
if err != nil || d.IsDir() {
255+
return res, err
409256
}
410-
411-
sc := types.ObjectStorageClassStandard
257+
objPath := filepath.Join(bucket, path)
412258
if s.glaciermode {
413259
// Check if there are any offline exents associated with this file.
414-
// If so, we will return the InvalidObjectState error.
260+
// If so, we will return the Glacier storage class
415261
st, err := statMore(objPath)
416262
if errors.Is(err, fs.ErrNotExist) {
417263
return s3response.Object{}, backend.ErrSkipObj
@@ -420,33 +266,11 @@ func (s *ScoutFS) fileToObj(bucket string) backend.GetObjFunc {
420266
return s3response.Object{}, fmt.Errorf("stat more: %w", err)
421267
}
422268
if st.Offline_blocks != 0 {
423-
sc = types.ObjectStorageClassGlacier
269+
res.StorageClass = types.ObjectStorageClassGlacier
424270
}
425271
}
426-
427-
size := fi.Size()
428-
mtime := fi.ModTime()
429-
430-
return s3response.Object{
431-
ETag: &etag,
432-
Key: &path,
433-
LastModified: &mtime,
434-
Size: &size,
435-
StorageClass: sc,
436-
ChecksumAlgorithm: []types.ChecksumAlgorithm{checksums.Algorithm},
437-
ChecksumType: checksums.Type,
438-
}, nil
439-
}
440-
}
441-
442-
func (s *ScoutFS) retrieveChecksums(f *os.File, bucket, object string) (checksums s3response.Checksum, err error) {
443-
checksumsAtr, err := s.meta.RetrieveAttribute(f, bucket, object, checksumsKey)
444-
if err != nil {
445-
return checksums, err
272+
return res, nil
446273
}
447-
448-
err = json.Unmarshal(checksumsAtr, &checksums)
449-
return checksums, err
450274
}
451275

452276
// RestoreObject will set stage request on file if offline and do nothing if

backend/scoutfs/scoutfs_compat.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ func New(rootdir string, opts ScoutfsOpts) (*ScoutFS, error) {
4848
Posix: p,
4949
rootfd: f,
5050
rootdir: rootdir,
51-
meta: metastore,
5251
glaciermode: opts.GlacierMode,
5352
disableNoArchive: opts.DisableNoArchive,
5453
}, nil

0 commit comments

Comments
 (0)