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  }