-
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: remove defer
in loop
#20223
Conversation
WalkthroughWalkthroughThe recent changes across the codebase focus on refining error handling and resource management practices. By utilizing closures and optimizing resource closure strategies, these updates enhance error reporting, streamline resource cleanup, and improve the overall code reliability. These adjustments aim to enhance control flow, aligning with best practices in software development. Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (invoked as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
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.
Actionable comments posted: 6
x/group/keeper/invariants.go
Outdated
err = memIt.Close() | ||
if err != nil { | ||
return "", broken | ||
} |
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.
Ensure proper error handling when closing the memIt
iterator.
- err = memIt.Close()
- if err != nil {
- return "", broken
- }
+ if err := memIt.Close(); err != nil {
+ return fmt.Sprintf("failed to close member iterator: %v", err), true
+ }
This change ensures that any error during the closing of the memIt
iterator is properly handled and reported, which aligns with the PR's objective of improving error handling in resource management.
Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
err = memIt.Close() | |
if err != nil { | |
return "", broken | |
} | |
if err := memIt.Close(); err != nil { | |
return fmt.Sprintf("failed to close member iterator: %v", err), true | |
} |
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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.
Hey if things are viewed as performance it would be good to get a benchmark. Thank you for the many prs you are making.
defer
in loopdefer
in loop
Thanks for your review! @tac0turtle I'll update the PR title from Please let me know if you have any other suggestions or concerns. I appreciate your feedback and support! |
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.
Thank you for these fixes @tropicaldog! I've added some suggestions for correctness by using anonymous closures because the current changes make the resource releases less likely due to the large number of branches.
Also you could please update the commit description to say
In Go, defers are only invoked in a terminal statement such as a return or panic;
invoking them in a for-loop means that all those resources will not be released
and will build up until the entire function returns or panics
store/migration/manager.go
Outdated
defer batch.Close() | ||
|
||
if err := batch.Set(csKey, csBytes); err != nil { | ||
return fmt.Errorf("failed to write changeset to db.Batch: %w", err) | ||
} | ||
if err := batch.Write(); err != nil { | ||
return fmt.Errorf("failed to write changeset to db: %w", err) | ||
} | ||
if err := batch.Close(); err != nil { | ||
return fmt.Errorf("failed to close batch: %w", err) | ||
} |
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.
The problem with the current change is that if batch.Set or batch.Write fail, then batch.Close() will now not be invoked. I do understand the importance of removing defers in the loop to avoid lingering resources that won't be cleaned up until a panic or a return, but the better fix for this would be making an anonymous closure so
// Invoking this code in a closure so that defer is called immediately on return
// yet not in the for-loop which can leave resource lingering.
err := func() error {
defer batch.Close()
if err := batch.Set(csKey, csBytes); err != nil {
return fmt.Errorf("failed to write changeset to db.Batch: %w", err)
}
if err := batch.Write(); err != nil {
return fmt.Errorf("failed to write changeset to db: %w", err)
}
}()
if err != nil {
return err
}
@@ -76,7 +76,6 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, storeService storetypes.KV | |||
msg += fmt.Sprintf("error while returning group member iterator for group with ID %d\n%v\n", groupInfo.Id, err) | |||
return msg, broken | |||
} | |||
defer memIt.Close() |
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.
Your change to move it down below creates an even less likely chance that memIt.Close() due to the large number of branches that could return before it is invoked. You could apply that anonymous closure trick that I showed up above.
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.
Much appreciated @odeke-em for your insightful review. I have refactored the code, could you kindly take a look. Thank you!
f370eaa
to
b6c8dbe
Compare
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.
Almost there, thank you @tropicaldog! Just ensure that you whenever you make a closure; that you hoist all the code within the control flow so as to keep it logically the same.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
c8b2d4a
to
8701127
Compare
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.
Actionable comments posted: 0
Review Details
Configuration used: .coderabbit.yml
Review profile: CHILL
Files selected for processing (2)
- store/snapshots/store.go (2 hunks)
- store/v2/commitment/store.go (1 hunks)
Additional Context Used
Path-based Instructions (2)
store/snapshots/store.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.store/v2/commitment/store.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Additional comments not posted (3)
store/snapshots/store.go (2)
143-143
: Ensure proper error handling and resource management in the goroutine.
154-163
: Refactoring to removedefer
inside the loop is correctly implemented.Verification successful
Refactoring to remove
defer
inside the loop in theLoad
function appears to be correctly integrated and functioning as expected based on the test cases provided instore/snapshots/store_test.go
. The error handling is consistently checked, ensuring that no errors occur during the operations, which aligns with the intended behavior post-refactoring.
store/snapshots/store_test.go
: Various test cases check for errors after callingLoad
, confirming that the function handles errors as expected.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the integration of the `Load` function with other parts of the system. # Test: Search for usages of the `Load` function. Expect: Correct handling of the returned error and channel. rg --type go $'Load\('Length of output: 3061
Script:
#!/bin/bash # Description: Verify the error handling and resource management in the refactored `Load` function. # Test: Search for error handling patterns in the files where `Load` is used, focusing on the `store/snapshots/store.go` and related test files. rg --type go -C 5 'if err := store.Load' store/snapshots/store.go store/snapshots/store_test.goLength of output: 97
Script:
#!/bin/bash # Description: Broaden the search for error handling and resource management patterns around the `Load` function. # Test: Search for general patterns of error handling and resource management in the files where `Load` is used, focusing on the `store/snapshots/store.go` and related test files. rg --type go -C 5 'err.*store.Load' store/snapshots/store.go store/snapshots/store_test.goLength of output: 3089
store/v2/commitment/store.go (1)
402-404
: Ensure proper resource management by directly handling theClose
operation.Verification successful
The review of the direct handling of the
Close()
operation in thestore/v2/commitment/store.go
file has been verified against the broader codebase. The findings confirm that both direct and deferredClose()
operations are used throughout the codebase, depending on the context and specific requirements for resource management. The direct handling in the provided snippet is consistent with a deliberate approach to ensure timely resource release, which is crucial in scenarios where resource locks or file handles need to be explicitly controlled.
- The direct
Close()
instore/v2/commitment/store.go
is appropriate for the context and aligns with practices observed in other critical parts of the codebase.Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify proper resource management by directly handling the `Close` operation. # Test: Search for direct `Close` calls in the codebase. Expect: Proper resource management. rg --type go $'Close\('Length of output: 41062
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.
Actionable comments posted: 0
Review Details
Configuration used: .coderabbit.yml
Review profile: CHILL
Files selected for processing (1)
- store/snapshots/store.go (3 hunks)
Files skipped from review as they are similar to previous changes (1)
- store/snapshots/store.go
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.
Actionable comments posted: 1
Review Details
Configuration used: .coderabbit.yml
Review profile: CHILL
Files selected for processing (1)
- x/group/keeper/msg_server.go (1 hunks)
Additional Context Used
Path-based Instructions (1)
x/group/keeper/msg_server.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
x/group/keeper/msg_server.go
Outdated
err = k.GasService.GasMeter(ctx).Consume(gasCostPerIteration, "vote on proposal") | ||
if err != nil { | ||
return &group.MsgSubmitProposalResponse{ProposalId: id}, errorsmod.Wrap(err, "the proposal was created but failed on gas consumption for vote") | ||
} |
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.
Consider optimizing gas consumption handling.
The current implementation consumes gas for each vote within the loop. This could lead to high gas costs if there are many proposers. Consider batching these operations or implementing a more efficient gas management strategy to optimize resource usage.
Head branch was pushed to by a user without write access
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.
Actionable comments posted: 0
Review Details
Configuration used: .coderabbit.yml
Review profile: CHILL
Files selected for processing (2)
- store/v2/commitment/store.go (1 hunks)
- store/v2/migration/manager.go (1 hunks)
Additional Context Used
Path-based Instructions (2)
store/v2/migration/manager.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.store/v2/commitment/store.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Additional comments not posted (2)
store/v2/migration/manager.go (1)
184-198
: RefactoredwriteChangeset
to use a closure fordefer
ensures immediate resource release, aligning with best practices.store/v2/commitment/store.go (1)
414-416
: Properly handling the error onimporter.Close()
enhances robustness in resource management.
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.
Actionable comments posted: 0
Review Details
Configuration used: .coderabbit.yml
Review profile: CHILL
Files selected for processing (1)
- x/group/keeper/invariants.go (2 hunks)
Files skipped from review due to trivial changes (1)
- x/group/keeper/invariants.go
@tac0turtle Hi could you re-review, I've fixed the conflicts with main. |
* main: (120 commits) chore: update protoc-gen-swagger to protoc-gen-openapiv2 (#20448) ci: Add GitHub Action for go mod tidy and mocks (#20501) chore: Address linter issues (#20486) fix: wrap errors in auto CLI service registration (#20493) chore: fix comment (#20498) chore: fix the note box syntax error (#20499) feat(server/v2): introduce cometbft v2 (#20483) refactor(x/upgrade): migrate to appmodule.VersionMap (#20485) docs: code guidelines changes (#20482) feat(cosmovisor): load cosmovisor configuration from toml file (#19995) perf(math): Significantly speedup Dec quo truncate and quo Roundup (#20034) fix: Bump CometBFT versions (#20481) refactor(core): remove redundant ExecMode (#20322) feat(store/v2): pruning manager (#20430) chore: force reload sonar cloud (#20480) refactor(x/accounts): reuse calculated sum in `func safeAdd` (#20458) refactor: remove `defer` in loop (#20223) ci: remove livness test (#20474) build(deps): Bump bufbuild/buf-setup-action from 1.32.1 to 1.32.2 (#20477) chore: migrate a few diagrams to mermaid (#20473) ...
Description
Remove all occurrences of
defer
in loophttps://stackoverflow.com/questions/45617758/proper-way-to-release-resources-with-defer-in-a-loop
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...
!
in 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...
Summary by CodeRabbit
Load
method of theStore
struct.SubmitProposal
function of theKeeper
struct inmsg_server.go
.importer.Close()
method call instore/v2/commitment/store.go
.writeChangeset
method instore/v2/migration/manager.go
to ensure immediate defer execution on return for proper resource handling.