为memcahed官方java client 添加使用getMulti协议的getMulti方法

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);
	}

 

 

 

你可能感兴趣的:(java,多线程,socket,cache,F#)