diff --git a/lib/Migration/Version016002000Date20260218134723.php b/lib/Migration/Version016002000Date20260218134723.php index 563347a547..e85d4a32f3 100644 --- a/lib/Migration/Version016002000Date20260218134723.php +++ b/lib/Migration/Version016002000Date20260218134723.php @@ -38,17 +38,22 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array ->where($setQb->expr()->eq('id', $setQb->createParameter('id'))); $i = 1; $this->db->beginTransaction(); - while ($row = $result->fetch()) { - if ($i++ % 1000 === 0) { - $this->db->commit(); - $this->db->beginTransaction(); + try { + while ($row = $result->fetch()) { + if ($i++ % 1000 === 0) { + $this->db->commit(); + $this->db->beginTransaction(); + } + $setQb->setParameter('url_hash', hash('xxh128', $row['url'])); + $setQb->setParameter('id', $row['id']); + $setQb->executeStatement(); + $output->advance(); } - $setQb->setParameter('url_hash', hash('xxh128', $row['url'])); - $setQb->setParameter('id', $row['id']); - $setQb->executeStatement(); - $output->advance(); + $this->db->commit(); + } catch (\Throwable $e) { + $this->db->rollBack(); + throw $e; } - $this->db->commit(); $output->finishProgress(); $result->closeCursor(); } diff --git a/lib/Migration/Version016002000Date20260717124723.php b/lib/Migration/Version016002000Date20260717124723.php new file mode 100644 index 0000000000..440ef6c7eb --- /dev/null +++ b/lib/Migration/Version016002000Date20260717124723.php @@ -0,0 +1,119 @@ +hasTable('bookmarks')) { + $table = $schema->getTable('bookmarks'); + if (!$table->hasColumn('url_hash')) { + $output->info('Recovering missing url_hash column on the bookmarks table'); + $table->addColumn('url_hash', 'string', [ + 'notnull' => false, + 'length' => 32, + ]); + } + } + + return $schema; + } + + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + // Only do any work if there are bookmarks without a hash. On healthy + // instances this short-circuits before the (expensive) dedup scan. + $countQb = $this->db->getQueryBuilder(); + $countQb->select($countQb->func()->count('id')) + ->from('bookmarks') + ->where($countQb->expr()->isNull('url_hash')); + $result = $countQb->executeQuery(); + $count = (int)$result->fetchOne(); + $result->closeCursor(); + + if ($count === 0) { + return; + } + + // Merge per-user duplicate URLs before hashing, otherwise duplicates + // would produce colliding (user_id, url_hash) pairs and break the + // unique index added by the next migration. + $this->deduplicateAll($output); + + $output->info('Hashing URLs of n=' . $count . ' bookmarks'); + $output->startProgress($count); + + $qb = $this->db->getQueryBuilder(); + $qb->select('id', 'url') + ->from('bookmarks') + ->where($qb->expr()->isNull('url_hash')); + $result = $qb->executeQuery(); + + $setQb = $this->db->getQueryBuilder(); + $setQb->update('bookmarks') + ->set('url_hash', $setQb->createParameter('url_hash')) + ->where($setQb->expr()->eq('id', $setQb->createParameter('id'))); + + $i = 1; + $this->db->beginTransaction(); + try { + while ($row = $result->fetch()) { + if ($i++ % 1000 === 0) { + $this->db->commit(); + $this->db->beginTransaction(); + } + $setQb->setParameter('url_hash', hash('xxh128', $row['url'])); + $setQb->setParameter('id', $row['id']); + $setQb->executeStatement(); + $output->advance(); + } + $this->db->commit(); + } catch (\Throwable $e) { + $this->db->rollBack(); + throw $e; + } + $output->finishProgress(); + $result->closeCursor(); + } +} diff --git a/lib/Migration/Version016002000Date20260717134723.php b/lib/Migration/Version016002000Date20260717134723.php new file mode 100644 index 0000000000..27476a6164 --- /dev/null +++ b/lib/Migration/Version016002000Date20260717134723.php @@ -0,0 +1,50 @@ +hasTable('bookmarks')) { + $table = $schema->getTable('bookmarks'); + if ($table->hasColumn('url_hash') && !$table->hasIndex('bookmarks_uniq_url')) { + $output->info('Recovering missing bookmarks_uniq_url unique index'); + $table->addUniqueIndex(['user_id', 'url_hash'], 'bookmarks_uniq_url'); + } + } + + return $schema; + } +}