Skip to content
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

Merged
merged 2 commits into from
Jan 25, 2023

Conversation

m1sterc001guy
Copy link
Contributor

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.

@@ -247,6 +261,77 @@ impl Drop for CommitTracker {
}
}

/// ModuleDatabaseTransaction is a wrapper around IsolatedDatabaseTransaction that
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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.

fedimint-api/src/db/mod.rs Outdated Show resolved Hide resolved
fedimint-api/src/db/mod.rs Show resolved Hide resolved
fedimint-api/src/db/mod.rs Outdated Show resolved Hide resolved
Comment on lines +486 to +499
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,
}
}

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor Author

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.

@elsirion
Copy link
Contributor

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?

dpc
dpc previously approved these changes Jan 25, 2023
Copy link
Contributor

@dpc dpc left a 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants