MetadataMigrationJob.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2024 Louis Chemineau <louis@chmn.me>
  5. *
  6. * @author Louis Chemineau <louis@chmn.me>
  7. *
  8. * @license AGPL-3.0-or-later
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace OC\Core\BackgroundJobs;
  25. use OCP\AppFramework\Utility\ITimeFactory;
  26. use OCP\BackgroundJob\IJobList;
  27. use OCP\BackgroundJob\TimedJob;
  28. use OCP\DB\QueryBuilder\IQueryBuilder;
  29. use OCP\IConfig;
  30. use OCP\IDBConnection;
  31. // Migrate oc_file_metadata.metadata to oc_file_metadata.value.
  32. // This was previously done in a migration, but it is taking to much time in large instances.
  33. // This job will progressively migrate the data 1 hour per night every night.
  34. // Once done, it will remove itself from the job list.
  35. class MetadataMigrationJob extends TimedJob {
  36. public function __construct(
  37. ITimeFactory $time,
  38. private IDBConnection $db,
  39. private IJobList $jobList,
  40. private IConfig $config,
  41. ) {
  42. parent::__construct($time);
  43. $this->setTimeSensitivity(\OCP\BackgroundJob\IJob::TIME_INSENSITIVE);
  44. $this->setInterval(24 * 3600);
  45. }
  46. protected function run(mixed $argument): void {
  47. $prefix = $this->config->getSystemValueString('dbtableprefix', 'oc_');
  48. if (!$this->db->createSchema()->getTable($prefix.'file_metadata')->hasColumn('metadata')) {
  49. return;
  50. }
  51. $updateQuery = $this->db->getQueryBuilder();
  52. $updateQuery->update('file_metadata')
  53. ->set('value', $updateQuery->createParameter('value'))
  54. ->set('metadata', $updateQuery->createParameter('metadata'))
  55. ->where($updateQuery->expr()->eq('id', $updateQuery->createParameter('id')))
  56. ->andWhere($updateQuery->expr()->eq('group_name', $updateQuery->createParameter('group_name')));
  57. $selectQuery = $this->db->getQueryBuilder();
  58. $selectQuery->select('id', 'group_name', 'metadata')
  59. ->from('file_metadata')
  60. ->where($selectQuery->expr()->nonEmptyString('metadata'))
  61. ->setMaxResults(1000);
  62. $movedRows = 0;
  63. $startTime = time();
  64. do {
  65. // Stop if execution time is more than one hour.
  66. if (time() - $startTime > 3600) {
  67. return;
  68. }
  69. $movedRows = $this->chunkedCopying($updateQuery, $selectQuery);
  70. } while ($movedRows !== 0);
  71. $this->jobList->remove(MetadataMigrationJob::class);
  72. }
  73. protected function chunkedCopying(IQueryBuilder $updateQuery, IQueryBuilder $selectQuery): int {
  74. $this->db->beginTransaction();
  75. $results = $selectQuery->executeQuery();
  76. while ($row = $results->fetch()) {
  77. $updateQuery
  78. ->setParameter('id', (int)$row['id'])
  79. ->setParameter('group_name', $row['group_name'])
  80. ->setParameter('value', $row['metadata'])
  81. ->setParameter('metadata', '')
  82. ->executeStatement();
  83. }
  84. $results->closeCursor();
  85. $this->db->commit();
  86. return $results->rowCount();
  87. }
  88. }