/*******************************************************************************
* Copyright 2014,
* Luis Pina <luis@luispina.me>,
* Michael Hicks <mwh@cs.umd.edu>
*
* This file is part of Rubah.
*
* Rubah is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rubah is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rubah. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package rubah.runtime.state.strategy;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.javatuples.Pair;
import rubah.framework.Clazz;
import rubah.runtime.Version;
import rubah.runtime.VersionManager;
import rubah.runtime.state.MigratingProgramState;
import rubah.runtime.state.migrator.ArrayMigratorFactory;
import rubah.runtime.state.migrator.BlackListMigratorFactory;
import rubah.runtime.state.migrator.DefaultObjectMigratorFactory;
import rubah.runtime.state.migrator.MigratorFactory;
import rubah.runtime.state.migrator.MigratorSubFactory;
import rubah.runtime.state.migrator.OutdatedClassMigratorFactory;
import rubah.runtime.state.migrator.OutdatedEnumMigratorFactory;
import rubah.runtime.state.migrator.ReferenceMigratorFactory;
import rubah.runtime.state.migrator.ReflectionMigratorFactory;
import rubah.runtime.state.migrator.StaticFieldsMigratorFactory;
import rubah.runtime.state.migrator.UpdatableObjectMigratorFactory;
import rubah.runtime.state.migrator.MigratorSubFactory.Migrator;
public class SingleThreaded implements MigrationStrategy {
protected transient MigratingProgramState state;
protected MappingStrategy mapping;
protected transient Set<String> outdatedClasses, transformedClasses;
protected transient MigratorFactory migratorFactory;
public SingleThreaded(MappingStrategy mapping) {
this.mapping = mapping;
}
@Override
public void migrate(Object fromBase, long fromOffset, Object toBase, long toOffset) {
Object fromObj = unsafe.getObject(fromBase, fromOffset);
Object toObj = unsafe.getObject(toBase, toOffset);
if (fromObj == null)
return;
// Has this object been converted already?
Object ret = this.mapping.get(fromObj);
if (ret != null) {
unsafe.compareAndSwapObject(toBase, toOffset, toObj, ret);
return;
}
this.doMigrate(fromBase, fromOffset, fromObj, toBase, toOffset, toObj);
}
protected void doMigrate(Object fromBase, long fromOffset, Object fromObj, Object toBase, long toOffset, Object toObj) {
Object ret = this.migrate(fromObj);
if (fromObj != ret)
if (!unsafe.compareAndSwapObject(toBase, toOffset, toObj, ret)) {
toObj = unsafe.getObject(toBase, toOffset);
ret = this.migrate(toObj);
if (toObj != ret)
throw new Error("CAS failed and object not migrated, should not happen...");
}
}
@Override
public Object migrate(Object obj) {
return this.baseMigrate(obj);
}
protected final Object baseMigrate(Object obj) {
if (obj == null) {
return null;
}
// Has this object been converted already?
Object ret = this.mapping.get(obj);
if (ret != null) {
return ret;
}
Class<?> c = obj.getClass();
Migrator m = this.migratorFactory.getMigrator(c);
ret = m.migrate(obj);
Object post = m.registerMapping(obj, ret);
if (post != ret)
return post;
m.followReferences(ret);
return ret;
}
@Override
public void waitForFinish() {
return;
}
@Override
public MappingStrategy getMapping() {
return this.mapping;
}
@Override
public MigrationStrategy setState(MigratingProgramState state) {
this.state = state;
this.setUpMigrators();
return this;
}
@Override
public String getDescription() {
return this.getClass().getSimpleName() + " - " + this.mapping.getClass().getSimpleName();
}
private void setUpMigrators() {
this.outdatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
this.transformedClasses = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
Version v1 = VersionManager.getInstance().getLatestVersion();
Version v0 = v1.getPrevious();
if (v0 != null) {
for (Clazz c0 : v0.getNamespace().getDefinedClasses()) {
this.outdatedClasses.add(v0.getUpdatableName(c0.getFqn()));
if (v1.getUpdate().isConverted(c0)) {
this.transformedClasses.add(v0.getUpdatableName(c0.getFqn()));
}
}
}
this.migratorFactory = new MigratorFactory(this.getMigrators(v1));
this.mapping.setUpdatedClassNames(this.outdatedClasses);
}
protected MigratorSubFactory[] getMigrators(Version v1) {
return new MigratorSubFactory[]{
new BlackListMigratorFactory(this),
new ReflectionMigratorFactory(this),
new ReferenceMigratorFactory(this),
new ArrayMigratorFactory(transformedClasses, outdatedClasses, v1, this),
new UpdatableObjectMigratorFactory(transformedClasses, v1, this),
new OutdatedEnumMigratorFactory(outdatedClasses, v1, this),
new OutdatedClassMigratorFactory(outdatedClasses, v1, this),
new DefaultObjectMigratorFactory(this),
};
}
@Override
public void migrateStaticFields(Collection<Class<?>> classes) {
Version v1 = VersionManager.getInstance().getLatestVersion();
LinkedList<Pair<String, Long>> times = new LinkedList<Pair<String,Long>>();
MigratorSubFactory staticMigratorFactory = new StaticFieldsMigratorFactory(this, v1);
for (Class<?> c : classes) {
long time = System.currentTimeMillis();
if (!staticMigratorFactory.canMigrate(c))
continue;
Migrator migrator = staticMigratorFactory.buildMigrator();
Object newC = migrator.migrate(c);
migrator.followReferences(newC);
times.add(new Pair<String, Long>(c.getName(), (System.currentTimeMillis() - time)));
}
Collections.sort(times, new Comparator<Pair<String, Long>>() {
@Override
public int compare(Pair<String, Long> o1, Pair<String, Long> o2) {
return o2.getValue1().compareTo(o1.getValue1());
}
});
for (Pair<String, Long> t : times.subList(0, Math.min(times.size(), 10)))
System.out.println("\t" + t.getValue1() + "\t" + t.getValue0());
}
protected void migrateStatic(Object base, long offset) {
this.migrate(base, offset, base, offset);
}
@Override
public long countMigrated() {
return this.migratorFactory.countMigrated();
}
}