Tools to migrate from Mnesia to Khepri.
The migration from Mnesia to Khepri implemented in this module is divided in two distinct parts:Both parts can be used independently.
For the first part, sync_cluster_membership/0
and sync_cluster_membership/1
ensure the default/specified Khepri store has the
same cluster members as Mnesia.
All "instances" of the Khepri store on unclustered nodes will be reset
except one. The selected surviving Khepri store is determined using several
heuristics which are explained in sync_cluster_membership/1
.
For the second part, copy_tables/3
, copy_tables/4
, copy_all_tables/2
and copy_all_tables/3
take care of copying
records to the designated Khepri store.
The functions take a converter module which is responsible for actually
writing each record to wherever it wants in the Khepri store. This allows
the caller to filter and convert the records. The converter module
interface is defined by the mnesia_to_khepri_converter
behavior.
There is an example converter module called mnesia_to_khepri_example_converter
provided.
The copy works while Mnesia tables are still being used and updated. To
allow that, the copy follows several stages which are explained in copy_tables/4
.
The functions is_migration_finished/1
, is_migration_finished/2
, wait_for_migration/2
and wait_for_migration/3
can be used to follow an on-going copy of the tables.
handle_fallback/3
and
handle_fallback/4
.
converter_mod() = module() | {module(), any()}
A converter module, possibly with a private term to initliaze it.
A converter module is a module implementing themnesia_to_khepri_converter
behavior. The private term is passed as is to
its {link mnesia_to_khepri_converter:init_copy_to_khepri/3} callback.
migration_id() = binary()
MigrationId of a migration.
This is used to semantically identify a migration that covers a set of Mnesia tables and an associated converter module.
A migration is idempotent, based on this identifier. In other words, a migration identifier by this identifier can happen only once, and there can't be concurrent migration processes with that same identifier.mnesia_table() = atom()
The name of a Mnesia table.
This is the same type asmnesia:table()
which is not exported
unfortunately.
sync_cluster_membership/0 | Ensures the default Khepri store has the same members as the Mnesia cluster. |
sync_cluster_membership/1 | Ensures the Khepri store named StoreId has the same members as the
Mnesia cluster. |
copy_tables/3 | Copies records from Mnesia tables Tables to the default Khepri
store. |
copy_tables/4 | Copies records from Mnesia tables Tables to the Khepri store named
StoreId . |
copy_all_tables/2 | Copies records from all Mnesia tables to the default Khepri store. |
copy_all_tables/3 | Copies records from all Mnesia tables to the Khepri store named
StoreId . |
is_migration_finished/1 | Returns the migration status of the specified migration identifier. |
is_migration_finished/2 | Returns the migration status of the specified migration identifier. |
wait_for_migration/2 | Waits for migration MigrationId to be finish. |
wait_for_migration/3 | Waits for migration MigrationId to be finish. |
cleanup_after_table_copy/1 | Performs any cleanups after a migration has finished. |
cleanup_after_table_copy/2 | Performs any cleanups after a migration has finished. |
rollback_table_copy/1 | Rolls back a migration. |
rollback_table_copy/2 | Rolls back a migration. |
handle_fallback/3 | Runs MnesiaFun or evaluates KhepriFunOrRet depending on the status
of the migration. |
handle_fallback/4 | Runs MnesiaFun or evaluates KhepriFunOrRet depending on the status
of the migration. |
sync_cluster_membership() -> ok
Ensures the default Khepri store has the same members as the Mnesia cluster.
See also: sync_cluster_membership/1.
sync_cluster_membership(StoreId) -> ok
StoreId = khepri:store_id()
Ensures the Khepri store named StoreId
has the same members as the
Mnesia cluster.
StoreId
.The synchronization process has to select a store instance that will grow and other store instances that will be reset. The criterias below are evaluated to sort the list of store instances, then the first instance in that list is selected as the winning instance.
Criterias are evaluated in order. For a given criteria, if both sides are equal, the next criteria is evaluated until one criteria gives an instance "greater" than another.
Here is the ordered list of criterias:copy_tables(MigrationId, Tables, Mod) -> Ret
MigrationId = migration_id()
Tables = [mnesia_table()]
Mod = converter_mod() | {converter_mod(), ModArgs}
ModArgs = any()
Ret = ok | {error, any()}
Copies records from Mnesia tables Tables
to the default Khepri
store.
See also: copy_tables/3.
copy_tables(StoreId, MigrationId, Tables, Mod) -> Ret
StoreId = khepri:store_id()
MigrationId = migration_id()
Tables = [mnesia_table()]
Mod = converter_mod() | {converter_mod(), ModArgs}
ModArgs = any()
Ret = ok | {error, any()}
Copies records from Mnesia tables Tables
to the Khepri store named
StoreId
.
The converter module Mod
is responsible for storing each Mnesia record in
the Khepri store. How it is called is described below. mnesia_to_khepri_example_converter
can be used as the default converter
module or as an example to write a new one.
Mod:init_copy_to_khepri/3
function, or Mod:init_copy_to_khepri/4
if
ModArgs
is set.Mod:copy_to_khepri/3
for each Mnesia
record.Mod:copy_to_khepri/3
and
Mod:delete_from_khepri/3
to update the Khepri store accordingly.Mod:finish_copy_to_khepri/1
to let the
converter module do any cleanups.handle_fallback/2
and handle_fallback/3
for helpers to use Mnesia while records are being copied.
copy_all_tables(MigrationId, Mod) -> Ret
MigrationId = migration_id()
Mod = converter_mod() | {converter_mod(), ModArgs}
ModArgs = any()
Ret = ok | {error, any()}
Copies records from all Mnesia tables to the default Khepri store.
See also: copy_all_tables/3.
copy_all_tables(StoreId, MigrationId, Mod) -> Ret
StoreId = khepri:store_id()
MigrationId = migration_id()
Mod = converter_mod() | {converter_mod(), ModArgs}
ModArgs = any()
Ret = ok | {error, any()}
Copies records from all Mnesia tables to the Khepri store named
StoreId
.
See also: copy_tables/4.
is_migration_finished(MigrationId) -> Migrated
MigrationId = mnesia_to_khepri:migration_id()
Migrated = boolean() | {in_flight, pid()} | undefined
Returns the migration status of the specified migration identifier.
The default Khepri store is queried to get the migration status. It must correspond to the Khepri store passed tocopy_tables/3
and similar
functions.
See also: is_migration_finished/2.
is_migration_finished(StoreId, MigrationId) -> Migrated
StoreId = khepri:store_id()
MigrationId = mnesia_to_khepri:migration_id()
Migrated = boolean() | {in_flight, pid()} | undefined
returns: true
if the migration is finished, {in_flight, Pid}
if the
migration is in progress and handled by the Pid
process, false
if the
migration has not started or undefined
if the query of the Khepri store
where the status is recorded failed.
Returns the migration status of the specified migration identifier.
The Khepri store namedStoreId
is queried to get the migration status. It
must correspond to the Khepri store passed to copy_tables/3
and
similar functions.
wait_for_migration(MigrationId, Timeout) -> Ret
MigrationId = mnesia_to_khepri:migration_id()
Timeout = timeout()
Ret = boolean() | timeout
Waits for migration MigrationId
to be finish.
copy_tables/3
and similar
functions.
See also: wait_for_migration/3.
wait_for_migration(StoreId, MigrationId, Timeout) -> Ret
StoreId = khepri:store_id()
MigrationId = mnesia_to_khepri:migration_id()
Timeout = timeout()
Ret = boolean() | timeout
Waits for migration MigrationId
to be finish.
If the migration has not started, it returns false
immediately.
If the migration is finished, it returns true
immediately.
If the migration is in progress or the status is undefined (see is_migration_finished/3
), it waits until the status is known to be
"finished" or "not started" or until Timeout
milliseconds.
StoreId
is queried to get the migration status. It
must correspond to the Khepri store passed to copy_tables/3
and
similar functions.
cleanup_after_table_copy(MigrationId) -> Ret
MigrationId = mnesia_to_khepri:migration_id()
Ret = ok | {error, any()}
Performs any cleanups after a migration has finished.
See also: cleanup_after_table_copy/2.
cleanup_after_table_copy(StoreId, MigrationId) -> Ret
StoreId = khepri:store_id()
MigrationId = mnesia_to_khepri:migration_id()
Ret = ok | {error, any()}
Performs any cleanups after a migration has finished.
Currently this includes the deletion of the copied Mnesia tables.
This is a separate step fromcopy_tables/4
because the caller might
want to record some post-migration states before comitting to delete the
Mnesia tables.
rollback_table_copy(MigrationId) -> Ret
MigrationId = mnesia_to_khepri:migration_id()
Ret = ok | {error, any()}
Rolls back a migration.
See also: rollback_table_copy/2.
rollback_table_copy(StoreId, MigrationId) -> Ret
StoreId = khepri:store_id()
MigrationId = mnesia_to_khepri:migration_id()
Ret = ok | {error, any()}
Rolls back a migration.
This function puts Mnesia tables back to read-write mode and deletes the "migration in progress" marker.
Rollback is not possible oncecleanup_after_table_copy/2
is used.
handle_fallback(MigrationId, MnesiaFun, KhepriFunOrRet) -> Ret
MigrationId = mnesia_to_khepri:migration_id()
MnesiaFun = fun(() -> Ret)
KhepriFunOrRet = fun(() -> Ret) | Ret
Ret = any()
Runs MnesiaFun
or evaluates KhepriFunOrRet
depending on the status
of the migration.
copy_tables/3
and similar
functions.
See also: handle_fallback/4.
handle_fallback(StoreId, MigrationId, MnesiaFun, KhepriFunOrRet) -> Ret
StoreId = khepri:store_id()
MigrationId = mnesia_to_khepri:migration_id()
MnesiaFun = fun(() -> Ret)
KhepriFunOrRet = fun(() -> Ret) | Ret
Ret = any()
Runs MnesiaFun
or evaluates KhepriFunOrRet
depending on the status
of the migration.
If the migration is finished it executes KhepriFunOrRet
if it is a
function with an arity of 0 or returns the term directly otherwise.
If the migration is not finished, the function tries to execute
MnesiaFun
. It should fail by returning or raising {aborted, {no_exists,
Table}}
. When this happens, the function waits for the migration to finish
using wait_for_table_migration/3
, then it starts again.
StoreId
is queried to get the migration status. It
must correspond to the Khepri store passed to copy_tables/3
and
similar functions.
Generated by EDoc