ml.shifu.guagua.unit.GuaguaUnitDriver Maven / Gradle / Ivy
/*
* Copyright [2013-2014] PayPal Software Foundation
*
* Licensed 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 ml.shifu.guagua.unit;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import ml.shifu.guagua.GuaguaConstants;
import ml.shifu.guagua.GuaguaRuntimeException;
import ml.shifu.guagua.GuaguaService;
import ml.shifu.guagua.InMemoryCoordinator;
import ml.shifu.guagua.io.Bytable;
import ml.shifu.guagua.io.GuaguaFileSplit;
import ml.shifu.guagua.master.GuaguaMasterService;
import ml.shifu.guagua.master.LocalMasterCoordinator;
import ml.shifu.guagua.worker.GuaguaWorkerService;
import ml.shifu.guagua.worker.LocalWorkerCoordinator;
/**
* {@link GuaguaUnitDriver} is a helper class to run master, worker and intercepters in one jvm instance.
*
*
* One should provide all the properties by using {@link #GuaguaUnitDriver(Properties)}.
*
* @param
* master result for computation in each iteration.
* @param
* worker result for computation in each iteration.
*/
public abstract class GuaguaUnitDriver {
private static final String GUAGUA_UNIT_TEST = "Guagua Unit Test";
/**
* Properties for all configuration information.
*/
private Properties props;
/**
* Master service instance.
*/
private GuaguaService masterService;
/**
* This list mocks services for all workers which will be run in different threads.
*/
private List workerServices;
/**
* The executor used to schedule master and workers in threads.
*/
private ExecutorService executor;
/**
* Total iteration.
*/
private int iteration;
/**
* File splits used for workers.
*/
private List fileSplits;
/**
* Constructor with {@link #props} setting.
*
*
* To make it work, please make sure you set parameters in below:
*
*
* props.setProperty(GuaguaConstants.MASTER_COMPUTABLE_CLASS, SumMaster.class.getName());
* props.setProperty(GuaguaConstants.WORKER_COMPUTABLE_CLASS, SumWorker.class.getName());
* props.setProperty(GuaguaConstants.GUAGUA_ITERATION_COUNT, "10");
* props.setProperty(GuaguaConstants.GUAGUA_WORKER_NUMBER, "3");
* props.setProperty(GuaguaConstants.GUAGUA_MASTER_RESULT_CLASS, LongWritable.class.getName());
* props.setProperty(GuaguaConstants.GUAGUA_WORKER_RESULT_CLASS, LongWritable.class.getName());
* props.setProperty(GuaguaConstants.GUAGUA_WORKER_RESULT_CLASS, LongWritable.class.getName());
*
*/
public GuaguaUnitDriver(Properties props) {
this.props = props;
}
/**
* Generate file splits according to inputs. It is like hadoop mapper splits.
*/
public abstract List generateWorkerSplits(String inputs) throws IOException;
static class UtDefaultThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;
UtDefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if(t.isDaemon())
t.setDaemon(false);
if(t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
return t;
}
}
@SuppressWarnings("unchecked")
protected void setUp() {
try {
this.fileSplits = generateWorkerSplits(this.props.getProperty(GuaguaConstants.GUAGUA_INPUT_DIR));
} catch (IOException e) {
throw new GuaguaRuntimeException(e);
}
this.executor = Executors.newFixedThreadPool(this.fileSplits.size() + 1, new UtDefaultThreadFactory() );
// hard code system interceptors for unit test.
this.props.setProperty(GuaguaConstants.GUAGUA_MASTER_SYSTEM_INTERCEPTERS,
LocalMasterCoordinator.class.getName());
this.props.setProperty(GuaguaConstants.GUAGUA_WORKER_SYSTEM_INTERCEPTERS,
LocalWorkerCoordinator.class.getName());
this.props.setProperty(GuaguaConstants.GUAGUA_WORKER_NUMBER, this.fileSplits.size() + "");
this.iteration = Integer.parseInt(this.props.getProperty(GuaguaConstants.GUAGUA_ITERATION_COUNT));
this.workerServices = new ArrayList();
this.masterService = new GuaguaMasterService();
InMemoryCoordinator coordinator = new InMemoryCoordinator(
this.fileSplits.size(), this.iteration);
this.masterService.setAppId(GUAGUA_UNIT_TEST);
this.masterService.setContainerId("0");
((GuaguaMasterService) this.masterService).setCoordinator(coordinator);
this.masterService.init(this.props);
for(int i = 0; i < this.fileSplits.size(); i++) {
GuaguaService workerService = new GuaguaWorkerService();
workerService.setAppId(GUAGUA_UNIT_TEST);
workerService.setContainerId((i + 1) + "");
workerService.setSplits(Arrays.asList(this.fileSplits.get(i)));
((GuaguaWorkerService) workerService).setCoordinator(coordinator);
workerService.init(this.props);
this.workerServices.add(workerService);
}
}
/**
* To run master-workers iteration.
*/
public void run() {
// setup at firstly
this.setUp();
this.doRun();
// tear down at last
this.tearDown();
}
/**
* Real running logic
*/
protected void doRun() {
this.executor.submit(new Runnable() {
@Override
public void run() {
GuaguaUnitDriver.this.masterService.start();
GuaguaUnitDriver.this.masterService.run(null);
GuaguaUnitDriver.this.masterService.stop();
}
});
for(final GuaguaService workerService: this.workerServices) {
this.executor.submit(new Runnable() {
@Override
public void run() {
workerService.start();
workerService.run(null);
workerService.stop();
}
});
}
}
protected void tearDown() {
this.executor.shutdown();
try {
this.executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}