package com.alipay.bluewhale.core.drpc; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; import org.apache.log4j.Logger; import org.apache.thrift7.TException; import com.alipay.bluewhale.core.callback.RunnableCallback; import com.alipay.bluewhale.core.cluster.StormConfig; import com.alipay.bluewhale.core.utils.AsyncLoopThread; import com.alipay.bluewhale.core.utils.StormUtils; import com.alipay.bluewhale.core.utils.TimeUtils; import backtype.storm.Config; import backtype.storm.daemon.Shutdownable; import backtype.storm.generated.DRPCExecutionException; import backtype.storm.generated.DRPCRequest; import backtype.storm.generated.*; import java.util.concurrent.atomic.AtomicInteger; import org.apache.thrift7.protocol.TBinaryProtocol; import org.apache.thrift7.server.*; import org.apache.thrift7.transport.TNonblockingServerSocket; import org.apache.thrift7.transport.TTransportException; /** * drpc��ʵ�� * @author yannian * */ public class Drpc implements DistributedRPC.Iface, DistributedRPCInvocations.Iface,Shutdownable{ private static Logger LOG = Logger.getLogger(Drpc.class); public static void main(String[] args) throws TTransportException { Map conf=StormConfig.read_storm_config(); final Drpc service=new Drpc(); int port =StormUtils.parseInt(conf.get(Config.DRPC_PORT)); TNonblockingServerSocket socket=new TNonblockingServerSocket(port); THsHaServer.Args targs = new THsHaServer.Args(socket); targs.workerThreads(64); targs.protocolFactory(new TBinaryProtocol.Factory()); targs.processor(new DistributedRPC.Processor<DistributedRPC.Iface>(service)); final THsHaServer handler_server = new THsHaServer(targs); int portinvoke =StormUtils.parseInt(conf.get(Config.DRPC_INVOCATIONS_PORT)); TNonblockingServerSocket socketInvoke=new TNonblockingServerSocket(portinvoke); THsHaServer.Args targsInvoke = new THsHaServer.Args(socketInvoke); targsInvoke.workerThreads(64); targsInvoke.protocolFactory(new TBinaryProtocol.Factory()); targsInvoke.processor(new DistributedRPCInvocations.Processor<DistributedRPCInvocations.Iface>(service)); final THsHaServer invoke_server = new THsHaServer(targsInvoke); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { service.shutdown(); handler_server.stop(); invoke_server.stop(); } }); LOG.info("Starting Distributed RPC servers..."); new Thread(new Runnable() { @Override public void run() { invoke_server.serve(); } }).start(); handler_server.serve(); } private AtomicInteger ctr=new AtomicInteger(0); private ConcurrentHashMap<String,Semaphore> idtoSem=new ConcurrentHashMap<String,Semaphore>(); private ConcurrentHashMap<String,Object> idtoResult=new ConcurrentHashMap<String,Object>(); private ConcurrentHashMap<String,Integer> idtoStart=new ConcurrentHashMap<String,Integer>(); private ConcurrentHashMap<String,ConcurrentLinkedQueue<DRPCRequest>> requestQueues=new ConcurrentHashMap<String,ConcurrentLinkedQueue<DRPCRequest>>(); private void cleanup(String id) { LOG.debug("clean id " +id+" @ "+(System.currentTimeMillis())); idtoSem.remove(id); idtoResult.remove(id); idtoStart.remove(id); } AsyncLoopThread clearthread; public Drpc() { clearthread=this.clearThread(); } public class clearThreadcall extends RunnableCallback { private static final int REQUEST_TIMEOUT_SECS=60; private static final int TIMEOUT_CHECK_SECS=5; private java.util.HashSet<String> lastclean=new HashSet<String>(); @Override public void run() { for(String id:this.lastclean) { Drpc.this.cleanup(id); } java.util.HashSet<String> set=new HashSet<String>(); for(Entry<String,Integer> e: Drpc.this.idtoStart.entrySet()) { if(TimeUtils.time_delta(e.getValue())>clearThreadcall.REQUEST_TIMEOUT_SECS) { String id=e.getKey(); Drpc.this.idtoResult.put(id, new DRPCExecutionException("Request timed out")); Semaphore s=Drpc.this.idtoSem.get(id); if(s!=null) { s.release(); } set.add(id); } } this.lastclean=set; } public Object getResult() { return clearThreadcall.TIMEOUT_CHECK_SECS; } } private AsyncLoopThread clearThread() { return new AsyncLoopThread(new clearThreadcall()); } @Override public String execute(String function, String args) throws DRPCExecutionException, TException { LOG.debug("Received DRPC request for " +function+ " " +args+ " at " +(System.currentTimeMillis())); int idinc=this.ctr.incrementAndGet(); int maxvalue=1000000000; int newid=idinc%maxvalue; if(idinc!=newid) { this.ctr.compareAndSet(idinc, newid); } String strid=String.valueOf(newid); Semaphore sem=new Semaphore(0); DRPCRequest req=new DRPCRequest(args, strid); this.idtoStart.put(strid, TimeUtils.current_time_secs()); this.idtoSem.put(strid, sem); ConcurrentLinkedQueue<DRPCRequest> queue=this.acquire_queue(this.requestQueues, function); queue.add(req); LOG.debug("Waiting for DRPC request for " +function+ " " +args+ " at " +(System.currentTimeMillis())); try { sem.acquire(); } catch (InterruptedException e) { LOG.error("acquire fail " ,e); } LOG.debug("Acquired for DRPC request for " +function+ " " +args+ " at " +(System.currentTimeMillis())); Object result=this.idtoResult.get(strid); LOG.debug("Returning for DRPC request for " +function+ " " +args+ " at " +(System.currentTimeMillis())); this.cleanup(strid); if(result instanceof DRPCExecutionException) { throw (DRPCExecutionException)result; } return String.valueOf(result); } @Override public void result(String id, String result) throws TException { Semaphore sem =this.idtoSem.get(id); LOG.debug("Received result " +result+ " for id " +id+ " at " +(System.currentTimeMillis())); if(sem!=null) { this.idtoResult.put(id,result); sem.release(); } } @Override public DRPCRequest fetchRequest(String functionName) throws TException { ConcurrentLinkedQueue<DRPCRequest> queue=this.acquire_queue(this.requestQueues, functionName); DRPCRequest req=queue.poll(); if(req!=null) { LOG.debug("Fetched request for " +functionName+ " at " +(System.currentTimeMillis())); return req; } return new DRPCRequest("", ""); } @Override public void failRequest(String id) throws TException { Semaphore sem =this.idtoSem.get(id); LOG.debug("failRequest result for id " +id+ " at " +(System.currentTimeMillis())); if(sem!=null) { this.idtoResult.put(id,new DRPCExecutionException( "Request failed")); sem.release(); } } @Override public void shutdown() { this.clearthread.interrupt(); } private ConcurrentLinkedQueue<DRPCRequest> acquire_queue(ConcurrentHashMap<String,ConcurrentLinkedQueue<DRPCRequest>> queues,String function) { if(!queues.containsKey(function)) { queues.putIfAbsent(function, new ConcurrentLinkedQueue<DRPCRequest>()); } return queues.get(function); } }