package org.fastcatsearch.job.state; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import org.fastcatsearch.cluster.NodeService; import org.fastcatsearch.env.Environment; import org.fastcatsearch.exception.FastcatSearchException; import org.fastcatsearch.job.cluster.ClearNodeTaskStateJob; import org.fastcatsearch.job.cluster.UpdateNodeTaskStateJob; import org.fastcatsearch.service.AbstractService; import org.fastcatsearch.service.ServiceManager; import org.fastcatsearch.settings.Settings; public class TaskStateService extends AbstractService { private NodeService nodeService; private boolean isMasterNode; private Map<String, Map<TaskKey, TaskState>> nodeTaskMap; private Timer reportTimer; // master노드로 현 task를 주기적으로 보낸다. public TaskStateService(Environment environment, Settings settings, ServiceManager serviceManager) { super(environment, settings, serviceManager); } @Override protected boolean doStart() throws FastcatSearchException { nodeTaskMap = new ConcurrentHashMap<String, Map<TaskKey, TaskState>>(); nodeTaskMap.put(environment.myNodeId(), newTaskMap()); nodeService = serviceManager.getService(NodeService.class); isMasterNode = nodeService.isMaster(); // master가 아니면 현 task 상태를 주기적으로 master에 보낸다. if (!isMasterNode) { reportTimer = new Timer("TaskStateReportTimer", true); reportTimer.schedule(new TaskStateReportTask(), 1000, 1000); } return true; } @Override protected boolean doStop() throws FastcatSearchException { if (!isMasterNode) { // master에 현 노드의 모든 task를 remove하도록한다. ClearNodeTaskStateJob clearJob = new ClearNodeTaskStateJob(); nodeService.sendRequestToMaster(clearJob); } if (reportTimer != null) { reportTimer.cancel(); } nodeTaskMap.clear(); return true; } @Override protected boolean doClose() throws FastcatSearchException { nodeTaskMap = null; reportTimer = null; return true; } public void register(TaskKey key, TaskState taskState) { Map<TaskKey, TaskState> map = getMyNodeTaskMap(); TaskState prevTaskState = map.get(key); if(prevTaskState != null) { //이전 상태가 남아있을때, 종료 상태가 아니면 동일한 작업을 시작하지 못한다. if(!prevTaskState.isFinished()){ return; } } // TaskState taskState = key.createState(isScheduled); map.put(key, taskState); } public void clearTaskMap(String nodeId) { nodeTaskMap.remove(nodeId); } public TaskState getTaskState(TaskKey key) { Iterator<Map.Entry<String,Map<TaskKey,TaskState>>> iterator = nodeTaskMap.entrySet().iterator(); while(iterator.hasNext()) { Entry<String,Map<TaskKey,TaskState>> entry = iterator.next(); TaskState taskState = entry.getValue().get(key); if(taskState != null) { return taskState; } } return null; } //각 노드에서 전달된 변경사항들이 master의 상태 map에 머징된다. public void putAllTasks(String nodeId, Map<TaskKey, TaskState> taskMap) { Map<TaskKey, TaskState> map = nodeTaskMap.get(nodeId); if(map == null) { map = newTaskMap(); nodeTaskMap.put(nodeId, map); } map.putAll(taskMap); } private Map<TaskKey, TaskState> newTaskMap() { return new ConcurrentHashMap<TaskKey, TaskState>(); } private Map<TaskKey, TaskState> getMyNodeTaskMap() { return nodeTaskMap.get(environment.myNodeId()); } public Map<TaskKey, TaskState> getNodeTaskMap(String nodeId) { return nodeTaskMap.get(nodeId); } // clazz 에 해당하는 task 들을 넘겨준다. public List<Entry<TaskKey, TaskState>> getTaskEntryList(Class<? extends TaskKey> clazz) { List<Entry<TaskKey, TaskState>> list = null; Iterator<Map<TaskKey, TaskState>> iterator = nodeTaskMap.values().iterator(); while(iterator.hasNext()){ Map<TaskKey, TaskState> taskMap = iterator.next(); for (Entry<TaskKey, TaskState> entry : taskMap.entrySet()) { if (clazz != null) { if (clazz.isInstance(entry.getKey())) { if (list == null) { list = new ArrayList<Entry<TaskKey, TaskState>>(); } list.add(entry); } } else { if (list == null) { list = new ArrayList<Entry<TaskKey, TaskState>>(); } list.add(entry); } } } return list; } class TaskStateReportTask extends TimerTask { @Override public void run() { //my node의 task를 master node 로 보낸다. Map<TaskKey, TaskState> taskMap = getMyNodeTaskMap(); if (taskMap.size() > 0) { UpdateNodeTaskStateJob reportJob = new UpdateNodeTaskStateJob(); reportJob.setRunningTaskMap(taskMap); nodeService.sendRequestToMaster(reportJob); //finished 된 task는 목록에서 비운다. //다음부터는 running상태의 task만 전달된다. Iterator<Entry<TaskKey, TaskState>> iterator = taskMap.entrySet().iterator(); while(iterator.hasNext()) { if(iterator.next().getValue().isFinished()){ iterator.remove(); } } } } } }