github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/backend.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "github.com/juju/errors" 8 9 "github.com/juju/juju/mongo" 10 ) 11 12 // modelBackend collects together some useful internal state methods for 13 // accessing mongo and mapping local and global ids to one another. 14 // 15 // Its primary purpose is to insulate watcher implementations from the 16 // other features of state (specifically, to deny access to the .workers 17 // field and prevent a class of bug in which it tries to use two 18 // different underlying TxnWatchers), but it's probably also useful 19 // elsewhere. 20 type modelBackend interface { 21 docID(string) string 22 localID(string) string 23 strictLocalID(string) (string, error) 24 getCollection(name string) (mongo.Collection, func()) 25 getCollectionFor(modelUUID, name string) (mongo.Collection, func()) 26 } 27 28 // isLocalID returns a watcher filter func that rejects ids not specific 29 // to the supplied modelBackend. 30 func isLocalID(st modelBackend) func(interface{}) bool { 31 return func(id interface{}) bool { 32 key, ok := id.(string) 33 if !ok { 34 return false 35 } 36 _, err := st.strictLocalID(key) 37 return err == nil 38 } 39 } 40 41 // docID generates a globally unique id value 42 // where the model uuid is prefixed to the 43 // localID. 44 func (st *State) docID(localID string) string { 45 return ensureModelUUID(st.ModelUUID(), localID) 46 } 47 48 // localID returns the local id value by stripping 49 // off the model uuid prefix if it is there. 50 func (st *State) localID(ID string) string { 51 modelUUID, localID, ok := splitDocID(ID) 52 if !ok || modelUUID != st.ModelUUID() { 53 return ID 54 } 55 return localID 56 } 57 58 // strictLocalID returns the local id value by removing the 59 // model UUID prefix. 60 // 61 // If there is no prefix matching the State's model, an error is 62 // returned. 63 func (st *State) strictLocalID(ID string) (string, error) { 64 modelUUID, localID, ok := splitDocID(ID) 65 if !ok || modelUUID != st.ModelUUID() { 66 return "", errors.Errorf("unexpected id: %#v", ID) 67 } 68 return localID, nil 69 } 70 71 // getCollection fetches a named collection using a new session if the 72 // database has previously been logged in to. It returns the 73 // collection and a closer function for the session. 74 // 75 // If the collection stores documents for multiple models, the 76 // returned collection will automatically perform model 77 // filtering where possible. See modelStateCollection below. 78 func (st *State) getCollection(name string) (mongo.Collection, func()) { 79 return st.database.GetCollection(name) 80 } 81 82 func (st *State) getCollectionFor(modelUUID, name string) (mongo.Collection, func()) { 83 database, dbcloser := st.database.CopyForModel(modelUUID) 84 collection, closer := database.GetCollection(name) 85 return collection, func() { 86 closer() 87 dbcloser() 88 } 89 }