PageRenderTime 65ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jgroups-2.10.0/src/org/jgroups/blocks/MemcachedConnector.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 386 lines | 301 code | 63 blank | 22 comment | 66 complexity | 339c2e87faabb886701dcd392b2d7487 MD5 | raw file
  1. package org.jgroups.blocks;
  2. import org.jgroups.annotations.ManagedAttribute;
  3. import org.jgroups.annotations.ManagedOperation;
  4. import org.jgroups.util.Util;
  5. import javax.management.MBeanRegistrationException;
  6. import javax.management.MalformedObjectNameException;
  7. import java.io.*;
  8. import java.net.InetAddress;
  9. import java.net.ServerSocket;
  10. import java.net.Socket;
  11. import java.nio.channels.ClosedSelectorException;
  12. import java.util.*;
  13. import java.util.concurrent.*;
  14. /** Class which listens on a server socket for memcached clients, reads the requests, forwards them to an instance of
  15. * PartitionedHashMap and sends the response. A memcached client should be able to work without changes once the
  16. * memcached protocol (http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt) has been implemented
  17. * completely.<br/>
  18. * @author Bela Ban
  19. * @version $Id: MemcachedConnector.java,v 1.15 2009/09/21 09:57:26 belaban Exp $
  20. */
  21. public class MemcachedConnector implements Runnable {
  22. @ManagedAttribute(writable=false)
  23. private int port=11211;
  24. @ManagedAttribute(writable=false)
  25. private InetAddress bind_addr=null;
  26. private PartitionedHashMap<String, byte[]> cache=null;
  27. private Thread thread=null;
  28. private ServerSocket srv_sock;
  29. @ManagedAttribute(writable=true)
  30. private int core_threads=1;
  31. @ManagedAttribute(writable=true)
  32. private int max_threads=500;
  33. @ManagedAttribute(writable=true)
  34. private long idle_time=5000L;
  35. private Executor thread_pool;
  36. private long start_time;
  37. private final byte[] STORED="STORED\r\n".getBytes();
  38. private final byte[] DELETED="DELETED\r\n".getBytes();
  39. private final byte[] END="END\r\n".getBytes();
  40. private final byte[] RN="\r\n".getBytes();
  41. public MemcachedConnector(InetAddress bind_addr, int port, PartitionedHashMap<String, byte[]> cache) {
  42. this.bind_addr=bind_addr;
  43. this.cache=cache;
  44. this.port=port;
  45. }
  46. public InetAddress getBindAddress() {
  47. return bind_addr;
  48. }
  49. public void setBindAddress(InetAddress bind_addr) {
  50. this.bind_addr=bind_addr;
  51. }
  52. public int getPort() {
  53. return port;
  54. }
  55. public void setPort(int port) {
  56. this.port=port;
  57. }
  58. public PartitionedHashMap<String, byte[]> getCache() {
  59. return cache;
  60. }
  61. public void setCache(PartitionedHashMap<String, byte[]> cache) {
  62. this.cache=cache;
  63. }
  64. public int getThreadPoolCoreThreads() {
  65. return core_threads;
  66. }
  67. public void setThreadPoolCoreThreads(int core_threads) {
  68. this.core_threads=core_threads;
  69. }
  70. public int getThreadPoolMaxThreads() {
  71. return max_threads;
  72. }
  73. public void setThreadPoolMaxThreads(int max_threads) {
  74. this.max_threads=max_threads;
  75. }
  76. public long getThreadPoolIdleTime() {
  77. return idle_time;
  78. }
  79. public void setThreadPoolIdleTime(long idle_time) {
  80. this.idle_time=idle_time;
  81. }
  82. public Executor getThreadPool() {
  83. return thread_pool;
  84. }
  85. public void setThreadPool(Executor thread_pool) {
  86. if(this.thread_pool instanceof ExecutorService) {
  87. ((ExecutorService)thread_pool).shutdown();
  88. }
  89. this.thread_pool=thread_pool;
  90. }
  91. public Map<String, Object> getStats() {
  92. Map<String,Object> stats=new HashMap<String,Object>();
  93. stats.put("time", System.currentTimeMillis());
  94. stats.put("uptime", (System.currentTimeMillis() - start_time) / 1000L);
  95. return stats;
  96. }
  97. @ManagedOperation
  98. public void start() throws IOException, MalformedObjectNameException, MBeanRegistrationException {
  99. srv_sock=new ServerSocket(port, 50, bind_addr);
  100. if(thread_pool == null) {
  101. thread_pool=new ThreadPoolExecutor(core_threads, max_threads, idle_time, TimeUnit.MILLISECONDS,
  102. new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());
  103. // thread_pool=new DirectExecutor();
  104. }
  105. if(thread == null || !thread.isAlive()) {
  106. thread=new Thread(this, "Acceptor");
  107. thread.start();
  108. }
  109. start_time=System.currentTimeMillis();
  110. }
  111. @ManagedOperation
  112. public void stop() throws IOException {
  113. Util.close(srv_sock);
  114. thread=null;
  115. if(thread_pool instanceof ExecutorService)
  116. ((ExecutorService)thread_pool).shutdown();
  117. }
  118. public void run() {
  119. System.out.println("MemcachedConnector listening on " + srv_sock.getLocalSocketAddress());
  120. while(thread != null && Thread.currentThread().equals(thread)) {
  121. Socket client_sock=null;
  122. try {
  123. client_sock=srv_sock.accept();
  124. // System.out.println("ACCEPT: " + client_sock.getRemoteSocketAddress());
  125. final RequestHandler handler=new RequestHandler(client_sock);
  126. /*new Thread() {
  127. public void run() {
  128. handler.run();
  129. }
  130. }.start();
  131. */
  132. thread_pool.execute(handler);
  133. }
  134. catch(ClosedSelectorException closed) {
  135. Util.close(client_sock);
  136. break;
  137. }
  138. catch(Throwable e) {
  139. }
  140. }
  141. }
  142. private class RequestHandler implements Runnable {
  143. private final Socket client_sock;
  144. private final InputStream input;
  145. private final OutputStream output;
  146. public RequestHandler(Socket client_sock) throws IOException {
  147. this.client_sock=client_sock;
  148. this.input=new BufferedInputStream(client_sock.getInputStream());
  149. this.output=new BufferedOutputStream(client_sock.getOutputStream());
  150. }
  151. public void run() {
  152. byte[] val;
  153. String line;
  154. while(client_sock.isConnected()) {
  155. try {
  156. line=Util.readLine(input);
  157. if(line == null)
  158. break;
  159. // System.out.println("line = " + line);
  160. Request req=parseRequest(line);
  161. if(req == null) {
  162. break;
  163. }
  164. // System.out.println("req = " + req);
  165. switch(req.type) {
  166. case SET:
  167. byte[] data=new byte[req.number_of_bytes];
  168. int num=input.read(data, 0, data.length);
  169. if(num == -1)
  170. throw new EOFException();
  171. cache.put(req.key, data, req.caching_time);
  172. output.write(STORED);
  173. output.flush();
  174. Util.discardUntilNewLine(input);
  175. break;
  176. case GET:
  177. case GETS:
  178. if(req.keys != null && !req.keys.isEmpty()) {
  179. for(String key: req.keys) {
  180. val=cache.get(key);
  181. if(val != null) {
  182. int length=val.length;
  183. output.write(("VALUE " + key + " 0 " + length + "\r\n").getBytes());
  184. output.write(val, 0, length);
  185. output.write(RN);
  186. }
  187. }
  188. }
  189. output.write(END);
  190. output.flush();
  191. break;
  192. case DELETE:
  193. cache.remove(req.key);
  194. output.write(DELETED);
  195. output.flush();
  196. break;
  197. case STATS:
  198. Map<String,Object> stats=getStats();
  199. StringBuilder sb=new StringBuilder();
  200. for(Map.Entry<String,Object> entry: stats.entrySet()) {
  201. sb.append("STAT ").append(entry.getKey()).append(" ").append(entry.getValue()).append("\r\n");
  202. }
  203. sb.append("END\r\n");
  204. output.write(sb.toString().getBytes());
  205. output.flush();
  206. break;
  207. }
  208. }
  209. catch(StreamCorruptedException corrupted_ex) {
  210. try {
  211. output.write(("CLIENT_ERROR failed to parse request: " + corrupted_ex + ":\r\n").getBytes());
  212. output.flush();
  213. }
  214. catch(IOException e) {}
  215. }
  216. catch(EOFException end_of_file_ex) {
  217. break;
  218. }
  219. catch(Throwable e) {
  220. }
  221. }
  222. Util.close(client_sock);
  223. }
  224. private Request parseRequest(String line) throws IOException {
  225. Request req=new Request();
  226. String[] args=line.trim().split(" +");
  227. String tmp=args[0];
  228. if(tmp == null)
  229. throw new EOFException();
  230. if(tmp.equals("set"))
  231. req.type=Request.Type.SET;
  232. else if(tmp.equals("add"))
  233. req.type=Request.Type.ADD;
  234. else if(tmp.equals("replace"))
  235. req.type=Request.Type.REPLACE;
  236. else if(tmp.equals("prepend"))
  237. req.type=Request.Type.PREPEND;
  238. else if(tmp.equals("append"))
  239. req.type=Request.Type.APPEND;
  240. else if(tmp.equals("cas"))
  241. req.type=Request.Type.CAS;
  242. else if(tmp.equals("incr"))
  243. req.type=Request.Type.INCR;
  244. else if(tmp.equals("decr"))
  245. req.type=Request.Type.DECR;
  246. else if(tmp.equals("get"))
  247. req.type=Request.Type.GET;
  248. else if(tmp.equals("gets"))
  249. req.type=Request.Type.GETS;
  250. else if(tmp.equals("delete"))
  251. req.type=Request.Type.DELETE;
  252. else if(tmp.equals("stat"))
  253. req.type=Request.Type.STAT;
  254. else if(tmp.equals("stats"))
  255. req.type=Request.Type.STATS;
  256. else {
  257. throw new StreamCorruptedException("request \"" + line + "\" not known");
  258. }
  259. switch(req.type) {
  260. case SET:
  261. case ADD:
  262. case REPLACE:
  263. case PREPEND:
  264. case APPEND:
  265. // key
  266. tmp=args[1];
  267. if(tmp == null)
  268. throw new EOFException();
  269. req.key=tmp;
  270. // read flags and discard: flags are not supported
  271. tmp=args[2];
  272. if(tmp == null)
  273. throw new EOFException();
  274. // expiry time
  275. tmp=args[3];
  276. if(tmp == null)
  277. throw new EOFException();
  278. req.caching_time=Long.parseLong(tmp) * 1000L; // convert from secs to ms
  279. // number of bytes
  280. tmp=args[4];
  281. if(tmp == null)
  282. throw new EOFException();
  283. req.number_of_bytes=Integer.parseInt(tmp);
  284. break;
  285. case GET:
  286. case GETS:
  287. req.keys=new ArrayList<String>(5);
  288. req.keys.addAll(Arrays.asList(args).subList(1, args.length));
  289. break;
  290. case DELETE:
  291. // key
  292. tmp=args[1];
  293. if(tmp == null)
  294. throw new EOFException();
  295. req.key=tmp;
  296. break;
  297. case STATS:
  298. break;
  299. }
  300. return req;
  301. }
  302. }
  303. public static class Request {
  304. public static enum Type {SET, ADD, REPLACE, PREPEND, APPEND, CAS, INCR, DECR, GET, GETS, DELETE, STAT, STATS};
  305. Type type;
  306. String key;
  307. List<String> keys=null;
  308. long caching_time;
  309. int number_of_bytes=0;
  310. public Request() {
  311. }
  312. public String toString() {
  313. StringBuilder sb=new StringBuilder();
  314. sb.append(type + ": ");
  315. if(key != null)
  316. sb.append("key=" + key);
  317. else if(keys != null && !keys.isEmpty())
  318. sb.append("keys=" + keys);
  319. sb.append(", caching_time=" + caching_time + ", number_of_bytes=" + number_of_bytes);
  320. return sb.toString();
  321. }
  322. }
  323. }