github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/state/bakerystorage/storage.go (about) 1 // Copyright 2014-2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package bakerystorage 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "gopkg.in/macaroon-bakery.v1/bakery" 11 "gopkg.in/mgo.v2" 12 ) 13 14 var expiryTimeIndex = mgo.Index{ 15 Key: []string{"expire-at"}, 16 Sparse: true, 17 18 // We expire records when the clock time is one 19 // second older than the record's expire-at field 20 // value. It has to be at least one second, because 21 // mgo uses "omitempty" for this field. 22 ExpireAfter: time.Second, 23 } 24 25 type storage struct { 26 config Config 27 expireAt time.Time 28 } 29 30 type storageDoc struct { 31 Location string `bson:"_id"` 32 Item string `bson:"item"` 33 ExpireAt time.Time `bson:"expire-at,omitempty"` 34 } 35 36 // ExpireAt implements ExpirableStorage.ExpireAt. 37 func (s *storage) ExpireAt(expireAt time.Time) ExpirableStorage { 38 return &storage{s.config, expireAt} 39 } 40 41 // Put implements bakery.Storage.Put. 42 func (s *storage) Put(location, item string) error { 43 coll, closer := s.config.GetCollection() 44 defer closer() 45 46 doc := storageDoc{ 47 Location: location, 48 Item: item, 49 } 50 if !s.expireAt.IsZero() { 51 // NOTE(axw) we subtract one second from the expiry time, because 52 // the expireAfterSeconds index we create is 1 and not 0 due to 53 // a limitation in the mgo EnsureIndex API. 54 doc.ExpireAt = s.expireAt.Add(-1 * time.Second) 55 } 56 _, err := coll.Writeable().UpsertId(location, doc) 57 if err != nil { 58 return errors.Annotatef(err, "cannot store item for location %q", location) 59 } 60 return nil 61 } 62 63 // Get implements bakery.Storage.Get. 64 func (s *storage) Get(location string) (string, error) { 65 coll, closer := s.config.GetCollection() 66 defer closer() 67 68 var i storageDoc 69 err := coll.FindId(location).One(&i) 70 if err != nil { 71 if err == mgo.ErrNotFound { 72 return "", bakery.ErrNotFound 73 } 74 return "", errors.Annotatef(err, "cannot get item for location %q", location) 75 } 76 return i.Item, nil 77 } 78 79 // Del implements bakery.Storage.Del. 80 func (s *storage) Del(location string) error { 81 coll, closer := s.config.GetCollection() 82 defer closer() 83 84 err := coll.Writeable().RemoveId(location) 85 if err != nil { 86 if err == mgo.ErrNotFound { 87 // Not an error to remove an item that doesn't exist. 88 return nil 89 } 90 return errors.Annotatef(err, "cannot remove item for location %q", location) 91 } 92 return nil 93 }