-
-
Notifications
You must be signed in to change notification settings - Fork 5.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 globallock #31933
Merged
Merged
Refactor globallock #31933
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
wolfogre
commented
Aug 28, 2024
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.
Maybe we can add a new method in the future, like
LockAndWatch(ctx context.Context, key string) (context.Context, ReleaseFunc, error)
For some operations which are revertable and care about lock losing, if they really exist.
lunny
approved these changes
Aug 28, 2024
lafriks
approved these changes
Aug 28, 2024
zjjhot
added a commit
to zjjhot/gitea
that referenced
this pull request
Aug 30, 2024
* giteaofficial/main: [skip ci] Updated translations via Crowdin Update JS and PY dependencies (go-gitea#31940) Fix search team (go-gitea#31923) Upgrade micromatch to 4.0.8 (go-gitea#31939) Refactor globallock (go-gitea#31933)
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
lgtm/done
This PR has enough approvals to get merged. There are no important open reservations anymore.
modifies/go
Pull requests that update Go code
size/L
Denotes a PR that changes 100-499 lines, ignoring generated files.
type/enhancement
An improvement of existing functionality
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Follow #31908. The main refactor is that it has removed the returned context of
Lock
.The returned context of
Lock
in old code is to provide a way to let callers know that they have lost the lock. But in most cases, callers shouldn't cancel what they are doing even it has lost the lock. And the design would confuse developers and make them use it incorrectly.See the discussion history: #31813 (comment) and #31813 (comment)
It's a breaking change, but since the new module hasn't been used yet, I think it's OK to not add the
pr/breaking
label.Design principles
It's almost copied from #31908, but with some changes.
Use spinlock even in memory implementation (unchanged)
In actual use cases, users may cancel requests.
sync.Mutex
will block the goroutine until the lock is acquired even if the request is canceled. And the spinlock is more suitable for this scenario since it's possible to give up the lock acquisition.Although the spinlock consumes more CPU resources, I think it's acceptable in most cases.
Do not expose the mutex to callers (unchanged)
If we expose the mutex to callers, it's possible for callers to reuse the mutex, which causes more complexity.
For example:
That's why #31813 (comment)
In this PR, we only expose
ReleaseFunc
to callers. So callers just need to callReleaseFunc
to release the lock, and do not need to care about the lock's lifecycle.In this way, it's also much easier for redis implementation to extend the mutex automatically, so that callers do not need to care about the lock's lifecycle. See also #31813 (comment)
Use "release" instead of "unlock" (unchanged)
For "unlock", it has the meaning of "unlock an acquired lock". So it's not acceptable to call "unlock" when failed to acquire the lock, or call "unlock" multiple times. It causes more complexity for callers to decide whether to call "unlock" or not.
So we use "release" instead of "unlock" to make it clear. Whether the lock is acquired or not, callers can always call "release", and it's also safe to call "release" multiple times.
But the code DO NOT expect callers to not call "release" after acquiring the lock. If callers forget to call "release", it will cause resource leak. That's why it's always safe to call "release" without extra checks: to avoid callers to forget to call it.
Acquired locks could be lost, but the callers shouldn't stop
Unlike
sync.Mutex
which will be locked forever once acquired until callingUnlock
, for distributed lock, the acquired lock could be lost.For example, the caller has acquired the lock, and it holds the lock for a long time since auto-extending is working for redis. However, it lost the connection to the redis server, and it's impossible to extend the lock anymore.
In #31908, it will cancel the context to make the operation stop, but it's not safe. Many operations are not revert-able. If they have been interrupted, then the instance goes corrupted. So
Lock
won't returnctx
anymore in this PR.Multiple ways to use the lock