Browse Source

re-acquired expired shared locks on large file uploads

during large file uploads, the shared lock that we get at the begining can expire
leading to locked errors later on, instead of erroring, try to re-get the lock

Signed-off-by: Robin Appelman <robin@icewind.nl>
tags/v18.0.0beta1
Robin Appelman 4 years ago
parent
commit
2e97e8bf84
No account linked to committer's email address

+ 15
- 3
apps/dav/lib/Connector/Sabre/File.php View File

@@ -252,10 +252,22 @@ class File extends Node implements IFile {
try {
$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
} catch (LockedException $e) {
if ($needsPartFile) {
$partStorage->unlink($internalPartPath);
// during very large uploads, the shared lock we got at the start might have been expired
// meaning that the above lock can fail not just only because somebody else got a shared lock
// or because there is no existing shared lock to make exclusive
//
// Thus we try to get a new exclusive lock, if the original lock failed because of a different shared
// lock this will still fail, if our original shared lock expired the new lock will be successful and
// the entire operation will be safe

try {
$this->acquireLock(ILockingProvider::LOCK_EXCLUSIVE);
} catch (LockedException $e) {
if ($needsPartFile) {
$partStorage->unlink($internalPartPath);
}
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}

// rename to correct path

+ 21
- 0
apps/dav/tests/unit/Connector/Sabre/FileTest.php View File

@@ -1201,4 +1201,25 @@ class FileTest extends TestCase {

$this->assertEquals('new content', $view->file_get_contents('root/file.txt'));
}

public function testPutLockExpired() {
$view = new \OC\Files\View('/' . $this->user . '/files/');

$path = 'test-locking.txt';
$info = new \OC\Files\FileInfo(
'/' . $this->user . '/files/' . $path,
$this->getMockStorage(),
null,
['permissions' => \OCP\Constants::PERMISSION_ALL],
null
);

$file = new \OCA\DAV\Connector\Sabre\File($view, $info);

// don't lock before the PUT to simulate an expired shared lock
$this->assertNotEmpty($file->put($this->getStream('test data')));

// afterMethod unlocks
$view->unlockFile($path, ILockingProvider::LOCK_SHARED);
}
}

Loading…
Cancel
Save