Class PhasedModelEvolutionSupport

java.lang.Object
org.eclipse.net4j.util.event.Notifier
org.eclipse.net4j.util.lifecycle.Lifecycle
org.eclipse.emf.cdo.server.db.evolution.phased.PhasedModelEvolutionSupport
All Implemented Interfaces:
IModelEvolutionSupport, org.eclipse.net4j.util.event.INotifier, org.eclipse.net4j.util.event.INotifier.INotifier2, org.eclipse.net4j.util.lifecycle.IDeactivateable, org.eclipse.net4j.util.lifecycle.ILifecycle, org.eclipse.net4j.util.lifecycle.ILifecycle.DeferrableActivation

public class PhasedModelEvolutionSupport extends org.eclipse.net4j.util.lifecycle.Lifecycle implements IModelEvolutionSupport
A phased implementation of model evolution support for DB stores.

Model evolution support is responsible for evolving the models stored in a DB store to match the currently registered EPackages.

This implementation is based on a phased approach. The following phases are supported:

  1. Change detection: Detects model changes between the stored models and the currently registered EPackages. If no changes are detected, the model evolution process is aborted.
  2. Repository export: Exports the repository data to a temporary location to prepare for schema migration. This phase is optional.
  3. Schema migration: Evolves the database schema to match the new models. This includes updating the database schema, changing the container feature IDs in case of shifted features, and adjusting enum literals in case of changed enums. This phase is mandatory and ensures that the database schema is in sync with the new models.
  4. Store processing: Performs any necessary post-processing on the DB store after schema migration. This phase is optional.
  5. Repository processing: Performs any necessary post-processing on the repository after the DB store has been processed. This phase is optional.

Each phase is handled by a dedicated phase handler. Phase handlers can be configured via dependency injection (see AnnotationFactory). The Change Detection and Schema Migration phases must have a phase handler configured. If no phase handler is configured for these phases, a default implementation is used:

The Repository Export, Store Processing, and Repository Processing phases may be skipped if no phase handler is configured for them. The Repository Export phase is the only optional phase for which a default implementation exists: DefaultRepositoryExporter.

Each phase is triggered at a specific point during the activation of the DB store and the repository. There are two triggers:

  • ActivatingStore: Triggered when the DB store is being activated by the IRepository. This is the main trigger for model evolution. It only occurs when the store is restarted, i.e., not when the store is activated for the first time.
  • ActivatedRepository: Triggered when the IRepository has been fully activated. This trigger exists mainly for special purposes, e.g., to export repository models before the schema is upgraded.

Phases can request a store or repository restart by returning the appropriate Phase.Transition from their transition method.

The model evolution process can be configured via the mode attribute, which can be set to migrate (default), prevent, or disabled. In migrate mode, model changes are automatically evolved. In prevent mode, an exception is thrown if model changes are detected. In disabled mode, model evolution is skipped entirely.

The model evolution process stores its state in a dedicated root folder, which can be configured via the rootFolder attribute. The root folder contains an evolution.properties file storing the current evolution ID and phase, as well as dedicated evolution folders for each evolution process. Each evolution folder is named after the evolution ID and contains the exported models and an optional evolution log. The DefaultRepositoryExporter stores the repository export file in the evolution folder during the Repository Export phase.

The model evolution context, which contains the models to be evolved and other relevant information, is persisted in the evolution folder after the Change Detection phase. If the model evolution process is interrupted, it can be resumed from the persisted context. Manual inspection of the evolution folder may help diagnosing issues during model evolution or recovering from failures. The context is managed by a context manager, which can be configured via dependency injection.

The phases and their handlers fire various events during the model evolution process. Clients can register listeners with the model evolution support to be notified about these events and to monitor or impact the evolution process. Registering a LogListener will log all evolution events to the logging system and helps to understand the evolution process.

Example configuration snippet:

 <store type="db">
   ...
   <modelEvolutionSupport type="phased" rootFolder="@state/evolution" mode="migrate">
     <
     <changeDetector/>
     <repositoryExporter type="default" binary="false"/>
     <schemaMigrator/>
     <storeProcessor type="my-sql-processor" myExtraArg="data"/>
     <repositoryProcessor type="my-eobject-handler" myExtraArg="data"/> -->
     <!-- Optional listeners -->
     <listener type="log"/>
     <listener type="my-extra-checks"/>
   </modelEvolutionSupport>
   ...
 </store>
 
Since:
4.14
Author:
Eike Stepper
No Implement
This package is currently considered provisional.
No Extend
This package is currently considered provisional.
No Reference
This package is currently considered provisional.
  • Field Details

    • FACTORY_TYPE

      public static final String FACTORY_TYPE
      The factory type of the default model evolution support implementation.
      See Also:
  • Constructor Details

    • PhasedModelEvolutionSupport

      public PhasedModelEvolutionSupport()
      Creates a model evolution support.
  • Method Details

    • getRootFolder

      public File getRootFolder()
      Returns the root folder where evolution data is stored.

      The root folder contains the evolution properties file and dedicated evolution folders for each evolution process.

      See Also:
    • setRootFolder

      public void setRootFolder(File rootFolder)
      Sets the root folder where evolution data is stored.
    • getStore

      public IDBStore getStore()
      Returns the DB store this model evolution support is associated with.
      Specified by:
      getStore in interface IModelEvolutionSupport
    • setStore

      public void setStore(IDBStore store)
      Sets the DB store this model evolution support is associated with.
      Specified by:
      setStore in interface IModelEvolutionSupport
      No Reference
      This method is not intended to be called by clients.
    • getMode

      Returns the model evolution mode.
    • setMode

      public void setMode(PhasedModelEvolutionSupport.Mode mode)
      Sets the model evolution mode.
    • getContextManager

      public Context.Manager getContextManager()
      Returns the context manager used to create, load, and save evolution contexts.
    • setContextManager

      public void setContextManager(Context.Manager contextManager)
      Sets the context manager used to create, load, and save evolution contexts.
    • getPhaseHandler

      public Phase.Handler getPhaseHandler(Phase phase)
      Returns the phase handler for the given phase, or null if none is set.
    • setChangeDetector

      public void setChangeDetector(Phase.Handler changeDetector)
      Sets the change detection phase handler.
    • setRepositoryExporter

      public void setRepositoryExporter(Phase.Handler repositoryExporter)
      Sets the repository export phase handler.
    • setSchemaMigrator

      public void setSchemaMigrator(Phase.Handler schemaMigrator)
      Sets the schema migration phase handler.
    • setStorePostProcessor

      public void setStorePostProcessor(Phase.Handler storeProcessor)
      Sets the store post-processing phase handler.
    • setRepositoryPostProcessor

      public void setRepositoryPostProcessor(Phase.Handler repositoryProcessor)
      Sets the repository post-processing phase handler.
    • getPhase

      public Phase getPhase()
      Returns the current evolution phase.
    • isPhaseOngoing

      public boolean isPhaseOngoing()
      Returns whether the current phase is ongoing.
    • getEvolutionID

      public int getEvolutionID()
      Returns the current evolution ID.

      The evolution ID is incremented each time a model evolution process is successfully completed. It starts at 0 for a new repository and is stored in the evolution properties file.

      The evolution ID is used to create a dedicated evolution folder under the root folder for each evolution process.

      See Also:
    • getEvolutionFolder

      public File getEvolutionFolder()
      Returns the evolution folder for the current evolution ID, or null if the evolution ID is less than 1.

      The evolution folder is a subfolder of the root folder named after the evolution ID. It contains the models properties file and the exported models for the corresponding evolution process.

      See Also:
    • getEvolutionLog

      public File getEvolutionLog()
    • getContext

      public Context getContext()
      Returns the current evolution context.

      The evolution context contains the models to be evolved and other relevant information for the model evolution process.

    • getOldPackageRegistry

      public InternalCDOPackageRegistry getOldPackageRegistry()
      Returns the old package registry used for recreating the old EPackages.
    • getNewPackageRegistry

      public InternalCDOPackageRegistry getNewPackageRegistry()
      Returns the new package registry used for determining the new EPackages.
    • log

      public void log(Object message)
      Logs the given message to the evolution log.

      Can be used by phases and handlers to log messages during model evolution.

      The evolution log is typically located in the evolution folder.

    • trigger

      public void trigger(IModelEvolutionSupport.Trigger trigger) throws Exception
      Evolves the models stored in the given DB store to match the currently registered EPackages.

      The evolution process is triggered by the given trigger. Depending on the current phase of the evolution process, the appropriate phase handler is executed.

      If the evolution mode is set to PhasedModelEvolutionSupport.Mode.Disabled, the evolution process is skipped.

      If the evolution mode is set to PhasedModelEvolutionSupport.Mode.Prevent and model changes are detected, an exception is thrown.

      If the evolution mode is set to PhasedModelEvolutionSupport.Mode.Migrate, the evolution process is executed phase by phase until completion.

      If a phase handler requests a store or repository restart, a LifecycleUtil.ReactivationTrigger is thrown to signal the need for a restart.

      Specified by:
      trigger in interface IModelEvolutionSupport
      Throws:
      Exception
    • executePhaseLoop

      protected void executePhaseLoop() throws IOException, Exception, org.eclipse.net4j.util.lifecycle.LifecycleUtil.ReactivationTrigger
      Executes the phase loop until completion or until a restart is requested.
      Throws:
      IOException
      Exception
      org.eclipse.net4j.util.lifecycle.LifecycleUtil.ReactivationTrigger
    • executePhaseHandler

      protected void executePhaseHandler(Phase.Handler phaseHandler) throws Exception
      Executes the given phase handler.
      Throws:
      Exception
    • determineNextPhase

      protected Phase determineNextPhase()
      Determines the next phase to execute, skipping any phases without a handler.
      Returns:
      the next phase to execute, or null if there are no more phases left to execute.
    • getCurrentPhaseHandler

      protected Phase.Handler getCurrentPhaseHandler()
      Returns the handler for the current phase, throwing an exception if none is set.
    • addedChangeInfo

      protected void addedChangeInfo(Context.Model model, Object changeInfo)
      Called after a change info has been added to the evolution context.
    • doBeforeActivate

      protected void doBeforeActivate() throws Exception
      Overrides:
      doBeforeActivate in class org.eclipse.net4j.util.lifecycle.Lifecycle
      Throws:
      Exception
    • doActivate

      protected void doActivate() throws Exception
      Overrides:
      doActivate in class org.eclipse.net4j.util.lifecycle.Lifecycle
      Throws:
      Exception
    • doDeactivate

      protected void doDeactivate() throws Exception
      Overrides:
      doDeactivate in class org.eclipse.net4j.util.lifecycle.Lifecycle
      Throws:
      Exception