cc.kune.kunecli.cmds.CustomDeltaMigrator.java Source code

Java tutorial

Introduction

Here is the source code for cc.kune.kunecli.cmds.CustomDeltaMigrator.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cc.kune.kunecli.cmds;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import org.waveprotocol.box.common.ExceptionalIterator;
import org.waveprotocol.box.server.persistence.PersistenceException;
import org.waveprotocol.box.server.waveserver.DeltaStore;
import org.waveprotocol.box.server.waveserver.DeltaStore.DeltasAccess;
import org.waveprotocol.box.server.waveserver.WaveletDeltaRecord;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.id.WaveletName;
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.util.logging.Log;

import com.google.common.collect.ImmutableSet;
import com.sun.xml.internal.rngom.parse.compact.EOFException;

/**
 *
 * An utility class to copy all deltas between storages. Already existing Waves
 * in the target store wont be changed.
 *
 * It is NOT an incremental process.
 *
 * @author pablojan@gmail.com (Pablo Ojanguren)
 *
 */
public class CustomDeltaMigrator {

    private static final Log LOG = Log.get(CustomDeltaMigrator.class);

    private Progressbar bar;
    int countError = 0;
    int countMigrated = 0;
    int countMigratedBecausePartial = 0;
    int countSkipped = 0;
    protected DeltaStore sourceStore = null;

    protected DeltaStore targetStore = null;

    public CustomDeltaMigrator(final DeltaStore sourceStore, final DeltaStore targetStore) {
        this.sourceStore = sourceStore;
        this.targetStore = targetStore;
    }

    private String getStats() {
        return "migrated/skipped/partial/error: " + countMigrated + "/" + countSkipped + "/"
                + countMigratedBecausePartial + "/" + countError;
    }

    private void printStats() {
        LOG.info("Total " + getStats());
    }

    private void processCorruptedWave(final WaveId waveId, final Exception e) {
        countError++;
        LOG.info("Waveid with errors: " + waveId.toString());
        // throw new RuntimeException(e);
    }

    public void run() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                printStats();
            }
        });

        LOG.info("Starting Wave migration from " + sourceStore.getClass().getSimpleName() + " to "
                + targetStore.getClass().getSimpleName());

        final long startTime = System.currentTimeMillis();

        try {
            // We need the total number of waves to make a progress bar
            int waveCount = 0;
            final ExceptionalIterator<WaveId, PersistenceException> countIterator = sourceStore.getWaveIdIterator();
            while (countIterator.hasNext()) {
                waveCount++;
                countIterator.next();
            }

            final ExceptionalIterator<WaveId, PersistenceException> srcItr = sourceStore.getWaveIdIterator();
            final File stopFile = new File(System.getProperty("java.io.tmpdir") + "/wave-mongo-migration-stop");

            bar = new Progressbar(waveCount, "Migrating " + waveCount + " Waves");

            int currentWave = 0;
            // Waves
            while (srcItr.hasNext()) {
                currentWave++;

                if (stopFile.exists()) {
                    LOG.info("Stopping Wave migration as requested. Partial migration.");
                    break;
                }

                bar.setVal(currentWave);

                final WaveId waveId = srcItr.next();
                final ImmutableSet<WaveletId> sourceLookup = sourceStore.lookup(waveId);
                final ImmutableSet<WaveletId> targetLookup = targetStore.lookup(waveId);
                final ImmutableSet<WaveletId> waveletIds = sourceLookup;

                boolean wavesAreNotTheSame = false;

                if (!targetLookup.isEmpty()) {
                    if (targetLookup.size() != sourceLookup.size()) {
                        wavesAreNotTheSame = true;
                    } else {
                        // Comparing source and target deltas
                        for (final WaveletId waveletId : waveletIds) {
                            setStatus("comparing");
                            bar.setVal(currentWave);

                            final DeltasAccess sourceDeltas = sourceStore.open(WaveletName.of(waveId, waveletId));
                            final DeltasAccess targetDeltas = targetStore.open(WaveletName.of(waveId, waveletId));
                            final HashedVersion deltaResultingVersion = sourceDeltas.getEndVersion();
                            final HashedVersion deltaResultingTargetVersion = targetDeltas.getEndVersion();

                            if (!deltaResultingVersion.equals(deltaResultingTargetVersion)) {
                                wavesAreNotTheSame = true;
                                break;
                            }
                        }

                        if (wavesAreNotTheSame) {
                            for (final WaveletId targetWaveletId : targetLookup) {
                                // LOG.info(
                                // "Deleting and appending Wave in target because it's found and
                                // has not the same size: "
                                // + waveId.toString());
                                targetStore.delete(WaveletName.of(waveId, targetWaveletId));
                            }
                            // Continue migrating that wave
                        } else {
                            setStatus("skipping already migrated");
                            bar.setVal(currentWave);
                            countSkipped++;
                            continue;
                        }
                    }
                }

                if (wavesAreNotTheSame) {
                    setStatus("migrating partial wave");
                    countMigratedBecausePartial++;
                } else {
                    setStatus("migrating");
                    countMigrated++;
                }
                setStatus(wavesAreNotTheSame ? "migrating partial wave" : "migrating");

                // LOG.info("--- Migrating Wave " + waveId.toString() + " with " +
                // waveletIds.size() + " wavelets");
                // final long waveStartTime = System.currentTimeMillis();
                //
                // Wavelets

                try {
                    for (final WaveletId waveletId : waveletIds) {
                        bar.setVal(currentWave);

                        // LOG.info(
                        // "Migrating wavelet " + waveletsCount + "/" + waveletsTotal + " :
                        // "
                        // + waveletId.toString());

                        final DeltasAccess sourceDeltas = sourceStore.open(WaveletName.of(waveId, waveletId));
                        final DeltasAccess targetDeltas = targetStore.open(WaveletName.of(waveId, waveletId));

                        // Get all deltas from last version to initial version (0): reverse
                        // order
                        // int deltasCount = 0;

                        final ArrayList<WaveletDeltaRecord> deltas = new ArrayList<WaveletDeltaRecord>();
                        HashedVersion deltaResultingVersion = sourceDeltas.getEndVersion();

                        // Deltas
                        while (deltaResultingVersion != null && deltaResultingVersion.getVersion() != 0) {
                            // deltasCount++;
                            final WaveletDeltaRecord deltaRecord = sourceDeltas
                                    .getDeltaByEndVersion(deltaResultingVersion.getVersion());
                            deltas.add(deltaRecord);
                            // get the previous delta, this is the appliedAt
                            deltaResultingVersion = deltaRecord.getAppliedAtVersion();
                        }
                        // LOG.info("Appending " + deltasCount + " deltas to target");
                        targetDeltas.append(deltas);
                    }

                } catch (final EOFException e) {
                    processCorruptedWave(waveId, e);
                } catch (final PersistenceException e) {
                    processCorruptedWave(waveId, e);
                } catch (final IOException e) {
                    processCorruptedWave(waveId, e);
                }

            } // While Waves

            bar.finish();
            final long endTime = System.currentTimeMillis();
            LOG.info("Migration completed. Total time = " + (endTime - startTime) + "ms");
            printStats();
        } catch (final PersistenceException e) {
            LOG.warning("Error iterating over waves");
            throw new RuntimeException(e);
        }
    }

    private void setStatus(final String status) {
        bar.setStatus(status, getStats());
    }

}