-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
refactor: Changes to AppModuleGenesis for concurrent modules' genesis states unmarshaling #12295
Conversation
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.
Excellent work!
types/module/module.go
Outdated
wg.Add(1) | ||
go func(moduleName string) { | ||
defer wg.Done() | ||
genesisStates[moduleName] = m.Modules[moduleName].UnmarshalGenesis(cdc, genesisData[moduleName]) |
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.
There is concurrent access to genesisStates
, which might trip off any race detectors. While in practice this should be OK since each goroutine accesses it's own unique key in genesisStates
, we might wanna make this thread-safe. Perhaps Manager
could have a mutex.
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.
This wasn't safe as written before! As genesisStates is a hashmap, with grow operations =p (You can not safely parallel write to new keys in a hashmap ~ever. Depending on implementation you can update existing keys, or deflate some of the unsafe concurrency in new keys)
The mutex operations were definitely needed for correctness
Co-authored-by: Aleksandr Bezobchuk <[email protected]>
8a7f4d5
to
acce5fa
Compare
Co-authored-by: Aleksandr Bezobchuk <[email protected]>
45a2a6e
to
78ee2c2
Compare
high level question, how would this differ from genesis streaming? I think part of the bottleneck is we load everything into memory then call init genesis, but if we streamed it as it was coming in, it may be faster than this approach? |
It's orthogonal somewhat @marbar3778 -- AFAIK, streaming is still in R&D or even just a rough idea ATM. This PR is just a small win in the context of the current design of "load and init". |
This is a breaking change for all API consumers -- not sure how the rollout plan for this one will look. Not really in favor of merging until that has a plan. Also would like to note in weighting the API break, this is good, but really not even 1% of the time in Genesis initialization for large states. Thats really all in DB work. Nor is this a dev UX improvement. If we really wanted it, would be nice if its something we could gate behind an extension API, or part of app wiring. But to be honest, if we take a step back, I've always been puzzled as to why is the AppModule even responsible for the unmarshal logic. Why can't module registration communicate the Genesis type (via function or generic), and the global system handles the unmarshalling into the correct type (as done here). This could be done by making So this would look like the following type signatures changing from these befores: func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {}
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {} to this after func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) proto.Message {}
func (am AppModule) InitGenesis(ctx sdk.Context, genesisState proto.Message) []abci.ValidatorUpdate {} The change here would involve less of a migration overhead (deleting code), rather than also writing a second function and shuffling stuff around. This would also carry with it longer term dev UX improvements, rather than making the already bad dev UX worse =p So if we wanted this, I think we should push for ^^, but still unclear to me if worth the tradeoff. If we lived in a world with generics with associated types (Rust style), these args could each be of the desired type, but I don't know how to do it in golang. |
Co-authored-by: Dev Ojha <[email protected]>
go func(moduleName string) { | ||
defer wg.Done() | ||
moduleGenesis := m.Modules[moduleName].UnmarshalGenesis(cdc, genesisData[moduleName]) | ||
m.mtx.Lock() | ||
genesisStates[moduleName] = moduleGenesis | ||
m.mtx.Unlock() | ||
}(moduleName) |
Check notice
Code scanning / CodeQL
Spawning a Go routine
should I close this ? |
Description
Change AppModuleGenesis interface for concurrent modules' genesis states unmarshaling.
Changes
ModuleManager
for unmarshaling modules'GenesisState
UnmarshalGenesis
toAppModule
interface for unmarshaling modules'GenesisState
, changingAppModule.InitGenesis
params from (sdk.Context, codec.JSONCodec, json.RawMessage) to (sdk.Context, proto.Message) so thatAppModule.InitGenesis
only does the work ofmodule initialization
with the passed in unmarshaledGenesisState
.Closes: #12172
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!
to the type prefix if API or client breaking changeCHANGELOG.md
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
I have...
!
in the type prefix if API or client breaking change