diff --git a/pkg/donutbox/donutbox.go b/pkg/donutbox/donutbox.go new file mode 100644 index 000000000..91b82b8de --- /dev/null +++ b/pkg/donutbox/donutbox.go @@ -0,0 +1,26 @@ +package donutbox + +import "io" + +// DonutBox is an interface specifying how the storage driver should interact with its underlying system. +type DonutBox interface { + // system operations + ListBuckets() ([]string, error) + + // bucket operations + CreateBucket(bucket string) error + ListObjects(bucket, prefix string) ([]string, error) + GetBucketMetadata(bucket, name string) (io.Reader, error) + SetBucketMetadata(bucket, name string, metadata io.Reader) error + + // object operations + GetObjectWriter(bucket, object string, column, blockSize uint) (io.WriteCloser, <-chan Result, error) + GetObjectReader(bucket, object string, column int) (io.Reader, error) + StoreObjectMetadata(bucket, object, name string, reader io.Reader) error + GetObjectMetadata(bucket, object, name string) (io.Reader, error) +} + +// Result is a result for async tasks +type Result struct { + Err error +} diff --git a/pkg/donutbox/donutfs/donutfs.go b/pkg/donutbox/donutfs/donutfs.go new file mode 100644 index 000000000..935d80ab7 --- /dev/null +++ b/pkg/donutbox/donutfs/donutfs.go @@ -0,0 +1 @@ +package donutfs diff --git a/pkg/donutbox/donutfs/donutfs_test.go b/pkg/donutbox/donutfs/donutfs_test.go new file mode 100644 index 000000000..935d80ab7 --- /dev/null +++ b/pkg/donutbox/donutfs/donutfs_test.go @@ -0,0 +1 @@ +package donutfs diff --git a/pkg/donutbox/donutmem/donutmem.go b/pkg/donutbox/donutmem/donutmem.go new file mode 100644 index 000000000..dd4e02381 --- /dev/null +++ b/pkg/donutbox/donutmem/donutmem.go @@ -0,0 +1,108 @@ +package donutmem + +import ( + "bytes" + "errors" + "github.com/minio-io/minio/pkg/donutbox" + "io" + "strconv" + "strings" +) + +type bucket struct { + name string + metadata map[string]string + objects map[string]object +} + +type object struct { + name string + data []byte + metadata map[string]string +} + +type donutMem struct { + buckets map[string]bucket +} + +// NewDonutMem creates a new in memory donut +func NewDonutMem() donutbox.DonutBox { + return donutMem{ + buckets: make(map[string]bucket), + } +} + +// system operations +func (donutMem donutMem) ListBuckets() ([]string, error) { + return nil, errors.New("Not Implemented") +} + +// bucket operations +func (donutMem donutMem) CreateBucket(b string) error { + b = strings.ToLower(b) + if _, ok := donutMem.buckets[b]; ok { + return errors.New("Bucket Exists") + } + metadata := make(map[string]string) + metadata["name"] = b + newBucket := bucket{ + name: b, + metadata: metadata, + objects: make(map[string]object), + } + donutMem.buckets[b] = newBucket + return nil +} +func (donutMem donutMem) ListObjects(bucket, prefix string) ([]string, error) { + return nil, errors.New("Not Implemented") +} +func (donutMem donutMem) GetBucketMetadata(bucket, name string) (io.Reader, error) { + return nil, errors.New("Not Implemented") +} +func (donutMem donutMem) SetBucketMetadata(bucket, name string, metadata io.Reader) error { + return errors.New("Not Implemented") +} + +// object operations +func (donutMem donutMem) GetObjectWriter(bucket, key string, column uint, blockSize uint) (io.WriteCloser, <-chan donutbox.Result, error) { + if _, ok := donutMem.buckets[bucket]; ok { + if _, ok := donutMem.buckets[bucket].objects[key]; !ok { + reader, writer := io.Pipe() + ch := make(chan donutbox.Result) + go func() { + var objBuffer bytes.Buffer + _, err := io.Copy(&objBuffer, reader) + metadata := make(map[string]string) + metadata["key"] = key + metadata["blockSize"] = strconv.FormatInt(int64(blockSize), 10) + if err == nil { + newObject := object{ + name: key, + data: objBuffer.Bytes(), + metadata: metadata, + } + donutMem.buckets[bucket].objects[key] = newObject + } + ch <- donutbox.Result{Err: err} + }() + return writer, ch, nil + } + return nil, nil, errors.New("Object exists") + } + return nil, nil, errors.New("Bucket not found") +} +func (donutMem donutMem) GetObjectReader(bucket, key string, column int) (io.Reader, error) { + if b, ok := donutMem.buckets[bucket]; ok { + if obj, ok := b.objects[key]; ok { + return bytes.NewBuffer(obj.data), nil + } + return nil, errors.New("Object not found") + } + return nil, errors.New("Bucket not found") +} +func (donutMem donutMem) StoreObjectMetadata(bucket, object, name string, reader io.Reader) error { + return errors.New("Not Implemented") +} +func (donutMem donutMem) GetObjectMetadata(bucket, object, name string) (io.Reader, error) { + return nil, errors.New("Not Implemented") +} diff --git a/pkg/donutbox/donutmem/donutmem_test.go b/pkg/donutbox/donutmem/donutmem_test.go new file mode 100644 index 000000000..376d618dc --- /dev/null +++ b/pkg/donutbox/donutmem/donutmem_test.go @@ -0,0 +1,44 @@ +package donutmem + +import ( + "testing" + + "bytes" + . "gopkg.in/check.v1" + "io" +) + +func Test(t *testing.T) { TestingT(t) } + +type MySuite struct{} + +var _ = Suite(&MySuite{}) + +func (s *MySuite) TestAPISuite(c *C) { + c.Skip("Not implemented") + donut := NewDonutMem() + + writer, ch, err := donut.GetObjectWriter("foo", "bar", 0, 2) + c.Assert(writer, IsNil) + c.Assert(ch, IsNil) + c.Assert(err, Not(IsNil)) + + err = donut.CreateBucket("foo") + c.Assert(err, IsNil) + + writer, ch, err = donut.GetObjectWriter("foo", "bar", 0, 2) + c.Assert(err, IsNil) + c.Assert(ch, Not(IsNil)) + writer.Write([]byte("Hello World")) + writer.Close() + res := <-ch + c.Assert(res.Err, IsNil) + + reader, err := donut.GetObjectReader("foo", "bar", 0) + c.Assert(err, IsNil) + var target bytes.Buffer + _, err = io.Copy(&target, reader) + c.Assert(err, IsNil) + c.Assert(target.Bytes(), DeepEquals, []byte("Hello World")) + +} diff --git a/pkg/storage/encoded/encoded.go b/pkg/storage/encoded/encoded.go index 4b36ee769..78c327b6a 100644 --- a/pkg/storage/encoded/encoded.go +++ b/pkg/storage/encoded/encoded.go @@ -18,21 +18,14 @@ package encoded import ( "errors" + "github.com/minio-io/minio/pkg/donutbox" "github.com/minio-io/minio/pkg/storage" "io" ) // StorageDriver creates a new single disk storage driver using donut without encoding. type StorageDriver struct { - donutBox DonutBox -} - -// DonutBox is an interface specifying how the storage driver should interact with its underlying system. -type DonutBox interface { - Store() error - Get() (io.Reader, error) - ListObjects(bucket string) ([]string, error) - ListBuckets() ([]string, error) + donutBox donutbox.DonutBox } // Start a single disk subsystem