Reparatur einer OrientDB

Gespeichert von Erik Wegner am/um
Aufmacherbild

Bei der Entwicklung von Software ist es für die Minimierung des Aufwands nützlich, bereits vorhandene Lösungen wiederzuverwenden. Dies geschieht in Form von Bibliotheken, Paketen oder auch Container-Abbildern. Als Zwischenspeicher oder zur Durchsetzung von Richtlinien kann für viele Sprachen und Systeme ein Nexus Repository betrieben werden.

In der Version 3 kann als Datenbank eine integrierte OrientDB genutzt werden. Wird die Datenbank nicht ordnungsgemäß beendet oder geht der Speicherplatz aus, führt das zu Inkonstitenzen in der Datenbank. Es treten dann Fehler auf wie BufferUnderrunException, ORecordDuplicatedException, ArrayOutOfBoundsExceptions und andere.

Der erste Versuch bestand darin, die Datenbank-Reparatur-Funktionen aufzurufen. Dabei half der Gist, hier für die Windows-Installation:

Reparaturversuche
cd n:\nexus\nexus-3.xx.y-zz
jre\bin\java -Xms4096m -Xmx4096m -jar lib\support\nexus-orient-console.jar

CONNECT PLOCAL:/D:/nexus/sonatype-work/nexus3/db/component admin admin
REBUILD INDEX *
REPAIR DATABASE --fix-graph
REPAIR DATABASE --fix-links
REPAIR DATABASE --fix-ridbags
REPAIR DATABASE --fix-bonsai
DISCONNECT

Die Datenbank hat zwar Probleme erkannt, konnte sie aber nicht lösen.

Deshalb war der nächste Schritt, durch Sichern und Wiederherstellen einen Datenbank-Beginn zu erreichen.

Die folgenden Befehle führten die Aktion aus:

Sichern und Wiederherstellen
EXPORT DATABASE D:/nexus/tmpexport
DROP DATABASE
CREATE DATABASE PLOCAL:/D:/nexus/sonatype-work/nexus3/db/component admin admin
IMPORT DATABASE D:/nexus/tmpexport.gz -preserveClusterIDs=true

Der Import konnte die Daten wiederherstellen, brach jedoch beim Erzeugen der Indizes ab. Nach diesem Anleitungsartikel sollte es klappen, die Indizes auch manuell anzulegen:

Indizes anlegen
create index asset_bucket_component_name_idx on asset (bucket, component, name)UNIQUE
create index asset_bucket_name_idx on asset (bucket, name) NOTUNIQUE
create index asset_component_idx on asset (component collate default) NOTUNIQUE
create index asset_name_ci_idx on asset (name collate ci) NOTUNIQUE
create index browse_node_asset_id_idx on browse_node (asset_id collate default) UNIQUE
create index browse_node_component_id_idx on browse_node (component_id collate default) NOTUNIQUE
create index browse_node_repository_name_parent_path_name_idx on browse_node (repository_name, parent_path, name) UNIQUE
create index bucket_repository_name_idx on bucket (repository_name collate default) UNIQUE
create index component_bucket_group_name_version_idx on component (bucket, group, name, version) UNIQUE
create index component_bucket_name_version_idx on component (bucket, name, version) NOTUNIQUE
create index component_ci_name_ci_idx on component (ci_name collate ci) NOTUNIQUE
create index component_group_name_version_ci_idx on component (group, name,version) NOTUNIQUE
create index docker_foreign_layers_digest_idx on docker_foreign_layers (digest collate default) UNIQUE
create index OFunction.name on OFunction (name collate default) UNIQUE_HASH_INDEX
create index ORole.name on ORole (name collate ci) UNIQUE
create index OUser.name on OUser (name collate ci) UNIQUE
create index statushealthcheck_node_id_idx on statushealthcheck (node_id collate ci) UNIQUE

Es stellte sich dabei heraus, dass einige Indizes angelegt wurden. Andere jedoch brachen ab, weil doppelte Einträge vorliegen.

Während des Abbruchs werden die betroffenen Datensatz-Identifizierer angezeigt. Der Blogeintrag hier zeigt an, wie solche Datensätze angezeigt und gelöscht werden können:

Datensatz anzeigen und löschen
load record #30:307921
truncate record #30:307921

Besonders auffällig waren einige Golang-Pakete, die konnten mit dieser Abfrage gelöscht werden:

Pakete löschen
DELETE from browse_node where format = 'go' and package_url is null

Weil trotz des Löschens weiterhin doppelte Index-Einträge auffielen, sollte abgefragt werden, wie viele Einträge noch vorhanden sind. Dies konnte mit diesen Abfragen für die beiden betroffenen Indizes erledigt werden, wobei die Umschreibung in eine verschachtelte Abfrage notwendig ist, weil die OrientDB kein HAVING unterstützt:

Abfragen
SELECT FROM (
SELECT COUNT(asset_id) as c1, asset_id
FROM browse_node
GROUP BY asset_id
) WHERE c1 > 1

SELECT FROM (
SELECT COUNT(*) as c1, repository_name, parent_path, name
FROM browse_node
GROUP BY repository_name, parent_path, name
) WHERE c1 > 1

Anschließend konnte die Nexus-Anwendung wieder gestartet und auf die Datenbank zugegriffen werden. Nun sollten noch diese Arbeiten über die Aufgabensteuerung umgesetzt werden:

  • Repair - Reconcile component database from blob store (on all blob stores)
  • Repair - Reconcile npm /-/v1/search metadata (on all repositories)
  • Repair - Rebuild repository browse (on all repositories)
  • Repair - Rebuild repository search (on all repositories)
  • Repair - Rebuild npm metadata (on all repositories)
Einsortiert unter