github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/storage/storage.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storage 5 6 import ( 7 "io" 8 9 "gopkg.in/juju/blobstore.v2" 10 "gopkg.in/mgo.v2" 11 ) 12 13 const ( 14 // metadataDB is the name of the blobstore metadata database. 15 metadataDB = "juju" 16 17 // blobstoreDB is the name of the blobstore GridFS database. 18 blobstoreDB = "blobstore" 19 ) 20 21 // Storage is an interface providing methods for storing and retrieving 22 // data by path. 23 type Storage interface { 24 // Get returns an io.ReadCloser for data at path, namespaced to the 25 // model. 26 // 27 // If the data is still being uploaded and is not fully written yet, a 28 // blobstore.ErrUploadPending error is returned. This means the path is 29 // valid but the caller should try again later to retrieve the data. 30 Get(path string) (r io.ReadCloser, length int64, err error) 31 32 // Put stores data from reader at path, namespaced to the model. 33 Put(path string, r io.Reader, length int64) error 34 35 // PutAndCheckHash stores data from reader at path, namespaced to 36 // the model. It also ensures the stored data has the correct 37 // hash. 38 PutAndCheckHash(path string, r io.Reader, length int64, hash string) error 39 40 // Remove removes data at path, namespaced to the model. 41 Remove(path string) error 42 } 43 44 // Storage returns a Storage for the model with the specified UUID. 45 func NewStorage(modelUUID string, session *mgo.Session) Storage { 46 return stateStorage{modelUUID, session} 47 } 48 49 type stateStorage struct { 50 modelUUID string 51 session *mgo.Session 52 } 53 54 func (s stateStorage) blobstore() (*mgo.Session, blobstore.ManagedStorage) { 55 session := s.session.Copy() 56 rs := blobstore.NewGridFS(blobstoreDB, blobstoreDB, session) 57 db := session.DB(metadataDB) 58 return session, blobstore.NewManagedStorage(db, rs) 59 } 60 61 func (s stateStorage) Get(path string) (r io.ReadCloser, length int64, err error) { 62 session, ms := s.blobstore() 63 r, length, err = ms.GetForBucket(s.modelUUID, path) 64 if err != nil { 65 session.Close() 66 return nil, -1, err 67 } 68 return &stateStorageReadCloser{r, session}, length, nil 69 } 70 71 func (s stateStorage) Put(path string, r io.Reader, length int64) error { 72 session, ms := s.blobstore() 73 defer session.Close() 74 return ms.PutForBucket(s.modelUUID, path, r, length) 75 } 76 77 func (s stateStorage) PutAndCheckHash(path string, r io.Reader, length int64, hash string) error { 78 session, ms := s.blobstore() 79 defer session.Close() 80 return ms.PutForBucketAndCheckHash(s.modelUUID, path, r, length, hash) 81 } 82 83 func (s stateStorage) Remove(path string) error { 84 session, ms := s.blobstore() 85 defer session.Close() 86 return ms.RemoveForBucket(s.modelUUID, path) 87 } 88 89 type stateStorageReadCloser struct { 90 io.ReadCloser 91 session *mgo.Session 92 } 93 94 func (r *stateStorageReadCloser) Close() error { 95 r.session.Close() 96 return r.ReadCloser.Close() 97 }