Version1025Date20240308063933.php 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\DAV\Migration;
  8. use Closure;
  9. use OCP\AppFramework\Services\IAppConfig;
  10. use OCP\DB\ISchemaWrapper;
  11. use OCP\DB\QueryBuilder\IQueryBuilder;
  12. use OCP\DB\Types;
  13. use OCP\IDBConnection;
  14. use OCP\Migration\IOutput;
  15. use OCP\Migration\SimpleMigrationStep;
  16. class Version1025Date20240308063933 extends SimpleMigrationStep {
  17. private IAppConfig $appConfig;
  18. private IDBConnection $db;
  19. public function __construct(IAppConfig $appConfig,
  20. IDBConnection $db) {
  21. $this->db = $db;
  22. $this->appConfig = $appConfig;
  23. }
  24. /**
  25. * @param IOutput $output
  26. * @param Closure(): ISchemaWrapper $schemaClosure
  27. * @param array $options
  28. * @return null|ISchemaWrapper
  29. */
  30. public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
  31. /** @var ISchemaWrapper $schema */
  32. $schema = $schemaClosure();
  33. foreach (['addressbookchanges', 'calendarchanges'] as $tableName) {
  34. $table = $schema->getTable($tableName);
  35. if (!$table->hasColumn('created_at')) {
  36. $table->addColumn('created_at', Types::INTEGER, [
  37. 'notnull' => true,
  38. 'length' => 4,
  39. 'default' => 0,
  40. ]);
  41. }
  42. }
  43. return $schema;
  44. }
  45. public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options): void {
  46. // The threshold is higher than the default of \OCA\DAV\BackgroundJob\PruneOutdatedSyncTokensJob
  47. // but small enough to fit into a cluster transaction size.
  48. // For a 50k users instance that would still keep 10 changes on average.
  49. $limit = max(1, (int) $this->appConfig->getAppValue('totalNumberOfSyncTokensToKeep', '500000'));
  50. foreach (['addressbookchanges', 'calendarchanges'] as $tableName) {
  51. $thresholdSelect = $this->db->getQueryBuilder();
  52. $thresholdSelect->select('id')
  53. ->from($tableName)
  54. ->orderBy('id', 'desc')
  55. ->setFirstResult($limit)
  56. ->setMaxResults(1);
  57. $oldestIdResult = $thresholdSelect->executeQuery();
  58. $oldestId = $oldestIdResult->fetchColumn();
  59. $oldestIdResult->closeCursor();
  60. $qb = $this->db->getQueryBuilder();
  61. $update = $qb->update($tableName)
  62. ->set('created_at', $qb->createNamedParameter(time(), IQueryBuilder::PARAM_INT))
  63. ->where(
  64. $qb->expr()->eq('created_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)),
  65. );
  66. // If there is a lot of data we only set timestamp for the most recent rows
  67. // because the rest will be deleted by \OCA\DAV\BackgroundJob\PruneOutdatedSyncTokensJob
  68. // anyway.
  69. if ($oldestId !== false) {
  70. $update->andWhere($qb->expr()->gt('id', $qb->createNamedParameter($oldestId, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT));
  71. }
  72. $updated = $update->executeStatement();
  73. $output->debug('Added a default creation timestamp to ' . $updated . ' rows in ' . $tableName);
  74. }
  75. }
  76. }