66 "context"
77 "crypto/md5"
88 "encoding/hex"
9+ "errors"
910 "fmt"
1011 "io"
1112 "path"
@@ -24,7 +25,8 @@ import (
2425var (
2526 hashType = hash .MD5
2627 // the object storage is persistent
27- buckets = newBucketsInfo ()
28+ buckets = newBucketsInfo ()
29+ errWriteOnly = errors .New ("can't read when using --memory-discard" )
2830)
2931
3032// Register with Fs
@@ -33,12 +35,32 @@ func init() {
3335 Name : "memory" ,
3436 Description : "In memory object storage system." ,
3537 NewFs : NewFs ,
36- Options : []fs.Option {},
38+ Options : []fs.Option {{
39+ Name : "discard" ,
40+ Default : false ,
41+ Advanced : true ,
42+ Help : `If set all writes will be discarded and reads will return an error
43+
44+ If set then when files are uploaded the contents not be saved. The
45+ files will appear to have been uploaded but will give an error on
46+ read. Files will have their MD5 sum calculated on upload which takes
47+ very little CPU time and allows the transfers to be checked.
48+
49+ This can be useful for testing performance.
50+
51+ Probably most easily used by using the connection string syntax:
52+
53+ :memory,discard:bucket
54+
55+ ` ,
56+ }},
3757 })
3858}
3959
4060// Options defines the configuration for this backend
41- type Options struct {}
61+ type Options struct {
62+ Discard bool `config:"discard"`
63+ }
4264
4365// Fs represents a remote memory server
4466type Fs struct {
@@ -164,6 +186,7 @@ type objectData struct {
164186 hash string
165187 mimeType string
166188 data []byte
189+ size int64
167190}
168191
169192// Object describes a memory object
@@ -558,7 +581,7 @@ func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) {
558581 if t != hashType {
559582 return "" , hash .ErrUnsupported
560583 }
561- if o .od .hash == "" {
584+ if o .od .hash == "" && ! o . fs . opt . Discard {
562585 sum := md5 .Sum (o .od .data )
563586 o .od .hash = hex .EncodeToString (sum [:])
564587 }
@@ -567,7 +590,7 @@ func (o *Object) Hash(ctx context.Context, t hash.Type) (string, error) {
567590
568591// Size returns the size of an object in bytes
569592func (o * Object ) Size () int64 {
570- return int64 ( len ( o .od .data ))
593+ return o .od .size
571594}
572595
573596// ModTime returns the modification time of the object
@@ -593,6 +616,9 @@ func (o *Object) Storable() bool {
593616
594617// Open an object for read
595618func (o * Object ) Open (ctx context.Context , options ... fs.OpenOption ) (in io.ReadCloser , err error ) {
619+ if o .fs .opt .Discard {
620+ return nil , errWriteOnly
621+ }
596622 var offset , limit int64 = 0 , - 1
597623 for _ , option := range options {
598624 switch x := option .(type ) {
@@ -624,13 +650,24 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read
624650// The new object may have been created if an error is returned
625651func (o * Object ) Update (ctx context.Context , in io.Reader , src fs.ObjectInfo , options ... fs.OpenOption ) (err error ) {
626652 bucket , bucketPath := o .split ()
627- data , err := io .ReadAll (in )
653+ var data []byte
654+ var size int64
655+ var hash string
656+ if o .fs .opt .Discard {
657+ h := md5 .New ()
658+ size , err = io .Copy (h , in )
659+ hash = hex .EncodeToString (h .Sum (nil ))
660+ } else {
661+ data , err = io .ReadAll (in )
662+ size = int64 (len (data ))
663+ }
628664 if err != nil {
629665 return fmt .Errorf ("failed to update memory object: %w" , err )
630666 }
631667 o .od = & objectData {
632668 data : data ,
633- hash : "" ,
669+ size : size ,
670+ hash : hash ,
634671 modTime : src .ModTime (ctx ),
635672 mimeType : fs .MimeType (ctx , src ),
636673 }
0 commit comments