-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
restore shared lock ttl to previous value when releasing #37469
Conversation
I am not sure I understand the problem description. |
c8f2738
to
dffaa3c
Compare
Yes
on upload it first 1) acquires a shared lock, 2) changes it to an exclusive one, 3) changes it back to a shared one So if a client repeatedly attempts to upload a file that has a leaked shared lock, it will never succeed to change it's shared lock into an exclusive one, but the TTL will never expire. |
dffaa3c
to
f363fbb
Compare
@@ -88,6 +118,12 @@ public function releaseLock(string $path, int $type): void { | |||
$newValue = $this->memcache->dec($path); | |||
} | |||
|
|||
if ($newValue > 0) { | |||
$this->restoreTTL($path); |
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.
Why is the restoreTTL from changeLock not enough, given the scenario you described?
What is the rationale behind this one in releaseLock? For other kind of exceptions/failures?
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.
We still want to restore the ttl when a request just acquires + releases.
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.
Logically it looks okay and I can follow your outlines, but I really cannot pretend to be very knowledgeable here. But contributed some bikeshedding ;)
f363fbb
to
1a6be1d
Compare
1a6be1d
to
07282d1
Compare
rebased, changed |
Signed-off-by: Robin Appelman <robin@icewind.nl>
Signed-off-by: Robin Appelman <robin@icewind.nl>
bba6fd7
to
ff62154
Compare
/backport to stable28 |
/backport to stable27 |
The backport to stable27 failed. Please do this backport manually. # Switch to the target branch and update it
git checkout stable27
git pull origin stable27
# Create the new backport branch
git checkout -b fix/foo-stable27
# Cherry pick the change from the commit sha1 of the change against the default branch
# This might cause conflicts. Resolve them.
git cherry-pick abc123
# Push the cherry pick commit to the remote repository and open a pull request
git push origin fix/foo-stable27 Error: Unknown error More info at https://docs.nextcloud.com/server/latest/developer_manual/getting_started/development_process.html#manual-backport |
With shared locks, each time the lock is acquired, the ttl for the path is reset.
Due to this "ttl extension" when a shared lock isn't freed correctly for any reason
the lock won't expire until no shared locks are required for the path for 1h.
This can lead to a client repeatedly trying to upload a file, and failing forever
because the lock never gets the opportunity to expire.
To help the lock expire in this case, we lower the TTL back to what it was before we
took the shared lock only if nobody else got a shared lock after we did.
This doesn't handle all cases where multiple requests are acquiring shared locks
but it should handle some of the more common ones and not hurt things further.
Ideally each copy of a shared lock will have it's own independent TTL so locks can expire while others are still being help, but we don't have that luxury.
To test:
test.txt
$path
and$this->memcache->prefix
used for the lock fortest.txt
(check$readablePath
to ensure you're look at the right lock)test.txt
set "<$this->memcache->prefix><$path>" 1
(key should be something likebc2af67f80d0445df3c328c2a0f08faf/lockfiles/0ca47d1e59d0cbf07f715297a70f8417
expire "<$this->memcache->prefix><$path>" 3600
expire "<$this->memcache->prefix><$path>"
in redis-cli to check that the TTL is counting downtest.txt
again, this should fail due to the leaked lock