Details
-
Bug
-
Resolution: Fixed
-
Low
-
None
-
None
-
1
-
Severity 3 - Minor
-
3
-
Description
Issue Summary
When migrating from the internal database to an external one, or between external databases, the XML file containing data from Bitbucket Server's tables is written twice. For large database migrations, this can result in non-trivial extra disk usage and, potentially, to the entire restore operation failing because the disk becomes full.
Steps to Reproduce
- Migrate databases
- Observe that two files are created, stash-data.xml and stash_<numbers>.xml, which contain the same contents
Expected Results
Database data should be unpacked once and then restored directly from the unpacked file, rather than copying that file and restoring from the copy.
Actual Results
XML data is unpacked to stash-data.xml, which is then copied to a temporary file called stash_<numbers>.xml and the data is restored from the copy.
If copying the XML data fills up the disk, an exception similar to the following will be written to atlassian-bitbucket.log and the restore process will fail:
2019-06-18 23:24:55,897 WARN [threadpool:thread-5] jdoe @1TMI4PIx1126x86x0 1fwxwkm 1.1.1.1 "POST /admin/db/edit HTTP/1.1" c.a.s.i.m.DefaultMaintenanceTaskMonitor MIGRATION maintenance has failed (Cause: MigrationException: Bitbucket could not be migrated to the new database. Some data may have already been written to the new database leaving it in an inconsistent state. You will need to empty or recreate the new database before trying again.) com.atlassian.stash.internal.migration.MigrationException: Bitbucket could not be migrated to the new database. Some data may have already been written to the new database leaving it in an inconsistent state. You will need to empty or recreate the new database before trying again. at com.atlassian.stash.internal.maintenance.migration.DatabaseMigrationTask.convertToMigrationException(DatabaseMigrationTask.java:86) at com.atlassian.stash.internal.maintenance.migration.DatabaseMigrationTask.run(DatabaseMigrationTask.java:51) at com.atlassian.stash.internal.maintenance.DefaultMaintenanceTaskMonitor.run(DefaultMaintenanceTaskMonitor.java:212) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at com.atlassian.stash.internal.concurrent.DefaultTransferableStateManager$StateTransferringRunnable.run(DefaultTransferableStateManager.java:166) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.lang.Thread.run(Thread.java:748) ... 1 frame trimmed Caused by: com.atlassian.stash.internal.backup.BackupException: An error occurred while restoring the database at com.atlassian.stash.internal.maintenance.restore.DatabaseRestoreStep.run(DatabaseRestoreStep.java:104) at com.atlassian.stash.internal.maintenance.CompositeMaintenanceTask$Step.run(CompositeMaintenanceTask.java:130) at com.atlassian.stash.internal.maintenance.CompositeMaintenanceTask.run(CompositeMaintenanceTask.java:69) at com.atlassian.stash.internal.maintenance.restore.RestorePhase.run(RestorePhase.java:27) at com.atlassian.stash.internal.maintenance.CompositeMaintenanceTask$Step.run(CompositeMaintenanceTask.java:130) at com.atlassian.stash.internal.maintenance.CompositeMaintenanceTask.run(CompositeMaintenanceTask.java:69) at com.atlassian.stash.internal.maintenance.CompositeMaintenanceTask$Step.run(CompositeMaintenanceTask.java:130) at com.atlassian.stash.internal.maintenance.CompositeMaintenanceTask.run(CompositeMaintenanceTask.java:69) at com.atlassian.stash.internal.maintenance.MaintenanceModePhase.run(MaintenanceModePhase.java:27) at com.atlassian.stash.internal.maintenance.migration.BaseMigrationTask.run(BaseMigrationTask.java:68) at com.atlassian.stash.internal.maintenance.migration.DatabaseMigrationTask.run(DatabaseMigrationTask.java:49) ... 11 common frames omitted Caused by: com.atlassian.stash.internal.backup.liquibase.LiquibaseDataAccessException: Failed to save the contents of the input stream to a temporary file; nested exception is java.io.IOException: No space left on device at com.atlassian.stash.internal.backup.liquibase.DefaultLiquibaseMigrationDao.saveInputToFile(DefaultLiquibaseMigrationDao.java:283) at com.atlassian.stash.internal.backup.liquibase.DefaultLiquibaseMigrationDao.restore(DefaultLiquibaseMigrationDao.java:178) at com.atlassian.stash.internal.maintenance.restore.DatabaseRestoreStep.run(DatabaseRestoreStep.java:102) ... 21 common frames omitted Caused by: java.io.IOException: No space left on device at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:326) at com.google.common.io.ByteStreams.copy(ByteStreams.java:74) at com.atlassian.stash.internal.backup.liquibase.DefaultLiquibaseMigrationDao.saveInputToFile(DefaultLiquibaseMigrationDao.java:280) ... 23 common frames omitted
Workaround
There are no workarounds for this behavior; it's hard-coded in how the restore processing for database migration runs.