-
Notifications
You must be signed in to change notification settings - Fork 210
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
Isolate each Database when initializing the module #1486
Conversation
fedimint-api/src/db/mod.rs
Outdated
@@ -247,6 +261,77 @@ impl Drop for CommitTracker { | |||
} | |||
} | |||
|
|||
/// ModuleDatabaseTransaction is a wrapper around IsolatedDatabaseTransaction that |
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.
Why do we need ... a wrapper around a wrapper? Could this be just
struct ModuleDatabaseTransaction<'a> {
dbtx: DatabaseTransaction<'a>,
}
where dbtx
is already wrapped?
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 actually running into problems when I do that, because the with_module_prefix
function takes a mutable reference to self, so it is still borrowed when trying to return the new ModuleDatabaseTransaction (that has a wrapped dbtx).
cannot return value referencing function parameter dbtx
returns a value referencing data owned by the current function
Let me know if I'm missing something but the current way seems the easiest to me?
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.
It should work - in similar way that it works for IsolatedDatabaseTransaction
to wrap the inner transaction.
Possibly here you need dbtx: &mut dyn IDatabaseTransaction<'a>
as well - same way?
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 don't think that works either, otherwise I could just reuse IsolatedDatabaseTransaction and I wouldn't need another wrapper. I believe the issue is that I need to create a DatabaseTransaction in begin_transaction that is wrapped, from nothing. I can't borrow a DatabaseTransaction that was created in begin_transaction and then return the new wrapped one, because the new one still has a reference to the old one that has now dropped out of scope.
38ce774
to
69bfae8
Compare
pub fn new_module_tx( | ||
self, | ||
module_instance_id: ModuleInstanceId, | ||
) -> DatabaseTransaction<'parent> { | ||
let decoders = self.decoders.clone(); | ||
let commit_tracker = self.commit_tracker.clone(); | ||
let wrapped = ModuleDatabaseTransaction::new(self, module_instance_id); | ||
DatabaseTransaction { | ||
tx: Box::new(wrapped), | ||
decoders, | ||
commit_tracker, | ||
} | ||
} | ||
|
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.
Am I correct to assume that this tx can never be committed since <ModuleDatabaseTransaction as IDatabaseTransaction>::commit_tx
panics? If so we need to document it. Maybe we can even reproduce the behavior in a test using should_panic
or catch_unwind
.
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.
Hmm that's how its coded right now, but I'm up for discussing whether or not they should.
IsolatedDatabaseTransaction
can never be committed because they do not own the transaction that can be committed. But this API allows a module (assuming it has access to a Database
handle, which it does during ModuleGen
), to own a transaction. Right now this is only used in the wallet module and is read-only, so its not a problem, but perhaps other modules will want to write into the database during ModuleGen
. What do you guys think?
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.
Thinking about this a bit more, I think we should let them commit. That's what makes 'ModuleDatabaseTransaction' and IsolatedDatabaseTransaction
different. IsolatedDatabaseTransaction
needs to be created from outside the module and borrowed when passed into the module. ModuleDatabaseTransaction
allows a module to own the transaction so it should be able to commit it if it needs to.
I'll add this to the documentation.
I feel like eventually we'll have to think about these new requirements holistically and come up with a better overall architecture. But for now this seems ready for mergig except for a few minor nits. Thoughts @dpc? |
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.
Good enough. These owned vs borrowed seems weirdly inconsistent, but if it works, then we're good for now.
…wed ModuleDatabaseTransactions to commit
As a follow up to #1331, this PR allows for entire Databases to be isolated instead of just individual DatabaseTransactions. We want the ability to isolate Databases and DatabaseTransactions because there are some db transactions that need to atomically span multiple modules, but we also sometimes give each module a handle to the database, such as during module_initialization (this db handle is only used in the wallet module currently).
Isolated databases have the same API as normal databases accept that begin_transaction now returns a DatabaseTransaction that is isolated, so all operations will have a prefix prepended to each key to keep the data separate.