/**
* Licensed to Ravel, Inc. under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Ravel, Inc. 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 org.goldenorb.util;
import java.io.IOException;
import java.io.OutputStream;
import java.net.UnknownHostException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RPC.Server;
import org.apache.zookeeper.ZooKeeper;
import org.goldenorb.Killable;
import org.goldenorb.Messages;
import org.goldenorb.OrbPartitionCommunicationProtocol;
import org.goldenorb.OrbPartitionManagerProtocol;
import org.goldenorb.PartitionProcess;
import org.goldenorb.Vertices;
import org.goldenorb.conf.OrbConfigurable;
import org.goldenorb.conf.OrbConfiguration;
import org.goldenorb.event.OrbCallback;
import org.goldenorb.event.OrbEvent;
import org.goldenorb.event.OrbExceptionEvent;
import org.goldenorb.io.input.RawSplit;
import org.goldenorb.jet.OrbPartitionMember;
import org.goldenorb.net.OrbDNS;
import org.goldenorb.zookeeper.LeaderGroup;
import org.goldenorb.zookeeper.OrbZKFailure;
import org.goldenorb.zookeeper.ZookeeperUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MockPartitionThread extends OrbPartitionMember implements OrbConfigurable, PartitionProcess, Runnable, OrbPartitionCommunicationProtocol, OrbPartitionManagerProtocol {
private final Logger logger = LoggerFactory.getLogger(MockPartitionThread.class);
private Thread thread;
private int processNum;
private boolean standby = false;
private String jobPath;
private String jobInProgressPath;
private ZooKeeper zk;
private boolean waitingForJoin = true;
private LeaderGroup<OrbPartitionMember> leaderGroup;
private Server partitionsServer;
private Server managerServer;
private int partitionsPort;
private int managerPort;
private boolean run;
private HeartbeatGenerator heartbeatGenerator;
private String jobNumber;
public boolean leader = false;
// public MockPartitionThread() {
// thread = new Thread(this);
// }
@Override
public void launch(OutputStream outStream, OutputStream errStream) {
thread = new Thread(this);
partitionsPort = getOrbConf().getOrbBasePort() + processNum;
managerPort = getOrbConf().getOrbBasePort() + processNum + 100;
jobPath = "/GoldenOrb/" + getOrbConf().getOrbClusterName() + "/JobQueue/" + jobNumber;
jobInProgressPath = "/GoldenOrb/" + getOrbConf().getOrbClusterName() + "/JobsInProgress/" + jobNumber;
logger.info("jobPath: " + jobPath);
logger.info("jobInProgressPath: " + jobInProgressPath);
try {
zk = ZookeeperUtils.connect(getOrbConf().getOrbZooKeeperQuorum());
} catch (Exception e) {
logger.error("Unable to establish a connection with ZooKeeper" + getOrbConf().getOrbZooKeeperQuorum(), e);
}
OrbConfiguration jobConf = null;
try {
jobConf = (OrbConfiguration) ZookeeperUtils.getNodeWritable(zk, jobPath, OrbConfiguration.class,
getOrbConf());
} catch (OrbZKFailure e) {
logger.error("Unable to retrieve job from ZooKeeper: " + jobPath, e);
}
if (jobConf != null) {
setOrbConf(jobConf);
}
thread.start();
}
@Override
public void run() {
try {
setHostname(OrbDNS.getDefaultHost(getOrbConf()));
setPort(this.managerPort);
logger.debug("setting partition hostname " + getHostname());
} catch (UnknownHostException e) {
logger.error(e.getMessage());
}
try {
partitionsServer = RPC.getServer(this, getHostname(), this.partitionsPort, getOrbConf());
partitionsServer.start();
logger.info("starting RPC server on " + getHostname() + this.partitionsPort);
managerServer = RPC.getServer(this, getHostname(), managerPort, getOrbConf());
managerServer.start();
logger.info("starting RPC server on " + getHostname() + this.managerPort);
} catch (IOException e) {
logger.error(e.getMessage());
}
try {
initProxy(getOrbConf());
} catch (IOException e) {
logger.error(e.getMessage());
}
leaderGroup = new LeaderGroup<OrbPartitionMember>(zk, new MockPartitionCallback(), jobInProgressPath, this, OrbPartitionMember.class);
synchronized (this) {
while(leaderGroup.getNumOfMembers() < (getOrbConf().getOrbRequestedPartitions() + getOrbConf().getOrbReservedPartitions())) {
try {
wait(10000);
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
}
if(leaderGroup.isLeader()) {
executeAsLeader();
}
else {
executeAsSlave();
}
// synchronized (this) {
// while(standby) {
// try {
// this.wait();
// } catch (InterruptedException e) {
// logger.error(e.getMessage());
// }
// }
// }
}
private void executeAsSlave() {
synchronized (this) {
leader = false;
}
waitLoop();
}
private void executeAsLeader() {
synchronized (this) {
leader = true;
heartbeatGenerator = new HeartbeatGenerator();
}
waitLoop();
}
private void waitLoop() {
while (run) {
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
if (leaderGroup.isLeader()) {
executeAsLeader();
} else {
executeAsSlave();
}
}
}
private class MockPartitionCallback implements OrbCallback {
@Override
public void process(OrbEvent e) {
int eventCode = e.getType();
if (eventCode == OrbEvent.ORB_EXCEPTION) {
((OrbExceptionEvent) e).getException().printStackTrace();
} else if (eventCode == OrbEvent.LEADERSHIP_CHANGE) {
synchronized (MockPartitionThread.this) {
if ((leaderGroup.isLeader() && !leader) || (!leaderGroup.isLeader() && leader)) {
MockPartitionThread.this.notify();
}
}
} else if (e.getType() == OrbEvent.NEW_MEMBER) {
synchronized (MockPartitionThread.this) {
if (waitingForJoin) {
MockPartitionThread.this.notify();
}
}
}
}
}
/**
*
*/
@Override
public void kill() {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public OrbConfiguration getConf() {
return getOrbConf();
}
@Override
public void setConf(OrbConfiguration conf) {
setOrbConf(conf);
}
@Override
public int getProcessNum() {
return processNum;
}
@Override
public void setProcessNum(int processNum) {
this.processNum = processNum;
}
@Override
public boolean isRunning() {
return thread.isAlive();
}
@Override
public void setReserved(boolean reserved) {
this.standby = reserved;
}
@Override
public boolean isReserved() {
return standby;
}
@Override
public long getProtocolVersion(String arg0, long arg1) throws IOException {
return 0;
}
@Override
public int stop() {
return 0;
}
@Override
public void sendVertices(Vertices vertices) {
// TODO Auto-generated method stub
}
@Override
public void sendMessages(Messages messages) {
// TODO Auto-generated method stub
}
@Override
public void becomeActive(int partitionID) {
if(standby) {
standby = false;
synchronized (this) {
notify();
}
}
}
@Override
public void loadVerticesFromInputSplit(RawSplit rawsplit) {
// TODO Auto-generated method stub
}
private class HeartbeatGenerator implements Runnable, Killable {
private boolean active = true;
private Long heartbeat = 1L;
@Override
public void run() {
while (active) {
synchronized (this) {
try {
wait((getOrbConf().getJobHeartbeatTimeout() / 10));
try {
ZookeeperUtils.existsUpdateNodeData(zk, jobInProgressPath + "/messages/hearbeat", new LongWritable(heartbeat++));
logger.debug("creating heartbeat for: " + jobInProgressPath + "/messages/heartbeat = " + heartbeat);
}
catch( OrbZKFailure e) {
logger.error(e.getMessage());
}
}
catch(InterruptedException e) {
logger.error(e.getMessage());
}
}
}
}
@Override
public void kill() {
active = false;
}
@Override
public void restart() {
active = true;
}
}
@Override
public void setJobNumber(String jobNumber) {
this.jobNumber = jobNumber;
}
@Override
public String getJobNumber() {
return jobNumber;
}
@Override
public void setCurrentJobConf(OrbConfiguration jobConf) {
// TODO Auto-generated method stub
}
@Override
public OrbConfiguration getCurrentJobConf() {
// TODO Auto-generated method stub
return null;
}
}