-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Go binding: do not automatically close database objects #11394
base: main
Are you sure you want to change the base?
Conversation
Cc @johscheuer Alternative approach would be: to use an In the Go binding there's only 3 objects which have a finalizer:
And currently only database has an user-reachable |
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 have to take some time to go over the changes.
In general I would prefer if all structs like Database
, Future
and Transaction
would implement a Close()
method. That would give a user more control over the life cycle of the structs and would fit well into the go model where you just define a defer
method to clean up the resources.
Understood, thanks for the info; I would prefer as well that you take all the time needed as rush can only favor the introduction of bugs.
I think that's precisely the more idiomatic Go way e.g. instead of setting finalizers letting user call Given that constraint I can see only two possible approaches:
Let me know if you prefer to retool for (2), after you have time to look into the changes. |
2131f59
to
9fd1f5a
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.
Given that constraint I can see only two possible approaches:
removing the finalizer (as done in this PR)
using a mutex or atomic.Value to make sure that multiple calls are safe
Let me know if you prefer to retool for (2), after you have time to look into the changes.
Removing the finalizer is from my point of view the best option. I wouldn't try to make it more complex than needed. Most (if not all) of the standard go library that implement Close()
are not safe to call concurrency either: https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/os/file_posix.go;l=15-24.
// You have to ensure that you're not resuing this database. | ||
// It must be called exactly once for each created database. | ||
// You have to ensure that you're not reusing this database | ||
// after it has been closed. |
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.
Should we return an error in the close method if the DB is already closed?
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.
In that case the Close()
function should set d.ptr
to nil
, which it currently doesn't, and calling Close()
on an improperly-constructed Database
would have an undetermined effect (most likely SIGSEGV) instead of current behavior (no-op).
I can make the change and add some test coverage, however that likely means that in future when adding Close()
for futures and transactions they'd also need to have this return value for consistency, and that might clutter a bit the calling code.
Since having this error on Close()
still does not do anything regarding concurrency-safety (caller must make sure of that), we could leave it without error
; let me know what you prefer.
The error return value can always be added later in its own PR.
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.
@jzhou77 this PR would add a breaking change in the go bindings, is there a good place to announce this somewhere e.g. in the release notes: https://github.com/apple/foundationdb/tree/main/documentation/sphinx/source/release-notes?
Result of foundationdb-pr-clang-ide on Linux CentOS 7
|
Result of foundationdb-pr-clang on Linux CentOS 7
|
Result of foundationdb-pr-macos-m1 on macOS Ventura 13.x
|
Result of foundationdb-pr-macos on macOS Ventura 13.x
|
Result of foundationdb-pr on Linux CentOS 7
|
Result of foundationdb-pr-cluster-tests on Linux CentOS 7
|
Setting the finalizer prevents user from calling Close(), as it would randomly result in SIGSEGV or some other silent memory corruption. No finalizer is set for the database and user is expected to call Close() to avoid memory leaks.
9fd1f5a
to
399c62a
Compare
Result of foundationdb-pr-clang-ide on Linux CentOS 7
|
Result of foundationdb-pr-macos-m1 on macOS Ventura 13.x
|
Result of foundationdb-pr-macos on macOS Ventura 13.x
|
Result of foundationdb-pr-clang on Linux CentOS 7
|
Result of foundationdb-pr-cluster-tests on Linux CentOS 7
|
Result of foundationdb-pr on Linux CentOS 7
|
Setting the finalizer prevents user from calling Close(), as it would randomly result in
SIGSEGV
or some other silent memory corruption.See #11383 (comment) for an example.
The change consists in setting no finalizer for the database and then expecting user to call
Close()
to avoid memory leaks.NOTE: this must be considered a breaking change, since clients who do not update their usage of the binding will automatically upgrade to a memory leak if they open many databases without closing any.
Code-Reviewer Section
The general pull request guidelines can be found here.
Please check each of the following things and check all boxes before accepting a PR.
For Release-Branches
If this PR is made against a release-branch, please also check the following:
release-branch
ormain
if this is the youngest branch)