-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add migrations for existing file repositories
The migration of an existing legacy file repository consists of: 1. Make inventory of all files in the current file repository 2. Write these files to the new backend (disk object store) 3. Store the metadata of a node's repository contents, containing the virtual hierarchy to the corresponding `repository_metadata` column in the database. The repository metadata will contain a hashkey for each file that was written to the disk object store, which was generated by the latter and that can be used to retrieve the content of the file. The migration is performed in a single database migration, meaning that everything is executed in a single transaction. Either the entire migration succeeds or in case of an error, it is a no-op. This why the migration will not delete the legacy file repository in the same migration. The advantage of this approach is that now there is no risk of data loss and/or corruption. If the migration fails, all original data will be in tact. The downside, however, is that the content of the file repository is more or less duplicated. This means that the migration will require a potentially significant amount of disk space that is at worst equal to the size of the existing file repository. This should be the upper limit since the disk object store will both deduplicate as well as compress the content that is written.
- Loading branch information
Showing
6 changed files
with
465 additions
and
10 deletions.
There are no files selected for viewing
53 changes: 53 additions & 0 deletions
53
aiida/backends/djsite/db/migrations/0047_migrate_repository.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# -*- coding: utf-8 -*- | ||
########################################################################### | ||
# Copyright (c), The AiiDA team. All rights reserved. # | ||
# This file is part of the AiiDA code. # | ||
# # | ||
# The code is hosted on GitHub at https://github.com/aiidateam/aiida-core # | ||
# For further information on the license, see the LICENSE.txt file # | ||
# For further information please visit http://www.aiida.net # | ||
########################################################################### | ||
# pylint: disable=invalid-name,too-few-public-methods | ||
"""Migrate the file repository to the new disk object store based implementation.""" | ||
# pylint: disable=no-name-in-module,import-error | ||
from django.core.exceptions import ObjectDoesNotExist | ||
from django.db import migrations | ||
|
||
from aiida.backends.djsite.db.migrations import upgrade_schema_version | ||
from aiida.backends.general.migrations import utils | ||
from aiida.cmdline.utils import echo | ||
|
||
REVISION = '1.0.47' | ||
DOWN_REVISION = '1.0.46' | ||
|
||
|
||
def migrate_repository(apps, _): | ||
"""Migrate the repository.""" | ||
DbNode = apps.get_model('db', 'DbNode') | ||
|
||
mapping_node_repository_metadata = utils.migrate_legacy_repository() | ||
|
||
if mapping_node_repository_metadata is None: | ||
return | ||
|
||
for node_uuid, repository_metadata in mapping_node_repository_metadata.items(): | ||
try: | ||
node = DbNode.objects.get(uuid=node_uuid) | ||
except ObjectDoesNotExist: | ||
echo.echo_warning(f'repo contained folder for Node<{node_uuid}>, but the node does not exist, skipping.') | ||
else: | ||
node.repository_metadata = repository_metadata | ||
node.save() | ||
|
||
|
||
class Migration(migrations.Migration): | ||
"""Migrate the file repository to the new disk object store based implementation.""" | ||
|
||
dependencies = [ | ||
('db', '0046_add_node_repository_metadata'), | ||
] | ||
|
||
operations = [ | ||
migrations.RunPython(migrate_repository, reverse_code=migrations.RunPython.noop), | ||
upgrade_schema_version(REVISION, DOWN_REVISION), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
aiida/backends/sqlalchemy/migrations/versions/1feaea71bd5a_migrate_repository.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# -*- coding: utf-8 -*- | ||
# pylint: disable=invalid-name,no-member | ||
"""Migrate the file repository to the new disk object store based implementation. | ||
Revision ID: 1feaea71bd5a | ||
Revises: 7536a82b2cc4 | ||
Create Date: 2020-10-01 15:05:49.271958 | ||
""" | ||
from alembic import op | ||
from sqlalchemy import Integer, cast | ||
from sqlalchemy.dialects.postgresql import UUID, JSONB | ||
from sqlalchemy.sql import table, column | ||
|
||
from aiida.backends.general.migrations import utils | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = '1feaea71bd5a' | ||
down_revision = '7536a82b2cc4' | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
"""Migrations for the upgrade.""" | ||
connection = op.get_bind() | ||
|
||
DbNode = table( | ||
'db_dbnode', | ||
column('id', Integer), | ||
column('uuid', UUID), | ||
column('repository_metadata', JSONB), | ||
) | ||
|
||
mapping_node_repository_metadata = utils.migrate_legacy_repository() | ||
|
||
if mapping_node_repository_metadata is None: | ||
return | ||
|
||
for node_uuid, repository_metadata in mapping_node_repository_metadata.items(): | ||
value = cast(repository_metadata, JSONB) | ||
connection.execute(DbNode.update().where(DbNode.c.uuid == node_uuid).values(repository_metadata=value)) | ||
|
||
|
||
def downgrade(): | ||
"""Migrations for the downgrade.""" |
Oops, something went wrong.