memcahe本身提供有对getMulti的支持 但是memecahed java client中的getMulti方法是使用多线程并发请求来实现的 为了减少socket的消耗添加了一个对getMulti(协议中为get key1 key2 ...)协议支持的方法
在AscIIClient中增加下面方法
private Map<String, Object> doMget(MultiKeyBuffer multiKeyBuffer) { Map<String, Object> valuesMap = new HashMap<String, Object>(); while(multiKeyBuffer.hasNext()) { String multiKey = multiKeyBuffer.next(); if(multiKey == null) return null; // get SockIO obj using cache key SchoonerSockIO sock = pool.getSock(multiKey, null); if (sock == null) { if (errorHandler != null) errorHandler.handleErrorOnGet(this, new IOException("no socket to server available"), multiKey); return null; } String cmdLine = "get " + multiKey; try { sock.writeBuf.clear(); sock.writeBuf.put(cmdLine.getBytes()); sock.writeBuf.put(B_RETURN); // write buffer to server sock.flush(); SockInputStream input = new SockInputStream(sock, Integer.MAX_VALUE); int oneTimeReadMaxCount = 32; jump: while(oneTimeReadMaxCount-- > 0){ String responseKey = ""; int dataSize = 0; int flag = 0; boolean stop = false; StringBuilder sb = new StringBuilder(); int b; int index = 0; while (!stop) { /* * Critical block to parse the response header. */ b = input.read(); if (b == ' ' || b == '\r') { switch (index) { case 0: if (END.startsWith(sb.toString())) break jump; case 1: responseKey = sb.toString(); break; case 2: flag = Integer.parseInt(sb.toString()); break; case 3: // get the data size dataSize = Integer.parseInt(sb.toString()); break; } index++; sb = new StringBuilder(); if (b == '\r') { input.read(); stop = true; } continue; } sb.append((char) b); } Object o = null; input.willRead(dataSize); // we can only take out serialized objects if (dataSize > 0) { if (NativeHandler.isHandled(flag)) { // decoding object byte[] buf = input.getBuffer(); if ((flag & F_COMPRESSED) == F_COMPRESSED) { GZIPInputStream gzi = new GZIPInputStream(new ByteArrayInputStream(buf)); ByteArrayOutputStream bos = new ByteArrayOutputStream(buf.length); int count; byte[] tmp = new byte[2048]; while ((count = gzi.read(tmp)) != -1) { bos.write(tmp, 0, count); } // store uncompressed back to buffer buf = bos.toByteArray(); gzi.close(); } if (primitiveAsString) { o = new String(buf, defaultEncoding); } else o = NativeHandler.decode(buf, flag); } else if (transCoder != null) { // decode object with default transcoder. InputStream in = input; if ((flag & F_COMPRESSED) == F_COMPRESSED) in = new GZIPInputStream(in); if (classLoader == null) o = transCoder.decode(in); else o = ((ObjectTransCoder) transCoder).decode(in, classLoader); } valuesMap.put(responseKey, o); } input.willRead(Integer.MAX_VALUE); input.getLine();//跳过每一个value发送完成的\r\n } } catch (Exception ce) { try { sock.trueClose(); } catch (IOException e) { log.error("++++ failed to close socket : " + sock.toString()); } sock = null; } finally { if (sock != null) { sock.close(); sock = null; } } } return valuesMap; } @Override public Map<String, Object> mget(String[] keys) { if (keys == null || keys.length == 0) { log.error("keys is null for mget()"); return null; } MultiKeyBuffer buf = new MultiKeyBuffer(keys); return doMget(buf); } /*这里设置每次使用getMulti最多执行多少个key(忘了memcache支持一次多少个key了...)*/ private static int per_multikey_max_size = 32; class MultiKeyBuffer{ /**原始数据*/ private final String[] keys; /**当前已经取到了哪个位置(从0开始)*/ private int position; /**数组的长度*/ private final int size; public MultiKeyBuffer(String[] keys) { this.keys = keys; size = keys.length; } /** * 获取下一个multiKey * @return */ public String next(){ if(hasNext()){ int limit = Math.min(size, position + per_multikey_max_size); StringBuilder multiKeySb = new StringBuilder(); while(position < limit){ String key = keys[position]; try { key = sanitizeKey(key); } catch (UnsupportedEncodingException e) { log.error("failed to sanitize your key!", e); return null; } multiKeySb.append(" ").append(key); position ++; } return multiKeySb.substring(1); } return null;//调用hasNext()防止执行到该行 } public boolean hasNext(){ return position < size; } }
在父类MemcachdClient中增加
public Map<String, Object> mget(String[] keys) { return client.mget(keys); }