Skip to content

Commit 31b7af4

Browse files
authored
Merge pull request #2362 from nextcloud/fix/deduplicate-migration
fix(Migration): Merge per-user-database-duplicate bookmarks before hashing URLs
2 parents 8982bc0 + 51b478f commit 31b7af4

7 files changed

Lines changed: 376 additions & 52 deletions

File tree

.github/workflows/floccus.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ jobs:
130130
MYSQL_PASSWORD: ${{env.MYSQL_PASSWORD}}
131131
MYSQL_HOST: mysql
132132
NEXTCLOUD_TRUSTED_DOMAINS: nextcloud
133-
volumes:
134-
- /home/runner/actions-runner/_work/bookmarks/bookmarks/apps:/var/www/html/apps
135133
options: --name nextcloud
136134
mysql:
137135
image: mariadb:10.5 # see https://github.com/nextcloud/docker/issues/1536
@@ -170,7 +168,7 @@ jobs:
170168
- name: Enable bookmarks app
171169
shell: bash
172170
run: |
173-
sudo cp -R ${{env.APP_NAME}} apps/
171+
docker cp ${{env.APP_NAME}} nextcloud:/var/www/html/apps/
174172
NEXT_WAIT_TIME=0
175173
until [ $NEXT_WAIT_TIME -eq 25 ] || docker exec --user www-data nextcloud php occ app:enable ${{ env.APP_NAME }}; do
176174
sleep $(( NEXT_WAIT_TIME++ ))

appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Requirements:
2323
- mbstring: *
2424
- when using MySQL, use at least v8.0
2525
]]></description>
26-
<version>16.1.0</version>
26+
<version>16.1.1-dev.1</version>
2727
<licence>agpl</licence>
2828
<author mail="mklehr@gmx.net" homepage="https://marcelklehr.de">Marcel Klehr</author>
2929
<author mail="blizzz@arthur-schiwon.de" homepage="https://www.arthur-schiwon.de">Arthur Schiwon</author>

lib/Db/BookmarkMapper.php

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ public function update(Entity $entity): Bookmark {
859859
if ($entity->isWebLink()) {
860860
$entity->setUrl($this->urlNormalizer->normalize($entity->getUrl()));
861861
}
862+
$entity->setUrlHash(hash('xxh128', $entity->getUrl()));
862863
$entity->setLastmodified(time());
863864
parent::update($entity);
864865
$this->eventDispatcher->dispatchTyped(new ManipulateEvent('bookmark', $entity->getId()));
@@ -883,19 +884,25 @@ public function insert(Entity $entity): Bookmark {
883884
if ($entity->isWebLink()) {
884885
$entity->setUrl($this->urlNormalizer->normalize($entity->getUrl()));
885886
}
886-
$entity->setUrlHash(hash('xxh128', $entity->getUrl()));
887+
$entityToInsert = new Bookmark();
888+
foreach ($entity->getUpdatedFields() as $field => $_value) {
889+
$value = $entity->{'get' . ucfirst($field)}();
890+
$entityToInsert->{'set' . ucfirst($field)}($value);
891+
}
887892

888-
if ($entity->getAdded() === null) {
889-
$entity->setAdded(time());
893+
$entityToInsert->setUrlHash(hash('xxh128', $entity->getUrl()));
894+
895+
if ($entityToInsert->getAdded() === null) {
896+
$entityToInsert->setAdded(time());
890897
}
891-
$entity->setLastmodified(time());
892-
$entity->setLastPreview(0);
893-
$entity->setClickcount(0);
898+
$entityToInsert->setLastmodified(time());
899+
$entityToInsert->setLastPreview(0);
900+
$entityToInsert->setClickcount(0);
894901

895902
try {
896-
parent::insert($entity);
897-
$this->eventDispatcher->dispatchTyped(new InsertEvent('bookmark', $entity->getId()));
898-
return $entity;
903+
parent::insert($entityToInsert);
904+
$this->eventDispatcher->dispatchTyped(new InsertEvent('bookmark', $entityToInsert->getId()));
905+
return $entityToInsert;
899906
} catch (Exception $e) {
900907
if ($e->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
901908
if ($this->db->inTransaction()) {
@@ -919,12 +926,15 @@ public function insert(Entity $entity): Bookmark {
919926
public function insertOrUpdate(Entity $entity): Bookmark {
920927
try {
921928
$newEntity = $this->insert($entity);
922-
} catch (AlreadyExistsError $e) {
929+
} catch (AlreadyExistsError) {
923930
try {
924931
$bookmark = $this->findByUrl($entity->getUserId(), $entity->getUrl());
925-
$entity->setId($bookmark->getId());
926-
$newEntity = $this->update($entity);
927-
} catch (DoesNotExistException $e) {
932+
foreach ($entity->getUpdatedFields() as $field => $_value) {
933+
$value = $entity->{'get' . ucfirst($field)}();
934+
$bookmark->{'set' . ucfirst($field)}($value);
935+
}
936+
$newEntity = $this->update($bookmark);
937+
} catch (DoesNotExistException) {
928938
$newEntity = $this->insert($entity);
929939
}
930940
}

lib/Migration/Version016002000Date20260201124723.php

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,35 +48,5 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
4848
}
4949

5050
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
51-
$countQb = $this->db->getQueryBuilder();
52-
$countQb->select($countQb->func()->count('id'))->from('bookmarks')->where($countQb->expr()->isNull('url_hash'));
53-
$result = $countQb->executeQuery();
54-
$count = $result->fetchOne();
55-
$output->info('Hashing URLs of n=' . $count . ' bookmarks');
56-
$output->startProgress($count);
57-
58-
$qb = $this->db->getQueryBuilder();
59-
$qb->select('id', 'url')->from('bookmarks')->where($qb->expr()->isNull('url_hash'));
60-
$result = $qb->executeQuery();
61-
$setQb = $this->db->getQueryBuilder();
62-
$setQb->update('bookmarks')
63-
->set('url_hash', $qb->createParameter('url_hash'))
64-
->where($qb->expr()->eq('id', $qb->createParameter('id')));
65-
$i = 1;
66-
$this->db->beginTransaction();
67-
while ($row = $result->fetch()) {
68-
if ($i++ % 1000 === 0) {
69-
$this->db->commit();
70-
$this->db->beginTransaction();
71-
}
72-
$setQb->setParameter('url_hash', hash('xxh128', $row['url']));
73-
$setQb->setParameter('id', $row['id']);
74-
$setQb->executeStatement();
75-
$output->advance();
76-
}
77-
$this->db->commit();
78-
$output->finishProgress();
79-
$result->closeCursor();
8051
}
81-
8252
}

0 commit comments

Comments
 (0)