/* * 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; import java.util.ArrayList; import java.util.List; import ml.shifu.guagua.io.Bytable; /** * {@link InMemoryCoordinator} is a helper for in-memory master and worker coordination. * * <p> * Master result can be set from master by {@link #signalWorkers(int, Bytable)}. Workers can get the result by * {@link #getMasterResult()}. * * <p> * Worker results can be set from worker by {@link #signalWorkers(int, Bytable)}. Master can get the result by * {@link #getWorkerResults()}. * * @param <MASTER_RESULT> * master computation result in each iteration. * @param <WORKER_RESULT> * worker computation result in each iteration. */ public class InMemoryCoordinator<MASTER_RESULT extends Bytable, WORKER_RESULT extends Bytable> { private static final int DEFAULT_SLEEP_TIME = 300; /** * Worker number which is used to construct count-down array. */ private final int workers; /** * Master result which is set from master and transfer to worker. */ private MASTER_RESULT masterResult; /** * Worker result list which are set from worker and transfer to master. */ private List<WORKER_RESULT> workerResults; /** * Worker count-down list for all iterations(plus initialization iteration 0) */ private List<Integer> workerCounts; /** * Master count-down list for all iterations(plus initialization iteration 0) */ private List<Integer> masterCounts; public InMemoryCoordinator(int workers, int iteration) { this.workers = workers; // iteration + (step 0(initialization)) int maxIteration = iteration + 1; this.workerCounts = new ArrayList<Integer>(maxIteration); this.masterCounts = new ArrayList<Integer>(maxIteration); for(int i = 0; i < maxIteration; i++) { // workers is set by parameter this.workerCounts.add(this.workers); // only one master this.masterCounts.add(1); } this.workerResults = new ArrayList<WORKER_RESULT>(this.workers); for(int i = 0; i < this.workers; i++) { this.workerResults.add(null); } } /** * Master waits for workers on each iteration condition */ public void awaitWorkers(int iteration) { int currentCount = 0; while(true) { synchronized(this.workerCounts) { currentCount = this.workerCounts.get(iteration); } if(currentCount == 0) { break; } try { Thread.sleep(DEFAULT_SLEEP_TIME); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } /** * Signal master with result setting. */ public void signalMaster(int iteration, int containerIndex, WORKER_RESULT workerResult) { synchronized(this.workerCounts) { this.workerCounts.set(iteration, this.workerCounts.get(iteration) - 1); if(workerResult != null) { this.workerResults.set(containerIndex, workerResult); } } } /** * Workers wait for master on each iteration condition */ public void awaitMaster(int iteration) { int currentCount = 0; while(true) { synchronized(this.masterCounts) { currentCount = this.masterCounts.get(iteration); } if(currentCount == 0) { break; } try { Thread.sleep(DEFAULT_SLEEP_TIME); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } /** * Master signals workers with result setting. */ public void signalWorkers(int iteration, MASTER_RESULT masterResult) { synchronized(this.masterCounts) { this.masterCounts.set(iteration, this.masterCounts.get(iteration) - 1); this.masterResult = masterResult; } } public MASTER_RESULT getMasterResult() { return this.masterResult; } public List<WORKER_RESULT> getWorkerResults() { return new ArrayList<WORKER_RESULT>(this.workerResults); } }