|
25 | 25 | use OCP\AppFramework\Db\DoesNotExistException; |
26 | 26 | use OCP\Command\IBus; |
27 | 27 | use OCP\EventDispatcher\IEventDispatcher; |
| 28 | +use OCP\Files\Cache\IPropagator; |
28 | 29 | use OCP\Files\FileInfo; |
29 | 30 | use OCP\Files\Folder; |
30 | 31 | use OCP\Files\IMimeTypeDetector; |
@@ -234,6 +235,14 @@ public static function markDeletedFile($path) { |
234 | 235 | 'filename' => $filename]; |
235 | 236 | } |
236 | 237 |
|
| 238 | + private static function getUserStoragePropagator(string $uid): ?IPropagator { |
| 239 | + try { |
| 240 | + return Server::get(IRootFolder::class)->getUserFolder($uid)->getStorage()->getPropagator(); |
| 241 | + } catch (\Exception) { |
| 242 | + return null; |
| 243 | + } |
| 244 | + } |
| 245 | + |
237 | 246 | /** |
238 | 247 | * delete the version from the storage and cache |
239 | 248 | * |
@@ -264,10 +273,16 @@ public static function delete($path) { |
264 | 273 |
|
265 | 274 | $versions = self::getVersions($uid, $filename); |
266 | 275 | if (!empty($versions)) { |
267 | | - foreach ($versions as $v) { |
268 | | - \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $path . $v['version'], 'trigger' => self::DELETE_TRIGGER_MASTER_REMOVED]); |
269 | | - self::deleteVersion($view, $filename . '.v' . $v['version']); |
270 | | - \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $path . $v['version'], 'trigger' => self::DELETE_TRIGGER_MASTER_REMOVED]); |
| 276 | + $propagator = self::getUserStoragePropagator($uid); |
| 277 | + $propagator?->beginBatch(); |
| 278 | + try { |
| 279 | + foreach ($versions as $v) { |
| 280 | + \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $path . $v['version'], 'trigger' => self::DELETE_TRIGGER_MASTER_REMOVED]); |
| 281 | + self::deleteVersion($view, $filename . '.v' . $v['version']); |
| 282 | + \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $path . $v['version'], 'trigger' => self::DELETE_TRIGGER_MASTER_REMOVED]); |
| 283 | + } |
| 284 | + } finally { |
| 285 | + $propagator?->commitBatch(); |
271 | 286 | } |
272 | 287 | } |
273 | 288 | } |
@@ -619,21 +634,27 @@ public static function expireOlderThanMaxForUser($uid) { |
619 | 634 | return $version < $threshold; |
620 | 635 | }); |
621 | 636 |
|
622 | | - foreach ($versions as $version) { |
623 | | - $internalPath = $version->getInternalPath(); |
624 | | - \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $internalPath, 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]); |
| 637 | + $propagator = self::getUserStoragePropagator($uid); |
| 638 | + $propagator?->beginBatch(); |
| 639 | + try { |
| 640 | + foreach ($versions as $version) { |
| 641 | + $internalPath = $version->getInternalPath(); |
| 642 | + \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $internalPath, 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]); |
625 | 643 |
|
626 | | - $versionEntity = isset($versionEntities[$version->getId()]) ? $versionEntities[$version->getId()] : null; |
627 | | - if (!is_null($versionEntity)) { |
628 | | - $versionsMapper->delete($versionEntity); |
629 | | - } |
| 644 | + $versionEntity = isset($versionEntities[$version->getId()]) ? $versionEntities[$version->getId()] : null; |
| 645 | + if (!is_null($versionEntity)) { |
| 646 | + $versionsMapper->delete($versionEntity); |
| 647 | + } |
630 | 648 |
|
631 | | - try { |
632 | | - $version->delete(); |
633 | | - \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $internalPath, 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]); |
634 | | - } catch (NotPermittedException $e) { |
635 | | - Server::get(LoggerInterface::class)->error("Missing permissions to delete version for user {$uid}: {$internalPath}", ['app' => 'files_versions', 'exception' => $e]); |
| 649 | + try { |
| 650 | + $version->delete(); |
| 651 | + \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $internalPath, 'trigger' => self::DELETE_TRIGGER_RETENTION_CONSTRAINT]); |
| 652 | + } catch (NotPermittedException $e) { |
| 653 | + Server::get(LoggerInterface::class)->error("Missing permissions to delete version for user {$uid}: {$internalPath}", ['app' => 'files_versions', 'exception' => $e]); |
| 654 | + } |
636 | 655 | } |
| 656 | + } finally { |
| 657 | + $propagator?->commitBatch(); |
637 | 658 | } |
638 | 659 | } |
639 | 660 |
|
@@ -935,47 +956,53 @@ public static function expire($filename, $uid) { |
935 | 956 | $versionsSize = $versionsSize - $sizeOfDeletedVersions; |
936 | 957 | } |
937 | 958 |
|
938 | | - foreach ($toDelete as $key => $path) { |
939 | | - // Make sure to cleanup version table relations as expire does not pass deleteVersion |
940 | | - try { |
941 | | - /** @var VersionsMapper $versionsMapper */ |
942 | | - $versionsMapper = Server::get(VersionsMapper::class); |
943 | | - $file = Server::get(IRootFolder::class)->getUserFolder($uid)->get($filename); |
944 | | - $pathparts = pathinfo($path); |
945 | | - $timestamp = (int)substr($pathparts['extension'] ?? '', 1); |
946 | | - $versionEntity = $versionsMapper->findVersionForFileId($file->getId(), $timestamp); |
947 | | - if ($versionEntity->getMetadataValue('label') !== null && $versionEntity->getMetadataValue('label') !== '') { |
948 | | - continue; |
| 959 | + $propagator = self::getUserStoragePropagator($uid); |
| 960 | + $propagator?->beginBatch(); |
| 961 | + try { |
| 962 | + foreach ($toDelete as $key => $path) { |
| 963 | + // Make sure to cleanup version table relations as expire does not pass deleteVersion |
| 964 | + try { |
| 965 | + /** @var VersionsMapper $versionsMapper */ |
| 966 | + $versionsMapper = Server::get(VersionsMapper::class); |
| 967 | + $file = Server::get(IRootFolder::class)->getUserFolder($uid)->get($filename); |
| 968 | + $pathparts = pathinfo($path); |
| 969 | + $timestamp = (int)substr($pathparts['extension'] ?? '', 1); |
| 970 | + $versionEntity = $versionsMapper->findVersionForFileId($file->getId(), $timestamp); |
| 971 | + if ($versionEntity->getMetadataValue('label') !== null && $versionEntity->getMetadataValue('label') !== '') { |
| 972 | + continue; |
| 973 | + } |
| 974 | + $versionsMapper->delete($versionEntity); |
| 975 | + } catch (DoesNotExistException $e) { |
949 | 976 | } |
950 | | - $versionsMapper->delete($versionEntity); |
951 | | - } catch (DoesNotExistException $e) { |
952 | | - } |
953 | 977 |
|
954 | | - \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
955 | | - self::deleteVersion($versionsFileview, $path); |
956 | | - \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
957 | | - unset($allVersions[$key]); // update array with the versions we keep |
958 | | - $logger->info('Expire: ' . $path, ['app' => 'files_versions']); |
959 | | - } |
| 978 | + \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
| 979 | + self::deleteVersion($versionsFileview, $path); |
| 980 | + \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $path, 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
| 981 | + unset($allVersions[$key]); // update array with the versions we keep |
| 982 | + $logger->info('Expire: ' . $path, ['app' => 'files_versions']); |
| 983 | + } |
960 | 984 |
|
961 | | - // Check if enough space is available after versions are rearranged. |
962 | | - // If not we delete the oldest versions until we meet the size limit for versions, |
963 | | - // but always keep the two latest versions |
964 | | - $numOfVersions = count($allVersions) - 2 ; |
965 | | - $i = 0; |
966 | | - // sort oldest first and make sure that we start at the first element |
967 | | - ksort($allVersions); |
968 | | - reset($allVersions); |
969 | | - while ($availableSpace < 0 && $i < $numOfVersions) { |
970 | | - $version = current($allVersions); |
971 | | - \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $version['path'] . '.v' . $version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
972 | | - self::deleteVersion($versionsFileview, $version['path'] . '.v' . $version['version']); |
973 | | - \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $version['path'] . '.v' . $version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
974 | | - $logger->info('running out of space! Delete oldest version: ' . $version['path'] . '.v' . $version['version'], ['app' => 'files_versions']); |
975 | | - $versionsSize -= $version['size']; |
976 | | - $availableSpace += $version['size']; |
977 | | - next($allVersions); |
978 | | - $i++; |
| 985 | + // Check if enough space is available after versions are rearranged. |
| 986 | + // If not we delete the oldest versions until we meet the size limit for versions, |
| 987 | + // but always keep the two latest versions |
| 988 | + $numOfVersions = count($allVersions) - 2 ; |
| 989 | + $i = 0; |
| 990 | + // sort oldest first and make sure that we start at the first element |
| 991 | + ksort($allVersions); |
| 992 | + reset($allVersions); |
| 993 | + while ($availableSpace < 0 && $i < $numOfVersions) { |
| 994 | + $version = current($allVersions); |
| 995 | + \OC_Hook::emit('\OCP\Versions', 'preDelete', ['path' => $version['path'] . '.v' . $version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
| 996 | + self::deleteVersion($versionsFileview, $version['path'] . '.v' . $version['version']); |
| 997 | + \OC_Hook::emit('\OCP\Versions', 'delete', ['path' => $version['path'] . '.v' . $version['version'], 'trigger' => self::DELETE_TRIGGER_QUOTA_EXCEEDED]); |
| 998 | + $logger->info('running out of space! Delete oldest version: ' . $version['path'] . '.v' . $version['version'], ['app' => 'files_versions']); |
| 999 | + $versionsSize -= $version['size']; |
| 1000 | + $availableSpace += $version['size']; |
| 1001 | + next($allVersions); |
| 1002 | + $i++; |
| 1003 | + } |
| 1004 | + } finally { |
| 1005 | + $propagator?->commitBatch(); |
979 | 1006 | } |
980 | 1007 |
|
981 | 1008 | return $versionsSize; // finally return the new size of the version history |
|
0 commit comments