|
11 | 11 |
|
12 | 12 | use OC\DB\Exceptions\DbalException; |
13 | 13 | use OC\Files\Storage\Wrapper\Encryption; |
| 14 | +use OCP\DB\QueryBuilder\ILiteral; |
14 | 15 | use OCP\DB\QueryBuilder\IQueryBuilder; |
15 | 16 | use OCP\Files\Cache\IPropagator; |
16 | 17 | use OCP\Files\Storage\IReliableEtagStorage; |
@@ -63,9 +64,7 @@ public function propagateChange($internalPath, $time, $sizeDifference = 0): void |
63 | 64 | $etag = uniqid(); // since we give all folders the same etag we don't ask the storage for the etag |
64 | 65 |
|
65 | 66 | $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); |
69 | 68 |
|
70 | 69 | $builder->update('filecache') |
71 | 70 | ->set('mtime', $builder->func()->greatest('mtime', $builder->createNamedParameter($time, IQueryBuilder::PARAM_INT))) |
@@ -106,9 +105,27 @@ public function propagateChange($internalPath, $time, $sizeDifference = 0): void |
106 | 105 |
|
107 | 106 | for ($i = 0; $i < self::MAX_RETRIES; $i++) { |
108 | 107 | 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 | + } |
110 | 124 | break; |
111 | 125 | } catch (DbalException $e) { |
| 126 | + if ($this->connection->getDatabaseProvider() !== IDBConnection::PLATFORM_SQLITE) { |
| 127 | + $this->connection->rollBack(); |
| 128 | + } |
112 | 129 | if (!$e->isRetryable()) { |
113 | 130 | throw $e; |
114 | 131 | } |
|
0 commit comments