Curator Migrations allow you pre-apply transactions in a staged manner so that you can ensure a consistent state for parts of your ZooKeeper node hierarchy in a manner similar to database migration utilities.
Note: To use Migrations, you should be familiar with Java 8's lambdas, CompletedFuture and CompletionStage.
A "migration" is a set of operations to be performed in a transaction. A "migration set" is a list of migrations. Combined, this can be used to ensure an initial state for your ZooKeeper nodes as well as supporting upgrading/modifying existing state.
For example, given a brand new ZooKeeper instance you might want to populate a few nodes and data. E.g.
CuratorOp op1 = client.transactionOp().create().forPath("/parent"); CuratorOp op2 = client.transactionOp().create().forPath("/parent/one"); CuratorOp op3 = client.transactionOp().create().forPath("/parent/two"); CuratorOp op4 = client.transactionOp().create().forPath("/parent/three"); CuratorOp op5 = client.transactionOp().create().forPath("/main", someData);
All 5 of these operations would be combined into a migration and set:
Migration migration = () -> Arrays.asList(op1, op2, op3, op4, op5); MigrationSet set = MigrationSet.build("main", Collections.singletonList(migration));
This set can then be passed to a MigrationManager for processing. The MigrationManager checks to see if the migration has been applied already and, if not, processes the transaction.
At a future date, the migration set could be expanded to update/modify things. E.g.
CuratorOp newOp1 = client.transactionOp().create().forPath("/new"); CuratorOp newOp2 = client.transactionOp().delete().forPath("/main"); // maybe this is no longer needed
This would be combined with the previous migration:
Migration initialMigration = () -> Arrays.asList(op1, op2, op3, op4, op5); Migration newMigration = () -> Arrays.asList(newOp1, newOp2); MigrationSet set = MigrationSet.build("main", Arrays.asList(initialMigration, newMigration));
When this set is run, the MigrationManager will perform both migration operations on new ZooKeeper databases but only the second "newMigration" on ZK databases that already have the first migration applied.
Migration
A Migration is a wrapper around a list of operations that constitute one stage in a migration set and are applied as a single transaction.
MigrationSet
A MigrationSet is an ordered list of Migrations. Curator keeps track of which migrations in a set have been previously applied and only processes un-applied migrations. Each migration set must have a unique identifier. Create a MigrationSet via its builder:
MigrationSet set = MigrationSet.build(migrationId, migrations);
MigrationManager
The MigrationManager processes MigrationSets. Usually, you'd run this only on new ZooKeeper databases or as part of a maintenance operation to update the ZooKeeper database. E.g.
MigrationManager manager = new MigrationManager(client, lockPath, // base path for locks used by the manager metaDataPath, // base path to store the meta data executor, // the executor to use lockMax // max time to wait for locks ); manager.migrate(set).exceptionally(e -> { if ( e instanceof MigrationException ) { // migration checksum failed, etc. } else { // some other kind of error } return null; });