public CompletionStage<Void> migrate(MigrationSet set) {
        InterProcessLock lock = new InterProcessSemaphoreMutex(client.unwrap(), ZKPaths.makePath(lockPath, set.id()));
        CompletionStage<Void> lockStage = lockAsync(lock, lockMax.toMillis(), TimeUnit.MILLISECONDS, executor);
        return lockStage.thenCompose(__ -> runMigrationInLock(lock, set));
    }
@Test
    public void testDocExample() throws Exception {
        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", "hey".getBytes());

        Migration initialMigration = () -> Arrays.asList(op1, op2, op3, op4, op5);
        MigrationSet migrationSet = MigrationSet.build("main", Collections.singletonList(initialMigration));
        complete(manager.migrate(migrationSet));

        assertNotNull(client.unwrap().checkExists().forPath("/parent/three"));
        assertArrayEquals(client.unwrap().getData().forPath("/main"), "hey".getBytes());

        CuratorOp newOp1 = client.transactionOp().create().forPath("/new");
        CuratorOp newOp2 = client.transactionOp().delete().forPath("/main"); // maybe this is no longer needed

        Migration newMigration = () -> Arrays.asList(newOp1, newOp2);
        migrationSet = MigrationSet.build("main", Arrays.asList(initialMigration, newMigration));
        complete(manager.migrate(migrationSet));

        assertNull(client.unwrap().checkExists().forPath("/main"));
    }