|
24 | 24 |
|
25 | 25 | namespace OC\Files\Cache; |
26 | 26 |
|
| 27 | +use Doctrine\DBAL\Exception\RetryableException; |
27 | 28 | use OC\Files\Storage\Wrapper\Encryption; |
28 | 29 | use OCP\DB\QueryBuilder\IQueryBuilder; |
29 | 30 | use OCP\Files\Cache\IPropagator; |
|
34 | 35 | * Propagate etags and mtimes within the storage |
35 | 36 | */ |
36 | 37 | class Propagator implements IPropagator { |
| 38 | + public const MAX_RETRIES = 3; |
37 | 39 | private $inBatch = false; |
38 | 40 |
|
39 | 41 | private $batch = []; |
@@ -100,35 +102,41 @@ public function propagateChange($internalPath, $time, $sizeDifference = 0) { |
100 | 102 | $builder->set('etag', $builder->createNamedParameter($etag, IQueryBuilder::PARAM_STR)); |
101 | 103 | } |
102 | 104 |
|
103 | | - $builder->execute(); |
104 | | - |
105 | 105 | if ($sizeDifference !== 0) { |
106 | | - // we need to do size separably so we can ignore entries with uncalculated size |
107 | | - $builder = $this->connection->getQueryBuilder(); |
108 | | - $builder->update('filecache') |
109 | | - ->set('size', $builder->func()->greatest( |
110 | | - $builder->func()->add('size', $builder->createNamedParameter($sizeDifference)), |
111 | | - $builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT) |
112 | | - )) |
113 | | - ->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))) |
114 | | - ->andWhere($builder->expr()->in('path_hash', $hashParams)) |
115 | | - ->andWhere($builder->expr()->gt('size', $builder->expr()->literal(-1, IQueryBuilder::PARAM_INT))); |
| 106 | + $hasCalculatedSize = $builder->expr()->gt('size', $builder->expr()->literal(-1, IQUeryBuilder::PARAM_INT)); |
| 107 | + $sizeColumn = $builder->getColumnName('size'); |
| 108 | + $newSize = $builder->func()->greatest( |
| 109 | + $builder->func()->add('size', $builder->createNamedParameter($sizeDifference)), |
| 110 | + $builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT) |
| 111 | + ); |
| 112 | + |
| 113 | + // Only update if row had a previously calculated size |
| 114 | + $builder->set('size', $builder->createFunction("CASE WHEN $hasCalculatedSize THEN $newSize ELSE $sizeColumn END")); |
116 | 115 |
|
117 | 116 | if ($this->storage->instanceOfStorage(Encryption::class)) { |
118 | 117 | // in case of encryption being enabled after some files are already uploaded, some entries will have an unencrypted_size of 0 and a non-zero size |
119 | | - $eq = $builder->expr()->eq('unencrypted_size', $builder->expr()->literal(0, IQueryBuilder::PARAM_INT)); |
| 118 | + $hasUnencryptedSize = $builder->expr()->neq('unencrypted_size', $builder->expr()->literal(0, IQueryBuilder::PARAM_INT)); |
120 | 119 | $sizeColumn = $builder->getColumnName('size'); |
121 | 120 | $unencryptedSizeColumn = $builder->getColumnName('unencrypted_size'); |
122 | | - $builder->set('unencrypted_size', $builder->func()->greatest( |
| 121 | + $newUnencryptedSize = $builder->func()->greatest( |
123 | 122 | $builder->func()->add( |
124 | | - $builder->createFunction("CASE WHEN $eq THEN $unencryptedSizeColumn ELSE $sizeColumn END"), |
| 123 | + $builder->createFunction("CASE WHEN $hasUnencryptedSize THEN $sizeColumn ELSE $unencryptedSizeColumn END"), |
125 | 124 | $builder->createNamedParameter($sizeDifference) |
126 | 125 | ), |
127 | 126 | $builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT) |
128 | | - )); |
| 127 | + ); |
| 128 | + |
| 129 | + // Only update if row had a previously calculated size |
| 130 | + $builder->set('unencrypted_size', $builder->createFunction("CASE WHEN $hasCalculatedSize THEN $newUnencryptedSize ELSE $unencryptedSizeColumn END")); |
129 | 131 | } |
| 132 | + } |
130 | 133 |
|
131 | | - $builder->execute(); |
| 134 | + for ($i = 0; $i < self::MAX_RETRIES; $i++) { |
| 135 | + try { |
| 136 | + $builder->executeStatement(); |
| 137 | + break; |
| 138 | + } catch (RetryableException $e) { |
| 139 | + } |
132 | 140 | } |
133 | 141 | } |
134 | 142 |
|
|
0 commit comments