Details
-
Bug
-
Status: Resolved
-
Major
-
Resolution: Fixed
-
None
-
None
-
None
Description
The dbnsapshot restore may truncate enum tables and cause referential integrity issues. From the code it restores from the SQL dump by first dropping all tables:
try (Connection c = ((DataSource) store.getUnsafeStoreAccess()).getConnection()) { LOG.info("Dropping all tables"); try (PreparedStatement drop = c.prepareStatement("DROP ALL OBJECTS")) { drop.executeUpdate(); }
However a freshly started leader will have some data in there from preparing the storage:
@Override @Transactional protected void startUp() throws IOException { Configuration configuration = sessionFactory.getConfiguration(); String createStatementName = "create_tables"; configuration.setMapUnderscoreToCamelCase(true); // The ReuseExecutor will cache jdbc Statements with equivalent SQL, improving performance // slightly when redundant queries are made. configuration.setDefaultExecutorType(ExecutorType.REUSE); addMappedStatement( configuration, createStatementName, CharStreams.toString(new InputStreamReader( DbStorage.class.getResourceAsStream("schema.sql"), StandardCharsets.UTF_8))); try (SqlSession session = sessionFactory.openSession()) { session.update(createStatementName); } for (CronCollisionPolicy policy : CronCollisionPolicy.values()) { enumValueMapper.addEnumValue("cron_policies", policy.getValue(), policy.name()); } for (MaintenanceMode mode : MaintenanceMode.values()) { enumValueMapper.addEnumValue("maintenance_modes", mode.getValue(), mode.name()); } for (JobUpdateStatus status : JobUpdateStatus.values()) { enumValueMapper.addEnumValue("job_update_statuses", status.getValue(), status.name()); } for (JobUpdateAction action : JobUpdateAction.values()) { enumValueMapper.addEnumValue("job_instance_update_actions", action.getValue(), action.name()); } for (ScheduleStatus status : ScheduleStatus.values()) { enumValueMapper.addEnumValue("task_states", status.getValue(), status.name()); } for (ResourceType resourceType : ResourceType.values()) { enumValueMapper.addEnumValue("resource_types", resourceType.getValue(), resourceType.name()); } for (Mode mode : Mode.values()) { enumValueMapper.addEnumValue("volume_modes", mode.getValue(), mode.name()); } createPoolMetrics(); }
Consider the case where we add a new value to an existing enum. This means restoring from a snapshot will not allow us to have that value in the enum table.
To fix this we should have a migration for every enum value we add. However to me it seems that the better idea would be to update the enum tables after we restore from a snapshot.