New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce state/toolstorage #663
Conversation
This seems eerily similar to what I've done for backups. I added github.com/juju/utils/filestorage as the abstraction of the file + metadata storage model. The implementation for backups lives in state/backups.go. The big wins were improved test isolation and ease of switching from one storage back end to another (e.g. env storage to gridFS). It wouldn't surprise me if I missed something, but is there any reason not to re-use at least some of what I've done for backups? |
// ToolsStorage returns a new toolstorage.StorageCloser | ||
// that stores tools metadata in the "juju" database'' | ||
// "toolsmetadata" collection. | ||
func (st *State) ToolsStorage() (toolstorage.StorageCloser, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewToolsStorage() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not keen, as it suggests to me that we're creating (and later destroying) the storage. It's more like we're "opening" the storage.
@ericsnowcurrently There are some similarities, yes. There are some significant differences, too, which could possibly be rectified by I'm not sure. For example, in the tools storage the metadata must not be written if the blob is not written, or clients may find tools that they cannot download. Other differences are:
The ManagedStorage could potentially adapt to RawFileStorage, but I'm not sure it's worthwhile. ManagedStorage is already an interface that can be mocked out. |
managedStorage, session := st.getManagedStorage(uuid) | ||
txnRunner := st.txnRunnerWith(session) | ||
metadataCollection := st.db.With(session).C(toolsmetadataC) | ||
storage := toolstorageNewStorage(uuid, managedStorage, metadataCollection, txnRunner) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can rework stuff here to be able to reuse the existing txnRunner() method and not have to create a new variant. It will require changes to getManagedStorage() and even txnRunner() itself which is only used in 3 places. I think this will make the code cleaner too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed txnRunner
to also return the session. I realised while doing this that we don't need the "authenticated" logic around copying sessions anymore, since we run mongo in the tests without auth, and in production we never open state without a tag/password anymore. So, I cleaned it up.
state/toolstorage provides an interface, Storage, for storing tools tarballs and metadata in state. The tarballs are stored in GridFS, while the metadata are stored in a Mongo collection. State grows a single new method, ToolsStorage, which constructs a toolstorage.StorageCloser. The returned object will store tools metadata in the "juju" database's "toolsmetadata" collection, and the tarballs in the "blobstore" database.
Don't need the "authenticated" logic around session copying anymore, as we now run mongo without auth in the tests, and in production we always open state with a tag/password. txnRunner now returns the session associated with the runner, and getManagedStorage and ToolsStorage are updated to use that. txnRunnerWith is dropped.
34f3652
to
42d780a
Compare
PTAL. |
closer = emptycloser | ||
// Otherwise the session is copied and a new instance is created | ||
// using that. | ||
func (st *State) txnRunner() (jujutxn.Runner, *mgo.Session, closeFunc) { | ||
if st.transactionRunner != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have done it, but could you please add a comment saying that the transactionRunner attribute is one set by tests so that the tests that use txn hooks work correctly? Normally in production code we fall through to create a new runner each time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
LGTM with extra txnRunner cleanup (sorry!) |
|
Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju |
Introduce state/toolstorage state/toolstorage provides an interface, Storage, for storing tools tarballs and metadata in state. The tarballs are stored in GridFS, while the metadata are stored in a Mongo collection. State grows a single new method, ToolsStorage, which constructs a toolstorage.StorageCloser. The returned object will store tools metadata in the "juju" database's "toolsmetadata" collection, and the tarballs in the "blobstore" database.
) | ||
|
||
// ToolsStorage returns a new toolstorage.StorageCloser | ||
// that stores tools metadata in the "juju" database'' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/database''/database's/ ? or just drop the '' entirely?
On Wed, Sep 3, 2014 at 7:22 PM, Andrew Wilkins notifications@github.com
Or do you mean that filestorage.Metadata has too much stuff and you want a Also, William made it clear to me that he wanted a strict distinction
Anyway, thanks for giving it some thought. I still think the benefits of To be honest I also think filestorage implementations for mongo However, there isn't exactly time for us to make all that happen. So in Would you mind just aligning toolstorage's Metadata and Storage with their |
Whoa. That was longer than I expected. FYI, I recognize that you have a better sense of the whole juju picture than I do and that I definitely have a purist/pro-abstractions inclination (i.e. compulsion ). So while I stand by what I say, I try not to be too stubborn about it unless I feel excessively strongly about it. If I haven't made a convincing argument then at the least please correct my incorrect perceptions and take this as an opportunity to enlighten me. :) The project benefits when we share like that! |
On Fri, Sep 5, 2014 at 12:10 AM, ericsnowcurrently <notifications@github.com
Not that comes to mind. It would be good to have something common.
Cool. I was concerned that we would require different behaviour, but if
I'm not concerned about the number of bytes stored. My preference is always I think there would be no problem with using filestorage internally in Also, William made it clear to me that he wanted a strict distinction
I mean that toolstorage.Storage.AddFile needs to overwrite tools metadata
I wish I knew the intent of filestorage before. Sorry, I hadn't looked into juju/blobstore is also used by juju/charmstore.
And I also have a lot of work to do around this.
I will have a look when I get my current work under control |
Cool. Thanks for following up on that Andrew. FYI, the implementation for FileStorage currently will leave the metadata stored even if storing the file itself fails. I'll work up a patch to fix that. |
state/toolstorage provides an interface, Storage,
for storing tools tarballs and metadata in state.
The tarballs are stored in GridFS, while the
metadata are stored in a Mongo collection.
State grows a single new method, ToolsStorage,
which constructs a toolstorage.StorageCloser.
The returned object will store tools metadata in
the "juju" database's "toolsmetadata" collection,
and the tarballs in the "blobstore" database.