Skip to content

Commit decac2a

Browse files
committed
fix(propagator): Lock rows also in propagateChange
Signed-off-by: Carl Schwan <carlschwan@kde.org> (cherry picked from commit 3d031b0)
1 parent 7e8f88c commit decac2a

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

lib/private/Files/Cache/Propagator.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use OC\DB\Exceptions\DbalException;
1313
use OC\Files\Storage\Wrapper\Encryption;
14+
use OCP\DB\QueryBuilder\ILiteral;
1415
use OCP\DB\QueryBuilder\IQueryBuilder;
1516
use OCP\Files\Cache\IPropagator;
1617
use OCP\Files\Storage\IReliableEtagStorage;
@@ -63,9 +64,7 @@ public function propagateChange($internalPath, $time, $sizeDifference = 0): void
6364
$etag = uniqid(); // since we give all folders the same etag we don't ask the storage for the etag
6465

6566
$builder = $this->connection->getQueryBuilder();
66-
$hashParams = array_map(function ($hash) use ($builder) {
67-
return $builder->expr()->literal($hash);
68-
}, $parentHashes);
67+
$hashParams = array_map(static fn (string $hash): ILiteral => $builder->expr()->literal($hash), $parentHashes);
6968

7069
$builder->update('filecache')
7170
->set('mtime', $builder->func()->greatest('mtime', $builder->createNamedParameter($time, IQueryBuilder::PARAM_INT)))
@@ -106,9 +105,27 @@ public function propagateChange($internalPath, $time, $sizeDifference = 0): void
106105

107106
for ($i = 0; $i < self::MAX_RETRIES; $i++) {
108107
try {
109-
$builder->executeStatement();
108+
if ($this->connection->getDatabaseProvider() !== IDBConnection::PLATFORM_SQLITE) {
109+
$this->connection->beginTransaction();
110+
// Lock all the rows first with a SELECT FOR UPDATE ordered by path_hash
111+
$forUpdate = $this->connection->getQueryBuilder();
112+
$forUpdate->select('fileid')
113+
->from('filecache')
114+
->where($forUpdate->expr()->eq('storage', $forUpdate->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
115+
->andWhere($forUpdate->expr()->in('path_hash', $hashParams))
116+
->orderBy('path_hash')
117+
->forUpdate()
118+
->executeQuery();
119+
$builder->executeStatement();
120+
$this->connection->commit();
121+
} else {
122+
$builder->executeStatement();
123+
}
110124
break;
111125
} catch (DbalException $e) {
126+
if ($this->connection->getDatabaseProvider() !== IDBConnection::PLATFORM_SQLITE) {
127+
$this->connection->rollBack();
128+
}
112129
if (!$e->isRetryable()) {
113130
throw $e;
114131
}

0 commit comments

Comments
 (0)